【圖文並茂,點贊收藏哦!】重學鞏固你的Vuejs知識體系(下)

程式設計師哆啦A夢發表於2020-10-19

前沿

置身世外只為暗中觀察!!!Hello大家好,我是魔王哪吒!重學鞏固你的Vuejs知識體系,如果有哪些知識點遺漏,還望在評論中說明,讓我可以及時更新本篇內容知識體系。歡迎點贊收藏!

生命週期

首先:new Vue(),new一個Vue的例項,Observe data資料檢視,init Events繫結事件,created執行created方法,判斷是否有el屬性,如果沒有,vm.$mount(el)表示處於未掛載狀態,可以手動呼叫這個方法來掛載。判斷是否有template屬性。

如果有el屬性,判斷是否有template屬性。

例項化期和載入期
建立期間的生命週期函式:beforeCreatecreatedbeforeMountmounted

beforeCreate在例項初始化後,資料觀測data observerevent/watcher事件配置之前被呼叫。

更新期

執行期間的生命週期函式:beforeUpdateupdated

created例項已經建立完成後被呼叫。

例項已完成以下的配置:資料觀測data observer,屬性和方法的運算,watch/event事件回撥。

掛載階段還沒開始,$el屬性目前不可見。

beforeMount在掛載開始之前被呼叫,相關的render函式首次被呼叫。mountedvm.$el已經掛載在文件內,對已有dom節點的操作可以在期間進行。beforeUpdate資料更新時呼叫,發生在虛擬dmo重新渲染和打補丁之前。updated當這個鉤子被呼叫時,元件dom已經更新,所以你現在可以執行依賴於dom的操作。activateddeactivatedbeforeDestroydestroyed。例項銷燬之前呼叫,vue例項銷燬後呼叫。

解除安裝期

銷燬期間的生命週期函式:beforeDestroydestroyed

例項生命週期鉤子

每個vue例項在被建立時都要經過一系列的初始化過程,需要設定資料監聽,編譯模板,將例項掛載到dom並在資料變化時更新dom等,同時在這個過程中也會執行一些叫做生命週期鉤子的函式。

用於給使用者在不同階段新增自己程式碼的機會。

beforeCreate,此時的data是不可見的

data() {
    return {
        a: 1
    }
},
beforeCreate() {
    // red
    console.log(this.a); // 看不見
}

created例項已經建立完成後被呼叫,這個時候你看不見你頁面的內容,例項已完成表示:資料觀測data observer,屬性和方法的運算,watch/event事件回撥。

這個時候掛載階段還沒開始,$el屬性目前不可見。

export default {
    data() {
        return {
            a: 1
        }
    },
    beforeCreate() {
        console.log(this.a);
    },
    created() {
        // red
        console.log(this.a);
        console.log(this.$el);
        // 此時data資料裡面的a可見,this.$el不可見
    }
}

beforeMount在掛載開始之前被呼叫,相關的render函式首次被呼叫。

export default{
    data() {
        return {
            a: 1
        }
    },
    beforeCreate() {
        console.log(this.a); // 不可見
    },
    created() {
        console.log(this.a);
        console.log(this.$el); // 不可見
    },
    beforeMount() {
        console.log(this.$el); // 不可見
    }
}

mounted

export default {
    data() {
        return {
            a: 1
        }
    },
    mounted() {
        console.log(this.$el); // 此時$el 可見
    }
}

beforeUpdate鉤子,dom更新之前呼叫:

beforeUpdate() {
    console.log(this.a);
}

// document.getElementById("web").innerHTML

updated鉤子,dom更新之後呼叫:

updated() {
    console.log(this.a);
}

// document.getElementById("web").innerHTML

activateddeactivated(元件)

activated() {
    console.log("元件使用了");
},

deactivated() {
    console.log("元件停用了");
Data to Drag},

keep-alivevue的內建元件,能在元件切換過程中將狀態保留在記憶體中,防止重複渲染dom

<keep-alive> 包裹動態元件時,會快取不活動的元件例項,而不會銷燬它們。和<transition>相似,<keep-alive>是一個抽象元件:它自身不會渲染一個DOM元素,也不會出現在父元件鏈中。

當元件在<keep-alive>內被切換,它的activateddeactivated這兩個生命週期鉤子函式將會被對應指定。

它的使用是因為我們不希望元件被重新渲染而影響使用體驗,或者是效能,避免多次渲染降低效能。快取下來,維持當前得狀態。

場景:

  1. 商品列表頁點選商品跳轉到商品詳情,返回後仍顯示原有資訊
  2. 訂單列表跳轉到訂單詳情,返回,等等場景。

keep-alive生命週期:

初次進入時:created > mounted > activated;退出後觸發 deactivated;再次進入:會觸發activated;事件掛載的方法等,只執行一次的放在mounted中;元件每次進去執行的方法放在 activated 中。

app.vue父元件:

<template>
 <div>
  <button @click="myBtn"> myBtn </button>
  <keep-alive>
   <range v-if="isShow"></range>
  </keep-alive>
 </div>
</template>

<script>
 import range from './components/range.vue'
 export default {
     data() {
         return {
             a: 1,
             isShow: true
         }
     },
     methods: {
         myBtn() {
             this.isShow = !this.isShow
         }
     },
     components: {
         range
     }
 }
</script>

beforeDestroydestroyed

beeforeDestroy型別為function,詳細:例項銷燬之前呼叫,在這一步,例項仍然完全可用。

該鉤子在伺服器端渲染期間不被呼叫。

destroyed型別為function,詳細:vue例項銷燬後呼叫,呼叫後,vue例項指示的所有東西都會解繫結,所有的事件監聽器會被移除,所有的子例項也會被銷燬。

該鉤子在伺服器端渲染期間不被呼叫。

beforeRouteEnterbeforeRouteLeave

beforeRouteEnter() {
    console.log('beforeRouteEnter')
},

beforeRouteLeave() {
    console.log('beforeRouteLeave')
}

vue路由使用的,路由進去和路由離開的時候新增的。

created() {
    console.log('開始執行created鉤子函式')
    // 獲取data資料
    console.log('獲取created屬性'+this.value)
    // 獲取頁面元素
    console.log(this.$refs['example'])
    this.$nextTick(()=>{
        console.log('執行created建立的this.$nextTick()函式')
    })
},

