Vue3 ( 制作後台 ) -6

1.使用 资料库 API

申请并汇入商品


2.建立新专案 new-project

vue create new-project(专案名称)

npm run serve

https://ithelp.ithome.com.tw/upload/images/20211115/20137684tXx7sFVSgY.png


3.新增环境变数 .env

连接资料库用

VUE_APP_API=
VUE_APP_PATH=rouoxo


4.连接资料库

view > home.vue

export default {
  name: "Home",
  components: {
    HelloWorld,
  },
  created() {
    //连接资料库
    console.log(process.env.VUE_APP_API);
    console.log(process.env.VUE_APP_PATH);
  },
};

5.汇入 Bootstrap 并调整版型

(1)安装

https://bootstrap.hexschool.com/

npm install bootstrap@

(2)自定义 sass

https://bootstrap.hexschool.com/docs/4.2/getting-started/theming/

2-1 自定义 sass
App.vue

<style lang="scss">
@import "~bootstrap/scss/bootstrap";
</style>

npm run serve

2-2 客制化样式
assets 下新增 all.scss
assets 下新增 helpers资料夹 下新增 _variables.scss(_不会被辨识到)
并将原本的BS内 variables.scss 资料贴至 _variables.scss 内

2-3 自定义汇入
assets > all.scss

@import "~bootstrap/scss/functions";
@import "./helpers/variables";
@import "~bootstrap/scss/mixins";

@import "~bootstrap/scss/bootstrap";

App.vue

<style lang="scss">
@import "./assets/all";
</style>

多尝试几次


6. 制作登入页面

(1)安装axios

https://www.npmjs.com/package/vue-axios

npm install --save axios vue-axios

(2)全域汇入

main.js

import axios from 'axios'
import VueAxios from 'vue-axios'

app.use(VueAxios, axios);

(3)制作登入页面(制作元件)

https://github.com/hexschool/vue3-course-api-wiki/wiki/%E8%AA%B2%E7%A8%8B%E9%83%A8%E5%88%86%E6%A8%A1%E6%9D%BF
View 新增 Login.vue

(4)綑绑路由(设定路由)

Router > index.js

  {
    path: "/login",
    name: "Login",
    component: () =>
      import("../views/Login.vue"),
  },

(5)对应API写JS

https://github.com/hexschool/vue3-course-api-wiki/wiki/%E7%99%BB%E5%85%A5%E5%8F%8A%E9%A9%97%E8%AD%89

登入成功显示范例
"uid": "XX4VbV87lRRBXKhZKT7YX6zhsuO2",
"token": "xxx"
"expired": "1234567890"
https://ithelp.ithome.com.tw/upload/images/20211115/20137684Sx269r1Qot.png


7. 登入与 Cookie

https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie
https://github.com/axios/axios#global-axios-defaults

document.cookie = "doSomethingOnlyOnce(名称自订)=true(值); 
expires(到期日)=Fri,31 Dec 9999 23:59:59 GMT; SameSite=None; Secure";

目标:将token存进Cookie

const {token, expired} = res.data //token、expired = data内的token、expired
console.log(token ,expired) 
document.cookie = `hexToken=${token}; expired=${new Date(expired)}`

成功
https://ithelp.ithome.com.tw/upload/images/20211115/20137684xWoCszp56f.png


8.确认是否维持登入状态

API
https://github.com/hexschool/vue3-course-api-wiki/wiki/%E7%99%BB%E5%85%A5%E5%8F%8A%E9%A9%97%E8%AD%89

(1)从cookie拿出token (需上步骤先看到Cookie内有token)

https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie

1-1 制作元素页面
Dashboard.vue

  created() {
    const token = document.cookie.replace(
        // hexToken cookie名称
      /(?:(?:^|.*;\s*)hexToken\s*=\s*([^;]*).*$)|^.*$/,
      "$1"
    );
    console.log(token);
  },
};