mounted() {
    console.log('開始執行mounted鉤子函式')
    // 獲取掛載資料
    console.log('獲取掛載資料--'+this.$refs['example'].innerText)
    this.$nextTick(()=>{
        console.log('執行mounted建立的this.$nextTick()函式')
    })
},

methods: {
    // 更新資料
    updateDate(){
        
    },
    get(){
        this.value='更新data內的value屬性值'
        // 獲取頁面元素資料
        console.log(this.$refs['example').innerText)
        this.$nextTick(()=>{
          console.log(this.$refs['example'].innerText)  
        })
    }
}

var vm=new Vue({})表示開始建立一個Vue的例項物件,init events&liftcycle表示剛初始化了一個vue空的例項物件,這個時候,物件身上,只有預設的一些生命週期函式和預設事件,其他東西都沒有建立,beforeCreate生命週期函式執行的時候,datamethods中的資料都沒有初始化。在created中,datamethods都已經被初始化好了,如果要呼叫methods中的方法,或者操作data中的資料,只能在created中操作。然後vue開始編輯模板,把vue程式碼中的那些指令進行執行,最終在記憶體中生成一個編譯好的最終模板字串,渲染為記憶體中的dom,此時只是在記憶體中,渲染好了模板,並沒有把模板掛載到真正的頁面中去。beforeMount函式執行的時候,模板已經在記憶體中編譯好了,但是尚未掛載到頁面中去。create vm.$el and replace 'el' with it這一步是將記憶體中編譯好的模板,真實的替換到瀏覽器的頁面中去。mounted,只要執行完了mounted,就表示整個vue例項已經初始化完了。此時,元件從建立階段進入到了執行階段。

beforeUpdate執行的時候,頁面中顯示的資料還舊的,而data資料是最新的,頁面尚未和最新的資料保持同步。updated事件執行的時候,頁面和data資料已經保持同步了,都是新的。virtual dom re-render and patch執行,先根據data中最新的資料,在記憶體中,重新渲染出一份最新的記憶體dom樹,當最新的記憶體dom樹被更新之後,會把最新的記憶體dom樹,重新渲染到真實的頁面中,完成資料從dataview的跟新。

beforeDestroy鉤子函式執行時,vue例項就從執行階段,進入到了銷燬階段。此時的例項還是可用的階段,沒有真正執行銷燬過程。destroyed函式執行時,元件已經被完全銷燬了,都不可用了。

vue面試題

談一談你對mvvm的理解

雙向繫結的過程

檢視view,路由-控制器Controller,資料Model

view->domviewModelModel資料

傳統的mvc指使用者操作會請求伺服器端路由,路由會呼叫對應的控制器來處理,控制器會獲取資料,將結果返回給前端,讓頁面重新渲染。

mvvm,對於傳統的前端會將資料手動渲染到頁面上,mvvm模式不需要使用者收到操作dom元素,將資料繫結到viewModel層上,會自動將資料渲染到頁面中,檢視變化會通知viewModel層更新資料。

Vue響應式原理

  1. vue內部是如何監聽message資料的改變
  2. 當資料發生改變,vue是如何知道要通知哪些人,介面發生重新整理

核心:

  • Object.defineProperty,監聽物件屬性的改變
  • 釋出訂閱者模式

程式碼:

Object.keys(obj).forEach(key => {
 let value = obj[key]
 
 Object.defineProperty(obj, key, {
    set(newValue) {
        // 監聽改變
        value = newValue
    },
    get() {
        return value
    }
 })
})

obj.name = 'web'

釋出者訂閱者

class Dep {
    constructor() {
        this.subs = []
    }
}

class Watcher {
    constructor(name) {
        this.name = name;
    }
}

物件的Object.defindeProperty中的訪問器屬性中的getset方法

  • 把資料轉化為gettersetter,建立watcher並收集依賴。

說明:

watcher通過回撥函式更新view;observer觀測data資料,通過get通知dep收集watcherdep通過notify()通知watcher資料更新,watcher通過addDep()收集依賴。

Observer:用於監聽劫持所有data屬性,dep,watcher,viewCompile解析el模板中的指令。

依照下圖(參考《深入淺出vue.js》)

首先從初始化data資料開始,使用Observer監聽資料,個體每個資料屬性新增Dep,並且在Data,有兩個gettersetter。在它的getter過程新增收集依賴操作,在setter過程新增通知依賴的操作。

在解析指令或者給vue例項設定watch選項或者呼叫$watch時,生成對應的watcher並收集依賴。

Data通過Observer轉換成了getter/setter的形式,來對資料追蹤變化。

修改物件的值的時候,會觸發對應的settersetter通知之前依賴收集得到的 Dep 中的每一個Watcher,告訴它們值改變了,需要重新渲染檢視。

資料雙向繫結原理

什麼是響應式的原理

  1. 核心:Object.defineProperty
  2. 預設vue在初始化資料時,會給data中的屬性使用Object.defineProperty重新定義所有屬性,當頁面取到對應屬性時,會進行依賴收集,如果屬性發生變化會通知相關依賴進行更新操作。

initData初始化使用者傳入的data資料,new Observer將資料進行觀測,this.walk(value)進行物件的處理,defineReactive迴圈物件屬性定義響應式變化,Object.defineProperty,使用Object.defineProperty重新定義資料。

使用使用Object.defineProperty重新定義資料的每一項。

Object.defineProperty(obj,key,{
 enumerable: true,
 configurable: true,
 get: function reactiveGetter(){
     const value=getter?getter.call(obj):val
     if(Dep.target){
         dep.depend()
         if(childOb){
             childOb.dep.depend()
             if(Array.isArray(value)){
                 dependArray(value)
             }
         }
     }
     return value
 },
 set: function reactiveSetter(newVal) {
     const value=getter?getter.call(obj).val
     if(newVal === value || (newVal !== newVal && value !==value)){
         return
     }
     if(process.env.NODE_ENV !== 'production' && customSetter){
         customSetter()
     }
     val = newVal
     childOb = !shallow && observe(newVal)
     dep.notify()
 }
})

vue中式如何檢測陣列變化

使用函式劫持的方式,重寫了陣列的方法,vuedata中的陣列進行了原型鏈的重寫,指向了自己定義的陣列原型方法,這樣當呼叫陣列api時,可以通知依賴跟新,如果陣列中包含著引用型別,會對陣列中的引用型別再次進行監控

initData初始化使用者傳入的data資料,new Observer將資料進行觀測,protoAugment(value,arrayMethods)將資料的原型方法指向重寫的原型。

  • 對陣列的原型方法進行重寫
  • observerArray深度觀察陣列中的每一項

程式碼:

if(Array.isArray(value)){
    // 判斷陣列
    if(hasProto){
        protoAugment(value, arrayMethods)// 改寫陣列原型方法
    }else{
        copyAugment(value,arrayMethods,arrayKeys)
    }
    this.observeArray(value)
    //深度觀察陣列中的每一項
}else{
    this.walk(value) 
    // 重新定義物件型別資料
}

function protoAugment(target, src: Object){
    target.__proto__ = src
}

export const arrayMethods = Object.create(arrayProto)
const methodsToPatch=[
 'push',
 'pop',
 'shift',
 'unshift',
 'splice',
 'sort',
 'reverse'
]

methodsToPatch.forEach(function (method){
    const original = arrayProto[method]
    def(arrayMethods, method, function mutator(...args){
        const result = original.apply(this.args)
        const ob = this.__ob__
        let inserted
        switch(method) {
            case 'push':
            case 'unshift':
            inserted = args
            break
            case 'splice':
            inserted = args.slice(2)
            break
        }
        if(inserted) ob.observerArray(inserted)
        // 對插入的資料再次進行觀測
        ob.dep.notify()
        // 通知檢視更新
        return result
    }
}

observeArray(items: Array<any>) {
    for(let i=0, l = items.length; i<1; i++) {
        observe(item[i])
        // 觀測陣列中的每一項
    }
}

為什麼vue採用非同步渲染

如果不採用非同步更新,每次更新資料都會對當前元件進行重新渲染,為了效能考慮。

dep.notify()通知watcher進行更新操作,subs[i].update()依次呼叫watcherupdatequeueWatcherwatcher去重放到佇列中,nextTick(flushSchedulerQueue)非同步清空watcher佇列。

nextTick實現原理

微任務高於巨集任務先執行

nextTick方法主要使用了巨集任務和微任務,定義了一個非同步方法,多次呼叫了nextTick會將方法存入到佇列中,通過這個非同步方法清空當前佇列。

nextTick方法是非同步方法。

原理:nextTick(cb)呼叫nextTick傳入cbcallbacks.push(cb)將回撥存入陣列中,timerFunc()呼叫timerFunc,返回promise支援promise的寫法。

webpack

什麼是webpack,webpack是一個現代的JavaScript應用的靜態模組打包工具。

webpack是前端模組化打包工具

安裝webpack需要安裝node.js,node.js自帶有軟體包管理工具npm

全域性安裝

npm install webpack@3.6.0 -g

區域性安裝

npm install webpack@3.6.0 --save-dev

webpack.config.js固定名檔案:

const path = require("path")
module.exports = {
    entry: './src/main.js',
    output: {
        patch: './dist',
        filename: ''
    },
}

package.json

{
    "name": 'meetwebpack',
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "test": "echo ..."
    },
    "author": "",
    "license": "ISC"
}

什麼是loader

loaderwebpack中一個非常核心的概念

loader使用過程:

  1. 通過npm安裝需要使用的loader
  2. webpack.config.js中的moudules關鍵字下進行配置

package.json中定義啟動

{
    "name": "meetwebpack",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "build": "webpack"
    },
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "webpack": "^3.6.0"
    }
}

webpack的介紹

webpack可以看做是模組打包機,它可以分析你的專案結構,找到JavaScript模組以及其它的一些瀏覽器不能直接執行的擴充語言,將其打包為合適的格式以供瀏覽器使用。

可以實現程式碼的轉換,檔案優化,程式碼分割,模組合併,自動重新整理,程式碼校驗,自動釋出。

安裝本地的webpack

webpack webpack-cli -D

初始化:

yarn init -y
yarn add webpack webpack-cli -D

webpack可以進行0配置,它是一個打包工具,可以輸出後的結果(Js模組),打包(支援js的模組化)

執行webpack命令打包

npx webpack

webpack.config.jswebpacknode寫出來的node的寫法:

let path = require('path')
console.log(path.resolve('dist');

module.exports = {
    mode: 'development',
    // 模式,預設兩種,production,development
    entry: '' // 入口
    output: {
        filename: 'bundle.js',
        // 打包後的檔名
        path: path.resolve(__dirname, 'build'),
        // 把相對路徑改寫為絕對路徑
    }
}

自定義,webpack.config.my.js

使用命令:

npx webpack --config webpack.config.my.js

package.json:

{
    "name": 'webpack-dev-1',
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "scripts": {
      "build": "webpack --config webpack.config.my.js"  
    },
    "devDependencies": {
        "webpack": "^4.28.3",
        "webpack-cli": "^3.2.0"
    }
}

使用命令:

npm run build

// npm run build -- --config webpack.config.my.js
開發伺服器的配置

程式碼:

let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin')
console.log(path.resolve('dist');

module.exports = {
    devServer: {
      // 開發伺服器的配置  
      port: 3000,
      // 看到進度條
      progress: true,
      contentBase: "./build",
      compress: true
    },
    mode: 'development',
    // 模式,預設兩種,production,development
    entry: '' // 入口
    output: {
        filename: 'bundle.js',
        // 打包後的檔名
        path: path.resolve(__dirname, 'build'),
        // 把相對路徑改寫為絕對路徑
    },
    plugins: [
        // 陣列,所有的webpack外掛
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            minify:{
                removeAttributeQuotes: true,//刪除“”
                collapseWhitespace: true, // 變成一行
               
            },
             hash: true
        })
    ],
    module: {
        // 模組
        rules: [
            // 規則
            {test: /\.css$/, use: [{
                loader: 'style-loader',
                options: {
                    insertAt: 'top'
                }
            },'css-loader'] },
        ]
    }
}
output: {
    filename: 'bundle.[hash:8].js',// 打包檔名後只顯示8位
}
{
    "name": 'webpack-dev-1',
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "scripts": {
      "build": "webpack --config webpack.config.my.js",
      "dev": "webpack-dev-server"
    },
    "devDependencies": {
        "webpack": "^4.28.3",
        "webpack-cli": "^3.2.0"
    }
}
yarn add css-loader style-loader -D