1-2 綑绑路由
index.js

  {
    path: "/dashboard",
    name: "Dashboard",
    component: () =>
      import("../views/Dashboard.vue"),
  },

(2)token放入Headers

https://github.com/axios/axios
Dashboard.vue

    this.$http.default.headers.common["Authorization"] = token;

(3)登入验证

Dashboard.vue
https://github.com/hexschool/vue3-course-api-wiki/wiki/%E7%99%BB%E5%85%A5%E5%8F%8A%E9%A9%97%E8%AD%89

    const api = `${process.env.VUE_APP_API}api/user/check`;
    console.log(api);
    this.$http.post(api, this.user).then((res) => {
      console.log(res);
    });

登入成功
https://ithelp.ithome.com.tw/upload/images/20211115/2013768447yBjv3W7Z.png

如果把cookie的hexToken删除
登入失败
https://ithelp.ithome.com.tw/upload/images/20211115/20137684U7MuIXny2V.png

(4)转址 $router.push

Login.vue如果登入成功转Dashboard.vue页面

        this.$http.post(api, this.user).then((res) => {
        // 如果登入成功转跳Dashboard.vue页面
        if (res.data.success) {
          this.$router.push("/dashboard");
        }
      });

如果登入失败Dashboard.vue会转回Login.vue

      if (!res.data.success) {
        this.$router.push("/login");
      }

9. 调整巢状路由并且加入 Navbar

(1)制作画面元件 Products.vue(新增元件)

(2)Dashboard.vue增加Bs Navbar

(3)Dashboard.vue调整巢状路由

显示App.vue

   <router-view />

(4)App.vue 调整巢状路由

删除

    <router-link />

(5)綑绑路由

index.js

  {
    path: "/dashboard",
    name: "Dashboard",
    component: () => import("../views/Dashboard.vue"),
    // 多个,阵列
    children: [
      {
        path: "products",
        component: () => import("../views/Products.vue"),
      },
    ],
  },

(6)调整 login.vue 登入成功转跳 products.vue

    this.$router.push("/dashboard/products");

(7)调整 Dashboard.vue Navbar

把Navbar拆出来做成一个小元件

7-1. 新增 components > Navbar.vue
并把Dashboard.vue 的 BS Navbar 剪下贴上