樣式:

  1. style-loader將模組的匯出作為樣式新增到dom
  2. css-loader解析css檔案後,使用import載入,並且返回css程式碼
  3. less-loader載入和轉譯less檔案
  4. sass-loader載入和轉譯sass/scss檔案
  5. postcss-loader使用PostCSS載入和轉譯css/sss檔案
  6. stylus-loader載入和轉譯Stylus檔案

style-loader安裝:

npm install style-loader --save-dev

用法:

建議將style-loadercss-loader結合使用

component.js

import style from './file.css'
  1. css-loader只負責將css檔案進行載入
  2. style-loader負責將樣式新增到dom
  3. 使用多個loader時,是從右到左

程式碼:

// webpack.config.js
module: {
    rules: [
        {
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
        }
    ]
}
css檔案處理:style-loader

安裝style-loader

npm install --save-dev style-loader

style-loader需要放在css-loader的前面,webpack在讀取使用的loader的過程中,是按照從右向左的順序讀取的。

webpack.config.js的配置如下:

const path = require('path')

module.exports = {
    // 入口:可以是字串/陣列/物件,這裡我們入口只有一個,所以寫一個字串即可。
    entry: './src/main.js',
    // 出口:通常是一個物件,裡面至少包含兩個重要屬性,path和filename
    output:{
        path: path.resolve(__dirname, 'dist'), // 注意:path通常是一個絕對路徑
        filename: 'bundle.js'
    },
    module: {
        rules: {
            {
                test: /\.css$/,
                use: ['style-loader','css-loader']
            }
        }
    }
}

webpack less檔案處理

安裝:

npm install --save-dev less-loader less

示例:

css-loader,style-loader,less-loader鏈式呼叫,可以把所有樣式立即應用於dom

// webpack.config.js
module.exports = {
    ...
    rules: [{
        test: /\.less$/,
        use: [{
            loader: 'style-loader'
        },{
            loader: 'css-loader'
        },{
            loader: 'less-loader'
        }]
    }]
}
圖片檔案處理

css normal程式碼:

body {
    background: url("../img/test.jpg")
}

url-loader

npm install --save-dev url-loader

用法

url-loader功能類似於file-loader,但是在檔案大小低於指定的限制時,可以返回一個DataURL

import img from './image.png'

webpack.config.js

module.exports = {
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192
                        }
                    }
                ]
            }
        ]
    }
}

img,檔案要打包到的資料夾

name,獲取圖片原來的名字,放在該位置

hash:8,為了防止圖片名稱衝突,依然使用hash,但是我們只保留8位

ext,使用圖片原來的副檔名

es6轉es5的babel

如果希望es6轉成es5,那麼就需要使用babel

npm install --save-dev babel-loader@7 babel-core babel-preset-es2015

配置webpack.config.js檔案:

{
    test: /\.m?js$/,
    use: {
        loader: 'babel-loader',
        options: {
            presets: ['es2015']
        }
    }
}

使用vue

如何在我們的webpack環境中整合vue.js

程式碼:

npm install vue --save
  1. runtime-only程式碼中,不可以有任何的template
  2. runtime-compiler程式碼中,可以有template因為有compiler可以用於編譯template

spa(simple age web application)->vue-router(前端路由)

.vue檔案封裝處理

安裝vue-loadervue-template-compiler

npm install vue-loader vue-template-compiler --save-dev

認識webpack的plugin

  1. plugin是什麼?
  • plugin是外掛的意思,通常用於對某個現有的架構進行擴充套件。
  • webpack中的外掛,是對webpack現有功能的各種擴充套件。
  1. loaderplugin的區別
  • loader主要用於轉換某些型別的模組,它是一個轉換器。
  • plugin是外掛,它是對webpack本身的擴充套件,是一個擴充套件器。
  1. plugin的使用過程:
  • 通過npm安裝需要使用的plugins
  • webpack.config.js中的plugins中配置外掛

webpack.config.js的檔案:

檢視bundle.js檔案的頭部:

Vue Cli詳解

什麼是vue cliCommand-Line Interface,命令列介面,俗稱腳手架,vue cli是一個官方釋出的專案腳手架。使用vue-cli可以快速搭建vue開發環境以及對應的webpack配置。

vue cli的使用

安裝vue腳手架

npm install -g @vue/cli

vuecli2初始化過程

程式碼:

vue init webpack vuecli2test
  1. 根據名稱建立一個資料夾,存放之後專案的內容,該名稱會作為預設的專案名稱,但是不能包含大寫字母等
  2. Project name 專案名稱,不能包含大寫
  3. Project description專案描述
  4. Author作者資訊
  5. Vue build`runtime`
  6. Install vue-router`no`是否安裝等
目錄結構詳解

build`configwebpack相關配置,node_modules 是依賴的node相關的模組,src是寫程式碼地方。 .babelrc是es程式碼相關轉換配置,.editorconfig專案文字相關配置,.gitignore`git倉庫忽略的資料夾配置,.postcssrc.jscss相關轉化的配置。

.editorconfig

前端模組化:

為什麼使用模組化,簡單寫js程式碼帶來的問題,閉包引起程式碼不可複用,自己實現了簡單的模組化,es中模組化的使用:exportimport

npm install @vue/cli -g
npm clean cache -force

vue cli2初始化:

vue init webpack my-project

vue cli3初始化專案:

vue create my-project

箭頭函式的使用和this

箭頭函式,是一種定義函式的方式

  1. 定義函式的方式:function
const a = function(){
    
}
  1. 物件字面量中定義函式
const obj = {
    b: function() {
        
    },
    b() {
        
    }
}
  1. 箭頭函式
const c = (引數列表) => {
    
}
const c = () => {
    
}
箭頭函式引數和返回值

程式碼:

const sum = (num1, num2) => {
    return num1 + num2
}

const power = (num) => {
    return num * num
}

const num = (num1,num2) => num1 + num2
const obj = {
    a() {
        setTimeout(function() {
            console.log(this); // window
        })
        setTimeout(()=>{
          console.log(this); // obj物件 
        })
    }
}

路由,,vue-router基本使用,vue-router巢狀路由,vue-router引數傳遞,vue-router導航守衛。

路由是一個網路工程裡面的術語,路由就是通過互聯的網路把資訊從源地址傳輸到目的地址的活動。

路由器提供了兩種機制:路由和轉送。路由是決定資料包從來源到目的地的路徑,轉送將輸入端的資料轉移到合適的輸出端。路由中有一個非常重要的概念叫路由表。路由表本質上就是一個對映表,決定了資料包的指向。

後端路由:後端處理url和頁面之間的對映關係。

前端路由和後端路由,前端渲染和後端渲染

vue-routerkoa-router的區別:

vue-router是前端路由,koa-router是後端路由。

vue-router前端路由原理:

前端路由主要模式:hash模式和history模式。

路由的概念來源於服務端,在服務端中路由描述的是 URL 與處理函式之間的對映關係。

前後端渲染之爭

url中的hashhtml5history

前端路由的核心是改變url,但是頁面不進行整體的重新整理。單頁面,其實spa最重要的特點就是在前後端分離的基礎上加了一層前端路由。就是前端來維護一套路由規則。

urlhash

urlhash是錨點#,本質上是改變window.locationhref屬性。直接賦值location.hash來改變href,但是頁面不發生重新整理。

html5history模式:pushState

html5history模式:replaceState

html5history模式:go

history.go()

history.back()等價於history.go(-1)

history.forward()等價於history.go(1)

安裝vue-router

npm install vue-router --save
  1. 匯入路由物件,並且呼叫Vue.use(VueRouter)
  2. 建立路由例項,並且傳入路由對映配置
  3. Vue例項中掛載建立的路由例項

程式碼:

// 配置路由相關的資訊
import VueRouter from 'vue-router'
import vue from 'vue'
import Home from '../components/Home'
import About from '../components/About'

// 通過Vue.use(外掛),安裝外掛
Vue.use(VueRouter)

// 配置路由和元件之間的應用關係
const routes = [
 {
     path: '/home',
     component: Home
 },
 {
     path: '/about',
     component: About
 }
]

// 建立VueRouter物件
const router = new VueRouter({
 routes
})

// 將router物件傳入到`Vue`例項
export default router

main.js

import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

new Vue({
 el: '#app',
 router,
 render: h => h(App)
})

使用vue-router的步驟

  1. 建立路由元件
  2. 配置路由對映:元件和路徑對映關係
  3. 使用路由:通過<router-link><router-view>

程式碼:

元件components

// home
<template>
 <div>
  <h2>我是首頁</h2>
 </div>
</template>

<script>
 export default {
     name: 'Home'
 }
</script>

<style scoped>
</style>
<template>
 <div>
  <h2>我是關於</h2>
 </div>
</template>

<script>
 export default {
     name: 'Aboout'
 }
</script>

<style scoped>
</style>

App.vue

<template>
 <div id="app">
  <router-link to="/home">首頁</router-link>
  <router-link to="/about">關於</router-link>
  <router-view></router-view>
 </div>
</div>

<script>
export default {
    name: 'App'
}
</script>

<style>
</style>

main.js

import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
new Vue({
 el: '#app',
 router,
 render: h => h(App)
})
路由的偶然值和修改為history模式

建立router例項

程式碼:

router->index.js

import Vue from 'vue'
import VueRouter from 'vue-router'

// 注入外掛
Vue.use(VueRouter)

// 定義路由
const routes = []

// 建立router例項
const router = new VueRouter({
 routes
})

// 匯出router例項
export default router

main.js程式碼:

import Vue from 'vue'
import App from './App'
import router from './router'

new Vue({
 el: '#app',
 router,
 render: h=>h(App)
})

router->index.js

import Vue from 'vue'
import VueRouter from 'vue-router'

import Home from '../components/home'
import About from '../components/about'

// 注入外掛
Vue.use(VueRouter)

// 定義路由
const  routes = [
 {
     path: '/home',
     component: Home
 },
 {
     path: '/about',
     component: About
 }
]

使用App.vue程式碼

<template>
 <div id="app">
  <router-link to="/home">首頁</router-link>
  <router-link to="/about">關於</router-link>
  <router-view></router-view>
 </div>
</template>
<script>
export default {
    name: 'App',
    components: {
        
    }
}
  1. <router-link>該標籤是一個vue-router已經內建的元件,它會被渲染成一個<a>標籤
  2. <router-view>該標籤會根據當前的路徑,動態渲染出不同的元件。
  3. 網頁的其他內容,比如頂部的標題或導航,或者底部的一些版本資訊等會和<router-view>處於同一個等級。
  4. 在路由切換時,切換的是<router-view>掛載的元件,其他內容不會發生改變。

路由的預設路徑

預設情況下,進入網站的首頁,<router-view>渲染首頁的內容,但是預設沒有顯示首頁元件,必須讓使用者點選才可以。

那麼如何讓路徑預設跳轉到首頁,並且<router-view>渲染首頁元件呢,只需要配置一個對映就可以:

const routes = [
 {
     path: '/',
     redirect: '/home'
 }
]

配置解析:在routes中又配置了一個對映,path配置的是根路徑:/redirect是重定向,就是我們將根路徑重定向到/home的路徑下。

// main.js
const router = new VueRouter({
 // 配置路由和元件之間的應用關係
 routes,
 mode: 'history'
})

改變路徑的方式:

  1. urlhash
  2. html5history
  3. 預設情況下,路徑的改變使用的urlhash

使用html5history模式:

// 建立router例項
const router = new VueRouter({
 routes,
 mode: 'history'
})

router-link,使用了一個屬性:to,用於指定跳轉的路徑。tag可以指定<router-link>之後渲染成什麼元件。

replace屬性不會留下history記錄,指定replace的情況下,後退鍵返回不能返回到上一個頁面中。

active-class屬性,當<router-link>對應的路由匹配成功時,會自動給當前元素設定一個router-link-activeclass,設定active-class可以修改預設的名稱。

const router = new VueRouter({
 routes,
 mode: 'history',
 linkActiveClass: 'active'
})

路由程式碼跳轉

App.vue程式碼:

// app.vue
<template>
 <div id="app">
  <button @click="linkToHome">首頁</button>
  <button @click="linkToAbout">關於</button>
  <router-view></router-view>
 </div>
</template>