7-2 Dashboard.vue下注册该 Navbar.vue 元件 并放入

    <Navber></Navber>

    import Navber from "../components/Navbar.vue";

    export default {
      // 注册元件
      components: {
          Navber
      },

(8)制作登出

https://github.com/hexschool/vue3-course-api-wiki/wiki/%E7%99%BB%E5%85%A5%E5%8F%8A%E9%A9%97%E8%AD%89
Navbar.vue

    <a class="nav-link" href="#" v-on:click.prevent="logout">登出</a>

    methods: {
    logout() {
      // 制作登出方法
      const api = `${process.env.VUE_APP_API}logout`;
      console.log(api);

      // axios post(api, 欲传送的值)方法方法
      this.$http.post(api, this.user).then((res) => {
        //
        if (res.data.success) {
          console.log(res);
          // 转跳登入页面
          this.$router.push("/login");
        }
      });
     },
    },

成功,F12检查
data: {success: true, message: '已登出'}


10. 加入产品列表

完成图
https://ithelp.ithome.com.tw/upload/images/20211115/20137684qHujdzaYxk.png

(1)Dashboard.vue 调整面板

  <!-- 让版面不要太贴齐周边 BS样式 -->
  <div class="container-fluid">
    <router-view />
  </div>

(2)Products.vue 制作表格

https://github.com/hexschool/vue3-course-api-wiki/wiki/%E8%AA%B2%E7%A8%8B%E9%83%A8%E5%88%86%E6%A8%A1%E6%9D%BF

(3)Products.vue 制作元件 取得商品列表

https://github.com/hexschool/vue3-course-api-wiki/wiki/%E7%AE%A1%E7%90%86%E6%8E%A7%E5%88%B6%E5%8F%B0-%5B%E9%9C%80%E9%A9%97%E8%AD%89%5D

检查
https://ithelp.ithome.com.tw/upload/images/20211115/20137684bwMxGbndJ0.png


11. 增加 Bootstrap Modal

目标:新增Bs Modal 弹跳视窗
https://bootstrap.hexschool.com/docs/4.2/components/modal/
BS的Modal,可以用JS呼叫出来使用~
https://ithelp.ithome.com.tw/upload/images/20211115/20137684YduVQG7Al2.png

(1)新增元件 放入BS样式 及 方法

components > ProductModal.vue

https://ithelp.ithome.com.tw/upload/images/20211115/20137684hcKGnC3rQM.png

(2)将ProductModal.vue 元件放入 Products.vue

    <ProductModal></ProductModal>

    import ProductModal from "../components/ProductModal.vue";

    components: {
      // 区域注册元件
      ProductModal,
    },

Modal元件已经放入,剩下写判断式让按按钮後 Modal跳出

(3)判断式 + 按钮

Products.vue

  <!-- 使用元件 ref似id 之後可以用this.$refs抓 -->
  <ProductModal ref="poductModal"></ProductModal>

      <button
      v-on:click="$refs.poductModal.showModal()"
      class="btn btn-primary"
      type="button"
    >
      增加一个产品
    </button>

https://ithelp.ithome.com.tw/upload/images/20211115/20137684vDtFSIWISN.png


12. 透过弹出视窗新增品项 - (新增)

目标:弹出视窗的元件,输入完资料後,资料推进产品列表元件内
逻辑
https://ithelp.ithome.com.tw/upload/images/20211115/20137684hmyiMx0OkG.png
API 取得商品列表
https://github.com/hexschool/vue3-course-api-wiki/wiki/%E7%AE%A1%E7%90%86%E6%8E%A7%E5%88%B6%E5%8F%B0-%5B%E9%9C%80%E9%A9%97%E8%AD%89%5D#%E5%95%86%E5%93%81%E5%BB%BA%E7%AB%8B

(1)修改ProductModal.vue 弹跳视窗样式,方便输入值(保留ref)

模板 增加 Bootstrap Modal
https://github.com/hexschool/vue3-course-api-wiki/wiki/%E8%AA%B2%E7%A8%8B%E9%83%A8%E5%88%86%E6%A8%A1%E6%9D%BF

(2)修改products.vue 弹跳视窗独立方法

    openModal() {
      this.tempProduct = {};
      const productComponent = this.$refs.productModal;
      productComponent.showModal();
    },

(3)修改ProductModal.vue 新增仓库接收外层(products.vue)输入的资料

https://ithelp.ithome.com.tw/upload/images/20211115/20137684oUu1GDxQwf.png
https://ithelp.ithome.com.tw/upload/images/20211115/20137684yOgIW3msS4.png

(4)products.vue 新增方法接收ProductModal.vue送进的值(item)

emit内传外

ProductModal.vue
emit送出去

            v-on:click="$emit('update-product',tempProduct)"
            type="button" class="btn btn-primary">确认</button>

products.vue
接收

    <ProductModal 
    v-on:update-product="updateProduct"
    ref="productModal">
    </ProductModal>


    updateProduct(item) {
      // 从内层(ProductModal.vue)接收资料, 送进tempProduct仓库
      this.tempProduct = item;

https://ithelp.ithome.com.tw/upload/images/20211115/20137684sgxIxsy4jn.png

(5)products.vue 并送值到资料库(使用axios)

      this.$http.post(api, { data: this.tempProduct })
      .then((res)=>{
        // then 成功
        console.log(res);
        // 执行 ProductModal.vue 的 hideModal()
        productComponent.hideModal();
        // 执行
        this.getProducts();
      })

title(String)
category(String)
unit(String)
origin_price(Number)
price(Number) 为必填栏位
https://ithelp.ithome.com.tw/upload/images/20211115/20137684LcaxyH2sAr.png


13. 产品资料更新 - (编辑)

API 修改产品
https://github.com/hexschool/vue3-course-api-wiki/wiki/%E7%AE%A1%E7%90%86%E6%8E%A7%E5%88%B6%E5%8F%B0-%5B%E9%9C%80%E9%A9%97%E8%AD%89%5D#%E4%BF%AE%E6%94%B9%E7%94%A2%E5%93%81

products.vue

(1)增加 是否为新增商品判断 仓库

  data() {
    return {
      isNew: false,
    };

(2)点击新增按钮时,带入参数 True

true = 点此按钮时要新增商品

    v-on:click="openModal(true)"

(3)点击编辑按钮时,带入参数 false

false = 点此按钮时非新增商品 = 编辑商品
item = v-if="item.is_enabled" 的 item

    v-on:click="openModal(false,item)"

有够方便。
https://ithelp.ithome.com.tw/upload/images/20211115/20137684OmjPFBhLZ1.png

(4)在跳窗的方法openModal带入参数 及 增加判断式 (渲染、显示)

此时判断 新增商品 or 编辑商品

    openModal(isNew, item) {
      // if isNew = true
      if(isNew){
        // 新增商品
        this.tempProduct ={};
      }else{
        // 编辑商品
        // ... 展开旧的item
        this.tempProduct ={...item};
      }

https://ithelp.ithome.com.tw/upload/images/20211115/20137684g7unyDo0so.png

(5)将资料写进後端API

API 修改产品
https://github.com/hexschool/vue3-course-api-wiki/wiki/%E7%AE%A1%E7%90%86%E6%8E%A7%E5%88%B6%E5%8F%B0-%5B%E9%9C%80%E9%A9%97%E8%AD%89%5D#%E4%BF%AE%E6%94%B9%E7%94%A2%E5%93%81

updateProduct(item) {
      // 从内层(ProductModal.vue)接收资料, 送进tempProduct仓库
      this.tempProduct = item;

      // 新增
      // API使用方式 取得商品列表
      let api = `${process.env.VUE_APP_API}api/${process.env.VUE_APP_PATH}/admin/product`;
      let httpMethod = "post";

      // 编辑
      if (!this.isNew) {
        api = `${process.env.VUE_APP_API}api/${process.env.VUE_APP_PATH}/admin/product/${item.id}`;
        httpMethod = "put";
      }
      // this.$refs.productModal = html 内 <ProductModal ref="productModal"></ProductModal>
      const productComponent = this.$refs.productModal;

      this.$http[httpMethod](api, { data: this.tempProduct }).then((res) => {
        // then 成功
        console.log(res);
        // 执行 ProductModal.vue 的 hideModal()
        productComponent.hideModal();
        // 执行 取得列表资料
        this.getProducts();
      });
    },

https://ithelp.ithome.com.tw/upload/images/20211115/201376846uRLqHK1eE.png

为何使用[]?
如果 $http.httpMethod(xxxx) 会被判定成function

https://ithelp.ithome.com.tw/upload/images/20211115/20137684uczc3kcVja.png


14. 透过 API 上传图片

API
https://github.com/hexschool/vue3-course-api-wiki/wiki/%E7%AE%A1%E7%90%86%E6%8E%A7%E5%88%B6%E5%8F%B0-%5B%E9%9C%80%E9%A9%97%E8%AD%89%5D#%E4%B8%8A%E5%82%B3%E5%9C%96%E7%89%87
https://ithelp.ithome.com.tw/upload/images/20211115/20137684iKuDW1u0SK.png

目标:点击新增产品内上传图片,可上传图片进资料库
取出档案,并改成FormData格式

ProductModal.vue

(1)input改变时,呼叫该方法

    v-on:change="uploadfile"

(2)并给该input id 好取值

    ref="fileInput"

(3)制作uploadfile方法,取出档案,并改成FormData格式

抓files[0]
![https://ithelp.ithome.com.tw/upload/images/20211115/20137684nviwLLUWkX.png](https://ithelp.ithome.com.tw/upload/images/20211115/20137684nviwLLUWkX.png)

 uploadfile() {
      // 抓取档案
      // this.$refs.fileInput = ref="fileInput"
      const uploadfile = this.$refs.fileInput.files[0];
      console.dir(uploadfile);

      // 制作成FormData格式
      const formData = new FormData(); //Js
      formData.append("file-to-upload", uploadfile); // "file-to-upload" API接收格式
    },

(4)上传资料库

    uploadfile() {

      //API收图片 表单传送 action
      const url = `${process.env.VUE_APP_API}api/${process.env.VUE_APP_PATH}/admin/upload`;
      //  axios post(api, 欲传送的值)方法方法
      this.$http.post(url, formData).then((response) => {
        console.log(response.data);
        if (response.data.success) {
          this.tempProduct.imageUrl = response.data.imageUrl;
        }
      });
    },

https://ithelp.ithome.com.tw/upload/images/20211115/20137684hbPZHklGwC.png


15. 删除商品

DelModal.vue

https://ithelp.ithome.com.tw/upload/images/20211115/20137684qBnq1pElRk.png


16. 使用 mixin 整合 元件内相同程序码

(1)src > 新增mixins 资料夹 > 新增 modalMixin.js

(2)把重复的资料放进去

(3)放到需要用到的元件内

 import modalMixin from "@/mixins/modalMixin";

 mixins: [modalMixin],

https://ithelp.ithome.com.tw/upload/images/20211115/20137684bCtq013nvT.png


17. 加入读取的视觉效果(vue3套件效果)

https://www.npmjs.com/package/vue3-loading-overlay

(1)安装套件

npm install vue3-loading-overlay

(2)main.js 汇入 并 全域注册

https://ithelp.ithome.com.tw/upload/images/20211115/201376845vUg4rbAgN.png

// 读取动画套件
// Import component
import Loading from "vue3-loading-overlay";
// Import stylesheet
import "vue3-loading-overlay/dist/vue3-loading-overlay.css";

// 全域注册
app.component('Loading', Loading)

(3)供各个网页使用(登入、注册、新增、编辑、删除产品..)

Products.vue、Login.vue
active = true才会转圈圈

 <Loading :active="isLoading"></Loading>


  data() {
    return {
      // 判断是否要loading转圈圈 仓库
      isLoading: false,
    };
  },


    getProdcts() {
      const api = `${process.env.VUE_APP_API}api/${process.env.VUE_APP_PATH}/admin/products`;
      // 捞到资料前有loding
      this.isLoading = true;
      console.log(api);

      this.$http.get(api).then((res) => {
        // 捞到资料loding圈圈关闭
        this.isLoading = false;
        if (res.data.success) {
        }
      });
    },

18.加入错误的讯息回馈 (错误通知) mitt 跨元件沟通(平行、父子层)

目标:编辑或新增商品错误时,跳出错误讯息(BS样式 吐司)通知

Toast分好几个放的优点:可以产生多次、独立的生命周期等...
https://ithelp.ithome.com.tw/upload/images/20211115/20137684SDVS7ZOAVp.png

(1)安装 mitt

npm i mitt

(2)为了让所有的元件可以使用mitt

src > 新增methods资料夹 > 新增 emitter.js档案

(3)汇入mitt

emitter.js

// 汇入
import mitt from "mitt";

const emitter = mitt();

// 使用方式:emitter
export default emitter;

(4)在最外层Dashboard.vue引用

让内层都可以引用外层功能 provide

import emitter from '@/methods/emitter';

  provide() {
    return {
      emitter,
    };
  },

https://ithelp.ithome.com.tw/upload/images/20211115/20137684ATfxEjfXJu.png
https://ithelp.ithome.com.tw/upload/images/20211115/20137684wcQdUbA0wb.png
https://ithelp.ithome.com.tw/upload/images/20211115/201376845Mi4rpFNlh.png

父、子层区分

index.js

    path: "/dashboard",
    name: "Dashboard",
    component: () => import("../views/Dashboard.vue"),
    // 多个,阵列
    children: [
      {
        // http://localhost:8080/#/dashboard/products
        path: "products",
        component: () => import("../views/Products.vue"),
      },
    ],
  },
];

(5)制作吐司 与 使用 emitter

https://ithelp.ithome.com.tw/upload/images/20211115/20137684eTG6lLMrPi.png


19. 加入分页切换 (制作分页元件)

API 取得商品列表
https://github.com/hexschool/vue3-course-api-wiki/wiki/%E7%AE%A1%E7%90%86%E6%8E%A7%E5%88%B6%E5%8F%B0-%5B%E9%9C%80%E9%A9%97%E8%AD%89%5D#%E5%8F%96%E5%BE%97%E5%95%86%E5%93%81%E5%88%97%E8%A1%A8

(1)API改分页模式(/?page=${page}),并检查res

Products.vue

    getProducts( page = 1 ) {
      // 3.使用API抓值 取得商品列表
      const api = `${process.env.VUE_APP_API}api/${process.env.VUE_APP_PATH}/admin/products/?page=${page}`;
      this.$http.get(api).then((res) => {

        if (res.data.success) {
          console.log("res", res);

https://ithelp.ithome.com.tw/upload/images/20211115/20137684Te4SwODHde.png

(2)制作分页元件 Pagination.vue

components > Pagination.vue

https://ithelp.ithome.com.tw/upload/images/20211115/20137684C8epPSUHir.png
https://ithelp.ithome.com.tw/upload/images/20211115/20137684ryTzRyifOo.png

(3)上下页制作

https://ithelp.ithome.com.tw/upload/images/20211115/20137684wKHfIqcRJ9.png


20. 套用全域的千分号 ($1,000)

区域方法

(1)制作 千分号 方法

src > methods > 新增filters.js

export function currency(num) {
  const n = parseInt(num, 10);
  return `${n.toFixed(0).replace(/./g, (c, i, a) => (i && c !== '.' && ((a.length - i) % 3 === 0) ? `, ${c}`.replace(/\s/g, '') : c))}`;
}

(2)汇入欲使用的区域

Products.vue

  import { currency } from "../methods/filters.js";

  methods: {
    // 千分号 方法引用
    currency,

(3)使用

Products.vue

   <td class="text-right">{{ currency(item.origin_price) }}</td>
   <td class="text-right">{{ currency(item.price) }}</td>

全域方法 globalProperties ****

https://v3.cn.vuejs.org/api/application-config.html#globalproperties

// foo 自定义 通常 = function才好用 如 下例
app.config.globalProperties.foo = 'bar'

app.component('child-component', {
  mounted() {
    console.log(this.foo) // 'bar'
  }
})

(1)制作 千分号 方法

src > methods > 新增filters.js

export function currency(num) {
  const n = parseInt(num, 10);
  return `${n.toFixed(0).replace(/./g, (c, i, a) => (i && c !== '.' && ((a.length - i) % 3 === 0) ? `, ${c}`.replace(/\s/g, '') : c))}`;
}

(2)全域汇入

main.js

import { currency } from "./methods/filters.js";

// 全域定义 方法
// https://v3.cn.vuejs.org/api/application-config.html#globalproperties
app.config.globalProperties.$filters = {
  // 转千位数 及 时间方法
  currency,
};

(3)选择任一地方使用

Products.vue

   <td class="text-right">{{ $filters.currency(item.price) }}</td>

21.中场加速 制作 订单资料 及 优惠卷

新增

src/methods/pushMessageState.js 错误讯息吐司 判断式 给Coupons.vue & Orders.vue
Products.vue 内 吐司错误讯息程序码 会因为点击越来越多,故拆开 制作成另一方法
因此 methods > pushMessageState.js
并 全域汇入 给 Coupons.vue & Orders.vue 用
逻辑:因为直接用全域方法(main.js)只会有全域一个仓库(提升效能),但区域方法就会到处都有仓库
https://ithelp.ithome.com.tw/upload/images/20211115/20137684jQDkQBc9UR.png

src/views/Orders.vue 订单页面
src/views/Coupons.vue 优惠页面
src/components/orderModal.vue
src/components/CouponModal.vue

修改

src/components/Navbar.vue 连结样板
src/router/index.js 连结制作
src/main.js 全域汇入pushMessageState = $httpMessageState


生命周期 mounted() vs created() 使用时机

mounted()
html标签跑完後执行
写在mounted就是防止抓不到dom元素 或抓不到html标签的问题产生
ex:Bootstrap Modal、吐司等等..

created()用在一开始要抓值时
ex: API资料


props vs emit vs mitt

(1) props 外传内

Products.vue(外)

   import DelModal from "@/components/DelModal.vue";

   // 口决:前内後外
   <DelModal :item="tempProduct"/>
   
     data() {
       return {
         tempProduct: {},
       };
     },

DelModal.vue(内)

     props: {
       item: {},
     },
     data() {
       return {
         modal: "",
       };

(2) emit 内传外

Products.vue(外)

   import DelModal from "@/components/DelModal.vue";

   // 口决:前内後外
   <DelModal @del-item="delProduct" />

    delProduct() {
      const url = `${process.env.VUE_APP_API}api/${process.env.VUE_APP_PATH}/admin/product/${this.tempProduct.id}`;
      this.isLoading = true;
      this.$http.delete(url).then((response) => {
        this.isLoading = false;
        console.log(response.data);
        const delComponent = this.$refs.delModal;
        delComponent.hideModal();
        this.getProdcts();
      });
    },

DelModal.vue(内)

   @click="$emit('del-item')"

(3) mitt 平行、跨元件沟通(没有谁包谁、父子层)

emitter.js

// 汇入
import mitt from "mitt";

const emitter = mitt();

// 使用方式:emitter
export default emitter;


Dashboard.vue(父)

import emitter from "@/methods/emitter";

  provide() {
    return {
      emitter,
    };
  },

ToastMessages.vue(子)

  // 引用emitter (因 Dashboard.vue provide )
  inject: ["emitter"],

父、子层区分
index.js

    path: "/dashboard",
    name: "Dashboard",
    component: () => import("../views/Dashboard.vue"),
    // 多个,阵列
    children: [
      {
        // http://localhost:8080/#/dashboard/products
        path: "products",
        component: () => import("../views/Products.vue"),
      },
    ],
  },
];

split() 转阵列

let myApple = '123T456';
let arr = myApple.split("T");
consolog(arr) // [123,456]

let myApple2 = '1,2,3,4';
let arr2 = myApple.split(",");
consolog(arr) // [1,2,3,4]


$http 是 axios的方法


<<:  如何建立 Windows USB 安装随身碟-适用 Win 10, Win Server 2019

>>:  (World N0-1)! To Pass LookML-Developer Exam Guide

学习javascript前...CSS1

现在来学习CSS 如果说 HTML 是用来处理主要网页结构,CSS 就是来处理网页细节的。负责美化跟...

实战练习 - 使用 RxJS 实作「自动完成 / 搜寻 / 排序 / 分页」功能

今天我们用实际的例子来练习各种 RxJS operators 的组合运用!在一般的应用程序里面,资料...

Day 19 - 卷积神经网络 CNN (4)-Pooling layer & Activation Function

Pooling Layer 影像的spatial information不会因scale而消失,所以...

DAY 05 实作环境配置 - 2

安装套件 Visual Studio Code 上有很多方便编写程序的扩充套件,能让我们在使用上更加...

[Day13]ISO 27001 标准:风险评监

风险 表示发生,可能会对价值或资产造成负面的冲击。 风险是外部威胁利用弱点对内部资产造成冲击的可能性...