<script>
 export default {
     name: 'App',
     methods: {
         linkToHome() {
             this.$router.push('/home')
         },
         linkToAbout() {
             this.$router.push('/about')
         }
     }
 }
</script>

<img :src="imgURL" alt="">

<router-link :to="'/uer/' + userId"> 使用者 </router-link>

<script>
 export default {
     name: 'User',
     computed: {
         userId() {
             return this.$route.params.userId
         }
     }
 }
</sript>

const Home = () => import('../components/Home')
const HomeNews = () => import('../components/HomeNews')
const HomeMessage = () => import('../components/HomeMessage')

{
    path: '/home',
    component: Home,
    children: [
        {
            path: 'news',
            component: HomeNews
        },
        {
            path: 'news',
            component: HomeMessage
        }
    ]
}
<router-link to = "/home/news">新聞</router-link>
<router-link to = "/home/message">資訊</router-link>

預設選中:

傳遞引數的方式

傳遞引數主要有兩種型別,paramsquery

params的型別:

  1. 配置路由方式:/router/:id
  2. 傳遞的方式:在path後面跟著對應的值
  3. 傳遞後形成的路徑:/router/123

vue-router傳遞引數程式碼

<router-link :to="{path: '/profile'}">使用者</router-link>

統一資源定位符

統一資源定位符,統一資源定位器,統一資源定位地址,Url地址等,網頁地址。如同在網路上的門牌,是因特網上標準的資源的地址。

userClick() {
    this.$router.push('/user/' + this.userId)
}

btnClick() {
    this.$router.push({
     path: '/user',
     query: {
         name: 'web',
         age: 12,
         height: 1.2
     }
    })
}

$route$router是有區別的

獲取引數通過$route物件獲取的,在使用vue-router的應用中,路由物件會被注入每個元件中,賦值為this.$route,並且當路由切換時,路由物件會被更新。

<template>
 <div>
  <p> {{$route.params}} </p>
 </div>
</template>

query的型別:

  1. 配置路由格式:/router也是普通配置
  2. 傳遞方式,物件中使用querykey作為傳遞方式
  3. 傳遞後形成的路徑,router?id=123,/router?id=abc

$route$router是有區別的

const router = new VueRouter({
 routes,
 mode: 'history',
 linkActiveClass: 'active'
})

Vue.config.productionTip = false

Vue.prototype.test = function() {
    console.log('test')
}

Vue.prototype.name  = 'web'

$route$router是有區別的

  1. $routerVueRouter例項,想要導航到不同url,則使用$router.push方法。
  2. $route為當前router跳轉物件裡面可以獲取name,path,query,params等。

vue-router全域性導航

meta:後設資料

router.beforeEach((to,from,next) => {
    // from 跳轉到to
    document.title = to.matched[0].meta.title
    console.log(to);
    next()
})
// 後置鉤子hook
router.afterEach((to,from) => {
  console.log();  
})

導航守衛:導航表示路由正在發生改變。

vue-router提供的導航守衛主要用來通過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程中,全域性的,單個路由獨享的,或者元件級的。

全域性守衛

可以使用router.beforeEach,註冊一個全域性前置守衛:

const router = new VueRouter({..})

router.beforeEach((to,from,nex)=>{
    
})

當一個導航觸發時,全域性前置守衛按照建立順序呼叫。守衛是非同步解析執行,此時導航在所有守衛resolve完之前一直處於等待中。

  1. to:Route,即將要進入的目標路由物件
  2. from:Route,當前導航正要離開的路由
  3. next:Function,一定要呼叫該方法來resolve這個鉤子。

vue-router-keep-alive

keep-alivevue-router

router-view是一個元件,如果直接被包含在keep-alive裡面,所有路徑匹配到的檢視元件都會被快取。

keep-aliveVue內建的一個元件,可以使被包含的元件保留狀態,或避免重新渲染。

屬性:

  1. include字串或正規表示式,只有匹配的元件會被快取
  2. exclude字串或正規表示式,任何匹配的元件都不會被快取
<keep-alive>
 <router-view>
  // 所有路徑匹配到的檢視元件都會被快取
 </router-view>
<keep-alive>

Promise的使用

es6的特性Promise,它是非同步程式設計的一種解決方案。

定時器的非同步事件:

setTimeout(function() {
    let data = 'web'
    console.log(content)
},1000)

new Promise((resolve, reject) => {
    setTimeout(function(){
        resolve('web')
        reject('error')
    },1000)
}).then(data=>{
    console.log(data)
}).catch(error=> {
    console.log(error)
})

Promise三種狀態:

  1. pending等待狀態,比如正在進行網路請求,或定時器沒有到時間。
  2. fulfill,滿足狀態,主動回撥resolve時,並且回撥.then()
  3. reject,拒絕狀態,回撥reject時,並且回撥.catch()

Vuex詳解

vuex是一個專門為vue.js應用程式開發的狀態管理模式

它採用集中式儲存管理應用的所有元件的狀態,,並以相應的規則保證狀態以一種可預測的方式發生變化。

  1. 狀態管理模式
  2. 集中式儲存管理

View components -> actions(dispatch方式) -> mutations(commit方式) -> state -> View components

Vuex核心概念5個:

StateGettersMutationActionModule

State單一狀態樹,單一資料來源。

Mutation狀態更新

Vuexstore的更新唯一方式,提交Mutation

Mutation的主要包括兩部分:

  1. 字串的事件型別
  2. 一個回撥函式,該回撥函式的第一個引數就是state

mutation的定義:

mutations: {
    increment(state) {
        state.count++
    }
}

通過mutation更新

increment: function() {
    this.$store.commit('increment')
}

引數被稱為是mutation的載荷payload

Vuexstore中的state是響應式的,當state中的資料發生改變時,Vue元件會自動更新。

  1. 提前在store中初始化好所需的屬性
  2. state中的物件新增新屬性時:使用
  • 使用Vue.set(obj,'newObj',123)
  • 用新物件給舊物件賦值

Mutation常量型別

// mutation-types.js
export const UPDATE_INFO = 'UPDATE_INFO'

import Vuex from 'vuex'
import Vue from 'vue'
import * as types from './mutation-types'

Vue.use(Vuex)

const store = new Vuex.Store({
    state: {
        info: {
            name: 'web',
            age: 12
        }
    },
    mutations: {
        [types.UPDATE_INFO](state, payload) {
            state.info = {...state.info, 'height': payload.height
        }
    }
})
<script>
 import {UPDATE_INFO} from './store/mutation-types';
 export default{
     name: 'App',
     components: {
         
     },
     computed: {
         info(){
             return this.$store.state.info
         }
     },
     methods: {
         updateInfo(){
             this.$store.commit(UPDATE_INFO,{height:1.00})
         }
     }
 }
</script>

注意:不要再mutation中進行非同步操作,mutation同步函式,在其中的方法必須時同步方法。

action的基本定義,如果有非同步操作,比如網路請求,

// 不能再mutation中使用非同步操作,不能再這裡進行非同步操作
update(state) {
    setTimeout(()=>{
        state.info.name = 'web'
    },1000)
}

mutations: {
    // 方法
    [INCREMENT](state){
        state.counter++
    }
}
actions: {
    // context:上下文,=》store
    <!--aUpdateInfo(context) {-->
    <!--    setTimeout(()=>{-->
    <!--        state.info.name = 'web'-->
    <!--    },1000)-->
    <!--}-->
}
actions: {
    aUpdateInfo(context) {
        setTimeout(()=>{
            context.commit('updateInfo')
        },1000)
    }
}

// xx.vue
updateInfo(){
    this.$store.dispatch('aUpdateInfo')
}

updateInfo(){
    <!--this.$store.commit('updateInfo')-->
    this.$store.dispatch('aUpdateInfo',{
        message: 'web',
        success: () => {
            console.log('web')
        }
    })
}
aUpdateInfo(context, payload) {
    return new Promise((resolve, reject) => {...})
}

vuex中的modules使用

modules時模組的意思

getters: {
    stu(){
        
    },
    stuLength(state, getters) {
        return getters.stu.length
    }
}

使用根資料:

getters: {
    fullName(state) {
        return state.name + '1'
    },
    fullName1(state, getters) {
        return getters.fullName + '2'
    },
    fullName3(state, getters, rootState) {
        return getters.fullName2+rootState.counter
    }
}

在模組中actions列印console.log(context)

actions接收一個context引數物件,區域性狀態通過context.state暴露出來,根節點狀態為context.rootState

import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import moduleA from './modules/moduleA'

import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)

const state = {
    
}

const store = new Vuex.Store({
    state,
    mutations,
    actions,
    getters,
    modules: {
        a: moduleA
    }
})

export default store

網路封裝

axios網路模組的封裝

ajax是基於XMLHttpRequest(XHR)jQuery-Ajax相對於傳統的ajax非常好用。

axios特點:

  • 在瀏覽器中傳送XMLHttpRequests請求
  • node.js中傳送http請求
  • 支援Promise API
  • 攔截請求和響應
  • 轉換請求和響應資料

axios請求方式:

axios(config)
axios.request(config)
axios.get()
axios.delete()
axios.head()
axios.post()
axios.put()
axios.patch()

安裝

npm install axios --save
axios({
    // 預設get
    url: '',
    method: 'get'
}).then(res=>{
    console.log(res)
})
// import request from "../utils/request.js"
import {request} from './network'

export function getHome() {
    return request({
        url: '/home/xxx'
    })
}

export function getXX(type, page) {
    return request({
        url: '/home/xx',
        params: {
            type,
            page
        }
    })
}
併發請求

程式碼:

axios.all([axios({
 url: ''
}), axios({
 url: '',
 params: {
     type: '',
     page: 1,
 }
})]).then(results => {

})

// then(axios.spread((res1,res2)=>{...}))

全域性配置

axios.defaults.baseURL=''

axios.all ..{
    url: '/home'
}

axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

axios.defaults.baseURL = global.HOST;

request.js

import axios from 'axios'
export function request(config,success,failure){
    // 建立axios例項
    const instance = axios.create({
        baseURL: '',
        timeout: 5000
    })
    // 傳送網路請求
    instance(config)
    .then(res=>{
        success(res)
    })
    .catch(err=>{
        failure(err)
    })
}

main.js

import {request} from './xx/request'

request({
    url: ''
},res=>{

),err=>{
    
}

也可以使用promise方法,不過本身返回的就是promise

import axios from 'axios'
export function request(config) {
    const instance = axios.create({
        baseURL: '',
        timeout: 2000
    })
    return instance(config)
}

axios攔截器的使用

// 配置請求和響應攔截
instance.interceptors.request.use(config => {
    console.log('request攔截success中')
    return config
},err => {
    console.log('request攔截failure中')
    return err
})

instance.interceptors.response.use(response => {
    console.log('response攔截success中')
    return response.data
},err => {
    console.log('response攔截failure中')
    return err
})

封裝axios

// request.js
import axios from 'axios'
cosnt service = axios.create({
 baseURL: process.env.BASE_API,
 timeout: 2000
})

service.interceptors.request.use(config=>{
 //發請求前做的一些處理,資料轉化,配置請求頭,設定token,設定loading等
 config.data=JSON.stringify(config.data);
 config.headers = {
     'Content-Type':'application/x-www-form-urlencoded'
 }
 return config
},error=>{
 Promise.reject(error)
})

// 響應攔截器
service.interceptors.response.use(response => {
 return response
}, error => {
  if (error && error.response) {
    switch (error.response.status) {
      case 400:
        error.message = '錯誤請求'
        break;
      case 401:
        error.message = '未授權,請重新登入'
        break;
      case 403:
        error.message = '拒絕訪問'
        break;
      case 404:
        error.message = '請求錯誤,未找到該資源'
        window.location.href = "/NotFound"
        break;
      case 405:
        error.message = '請求方法未允許'
        break;
      case 408:
        error.message = '請求超時'
        break;
      case 500:
        error.message = '伺服器端出錯'
        break;
      case 501:
        error.message = '網路未實現'
        break;
      case 502:
        error.message = '網路錯誤'
        break;
      case 503:
        error.message = '服務不可用'
        break;
      case 504:
        error.message = '網路超時'
        break;
      case 505:
        error.message = 'http版本不支援該請求'
        break;
      default:
        error.message = `連線錯誤${error.response.status}`
    }
  } else {
    if (JSON.stringify(error).includes('timeout')) {
      Message.error('伺服器響應超時,請重新整理當前頁')
    }
    error.message('連線伺服器失敗')
  }
  Message.error(err.message)
  return Promise.resolve(error.response)
})
// 匯入檔案
export default service

封裝請求http.js

import request from './request'
const http ={
    /**
     * methods: 請求
     * @param url 請求地址 
     * @param params 請求引數
     */
    get(url,params){
        const config = {
            methods: 'get',
            url:url
        }
        if(params){
         config.params = params
        }
        return request(config)
    },
    post(url,params){
        const config = {
            methods: 'post',
            url:url
        }
        if(params){
         config.data = params
        }
        return request(config)
    },
    put(url,params){
        const config = {
            methods: 'put',
            url:url
        }
        if(params){
         config.params = params
        }
        return request(config)
    },
    delete(url,params){
        const config = {
            methods: 'delete',
            url:url
        }
        if(params) {
         config.params = params
        }
        return request(config)
    }
}

export default http
// api.js
import http from '../utils/http'
let resquest = "/xx/request/"
// get請求
export function getListAPI(params){
    return http.get(`${resquest}/getList.json`,params)
}

// js

//建立新的axios例項,
const service = axios.create({
  baseURL: process.env.BASE_API,
  timeout: 3 * 1000
})

專案

建立專案:

vue create webMall

npm run serve

// .editorconfig
root = true
[*]
charset = utf-8
indent_style=space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
專案在window下部署

main.js程式碼:

import store from './store'
import FastClick from 'fastclick'
import VueLazyLoad from 'vue-lazyload'

import toast from 'components/common/toast'

Vue.config.productionTip = false
// 新增事件匯流排物件
Vue.prototype.$bus = new Vue()
// 安裝toast外掛
Vue.use(toast)
// 解決移動端300ms延遲
FastClick.attach(document.body)
// 使用懶載入的外掛
Vue.use(VueLazyLoad,{
 loading: require('./xx.png')
})

windows安裝nginxlinux部署,centos上安裝nginx

linux ubuntu

Ubuntu是一個以桌面應用為主的Linux作業系統,其名稱來自非洲南部祖魯語或豪薩語的“ubuntu"一詞。

作業系統:Window10 + Centos6.5(虛擬機器)

yum install nginx
systemtl start nginx.service
systemctl enable nginx.service

通過Xftp將vue專案檔案上傳至雲伺服器

使用Xshell連線雲伺服器

主機就是阿里雲上建立的例項的公網ip

輸入登入名和密碼,登入名就是購買伺服器時輸入的登入名和密碼。

執行npm run build命令,有一個dist資料夾,這就是vue專案打包後的檔案。

nginx安裝配置

Xshell終端輸入命令yum install nginx,當需要確認時輸入”y“回車。

安裝完成後,輸入service nginx start啟動nginx服務。

通過命令nginx -t檢視nginx所在的安裝目錄。

在命令列輸入命令cd/etc/nginx 切換到nginx目錄下,再輸入cat nginx.conf可檢視當前nginx配置檔案。

輸入命令 wget https://nodejs.org/dist/v10.8.0/node-v10.8.0-linux-x64.tar.xz 回車,等待安裝。

輸入命令tar xvf node-v10.8.0-linux-x64.tar.xz 回車進行解壓操作。

小結:

  1. 計算屬性在多次使用時,只會呼叫一次,因為它是有快取額
  2. 修飾符:stopprevent.enter.once.native等,lazynumbertrim等。
  3. 模板的分類寫法:scripttemplate
  4. 父子元件的通訊:父傳子,props,子傳父,$emit
  5. 專案,npm installnpm run serve
  6. webStorm開發vuePlugins安裝外掛vue.js
  7. 2.6.0 版本中,Vue為具名插槽和作用域插槽引入了一個新的統一的語法 (即 <v-slot> 指令)。它取代了 slotslot-scope 這兩個目前已被廢棄、尚未移除,仍在文件中的特性。
  8. v-slot 用法,分為三類:預設插槽、具名插槽以及作用域插槽。

作用域插槽,通過 slot-scope屬性來接受子元件傳入的屬性集合

  • 預設插槽

程式碼:

// 子元件
<template>
  <div>
  
    <header>
      <slot>預設值</slot>
    </header>
    
  </div>
</template>

任何沒有被包裹在帶有v-slot<template>中的內容都會被視為預設插槽的內容。當子元件只有預設插槽時,<v-slot>標籤可以直接用在元件上

// 父元件
<template>
  <div>
  
    <child>
      內容1
      <template>內容2</template>
      內容3
    </child>

    <child v-slot="web">
      插槽<br>
      插槽<br>
    </child>
    
  </div>
</template>
  • 具名插槽:v-slot 重複定義同樣的 name 後只會載入最後一個定義的插槽內容
// 子元件
<template>
  <div>
  
    <main>
      <slot name="main"></slot>
    </main>
    
    <footer>
      <slot name="footer"></slot>
    </footer>
    
  </div>
</template>
  • 作用域插槽:
// 子元件
<template>
  <div>
  
    <footer>
      <slot name="footer" :user="user" :testBtn="testBtn">
        {{user.name}}
      </slot>
    </footer>
    
  </div>
</template>

<script>

exportdefault {
    name: 'child',
    data () {
      return {
        user: {
          title: 'web',
          name: 'web'
        }
      };
    },
    methods:{
      testBtn(){
        alert('web');
      }
    }
  };
  
</script>

Vue如何直接呼叫Component裡的方法

<template>
  <div>
    <b-component ref="BComponent"></b-component>
  </div>
</template>
 
<script>
import BComponent from './BComponent'
 
export default {
  name: 'A',
 
  data () {
  },
 
  components: {
    BComponent
  },
 
  methods: {
    callACompoentFunction () {
      this.$refs.BComponent.sayHi()
    }
  }
}
</script>
 
<style scoped>
</style>
<template>
  <div></div>
</template>
 
<script>
 
export default {
  name: 'B',
 
  data () {
  },
 
  methods: {
    sayHi () {
      console.log('web!')
    }
  }
}
</script>
 
<style scoped>
</style>

最後

我是程式設計師哆啦A夢,藍胖子,簡書萬粉優秀創作者,掘金優秀作者、CSDN部落格專家,雲+社群社群活躍作者,致力於打造一系列能夠幫助程式設計師提高的優質文章。網站@http://www.dadaqianduan.cn

相關文章