1. 程式人生 > 實用技巧 >Vue核心知識點

Vue核心知識點

一、vue.config.js 基本配置

module.exports = {
  // 基本路徑 cli3.3以前版本用baseUrl
  publicPath: '/',
  // 輸出檔案目錄
  outputDir: 'dist',
  // 用於巢狀生成的靜態資源
  assetsDir: '',
  // 生產環境sourMap
  productionSourceMap: false,
  // webpack配置
  configureWebpack: () => {},
  chainWebpack: () => {},
  
  // css相關配置
  css: {
    // 啟動css modules
    modules: false,
    // 是否使用css分離外掛
    extract: true,
    // 開啟 css sourcemaps?
    sourceMap: false,
    // css 前處理器配置項
    loaderOptions: {}
  },
  
  // webpack-dev-server 相關配置
  devServer: {
    host: '0.0.0.0',
    port: 8080,
    proxy: {} // 設定代理
  },
  // 第三方外掛配置
  pluginOptions: {
    // ...
  }
}

二、vue元件間傳值

1. 父子元件傳值

(1) props(父傳子) / $emit(子傳父)

(2) $parent / $children

// App => Father => Child
// Father.vue
mounted () {
  console.log(this.$children[0].val) // 訪問子元件 Child 的某個資料(子傳父)
  console.log(this.$parent.val) // 訪問父元件 App 的某個資料(父傳子)
  console.log(this.$parent.handleClick) // 也可以是某個方法
}

(3) $refs(訪問具體DOM節點)

ref 後面自定義節點名稱,從而實現在 js 中訪問,訪問的方式是 this.$refs.自定義名稱

<!-- Father.vue -->
<child ref="child"></child>
// Father.vue
mounted () {
  console.log(this.$refs.child)
}

2. 非父子元件傳值

(1) 事件匯流排

原理:建立一個公有的 js 檔案,專門來傳遞訊息。

// 在 util 資料夾下新建 bus.js
import Vue from 'vue'
export default new Vue()

// 在需要傳遞訊息或者接收訊息的地方引入
import bus from './bus.js'

// 點選事件中傳遞自定義事件,傳送訊息
bus.$emit('msg', val)

// 監聽事件,接收訊息
bus.$on('msg', val => {
  console.log(val)
})

(2) $attrs / $listeners

爺傳孫:$attrs 將父元件中不包含 props 的屬性傳入子元件,通常配合 inheritAttrs 選項一起使用。

// 祖孫元件傳值 App => Father => Child
// App.vue 繫結屬性將祖輩元件中 msg、title 傳遞給父元件
<father :msg="msg" :title="title"></father>
// Father.vue 在父元件上繫結 v-bind="$attrs" 
<child v-bind="$attrs"></child>
// Child.vue 孫子元件獲取到祖父元件的資料
mounted () {
  console.log(this.$attrs)
}

$listeners 監聽子元件中資料變化,傳遞給父元件。(略)

(3) vuex

見第四章、第五章


三、Vue Router

1. 路由的基本配置

(1) router 配置(路由懶載入)

// index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    {
      path: '/home',
      name: 'home',
      component: () => import('../components/Home.vue') // 懶載入:動態匯入,按需載入
    }
  ]
})

export default router

(2) 路由檢視

App.vue,在合適的位置加上以下程式碼:

<router-view></router-view>

2. 路由的跳轉

<router-link to="/home">跳轉</router-link>
<router-view></router-view>

(2) 程式設計式導航 this.$router.push( { ... } )

<button @click="handleGo">js 跳轉</button>
<router-view></router-view>
methods: {
  handleGo () {
    this.$router.push({
      path: 'home'
    })
  },
  // handleGo () {
  //  this.$router.push({
  //    name: 'home'
  //  })
  // }
}

3. 動態路由

(1) 基本配置

// router 目錄下的 index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    {
      path: '/home/:id', // 動態路由,id 是自定義的引數名
      name: 'home',
      component: () => import('../components/Home.vue')
    }
  ]
})

export default router

通過 $route.params.動態引數名 可以訪問到動態引數:

<!-- Home.vue -->
<template>
  <div>
    <h2>Home 頁</h2>
    <p>路由動態引數:{{$route.params.id}}</p>
  </div>
</template>

(2) 程式設計式導航的傳參

傳參有兩種形式,

  • 一種是查詢欄位的傳參。(path + query)
// App.vue (path + query)
methods: {
  handleGo () {
    this.$router.push({
    	path: 'home',
    	query: {
        name: 'jack',
        gender: 'male',
        age: 18
      }
		})
  }
}

點選跳轉按鈕後,資料被傳遞到了 url 中:

  • 一種是動態路由引數的傳參。(name + params)
// App.vue (name + params)
methods: {
  handleGo () {
    this.$router.push({
      name: 'home',
      params: {
        id: 123
      }
    })
  }
}

4. 巢狀路由

在 Home 頁的一個區域顯示一個路由頁面,這個新的路由頁面屬於 home 路由,因此就要將它寫在home路由規則下。

Home.vue
	|- Child.vue

(1) 路由規則配置

在 home 路由下新增 children 選項,配置新的路由規則。

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

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    {
      path: '/home/:id',
      name: 'home',
      component: () => import('../components/Home.vue'),
      children: [ // 新路由 Child.vue 寫在 children 選項下
        {
          path: '/child',
          component: () => import('../components/Child.vue')
        }
      ]
    }
  ]
})

export default router

(2) 路由檢視

router-view 也理應寫在 Home.vue 下。

<!-- Home.vue -->
<template>
  <div>
    <h2>Home 頁</h2>
    <p>路由動態引數:{{$route.params.id}}</p>
    
    <!-- Child.vue 的檢視將會在此處展示 -->
    <router-view></router-view>
    
  </div>
</template>

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

<style lang='stylus' scoped>

</style>

5. 導航守衛

在 main.js 中加入以下程式碼:

// main.js
router.beforeEach((to, from, next) => {
  console.log('從這出發:', from.path)
  console.log('到達此處:', to.path)
  next()
})

在 '/' 處點選按鈕後,跳轉到 '/home/123'


四、Vuex 基礎用法

公共資料倉庫。

  • State
    • 資料
  • Mutations
    • 資料怎麼變(同步)
  • Actions
    • 非同步改變

1. store 倉庫建立

// store 目錄下的 index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  // 公共資料
  state: {
    count: 0
  },
  
  // 資料怎麼變(同步):每個方法下都有一個引數 state 可以訪問到公共資料
  mutations: {
    add (state) {
      state.count++
    },
    decrese (state) {
      state.count--
    }
  },
  
  // 非同步修改資料:方法下有一個形參 context,通過 context.commit('變更方法名') 來提交變更方法,告訴它資料怎麼變
  actions: {
    // 模擬非同步操作
    delayAdd (context) {
      // 一秒後,呼叫 add 方法
      setTimeout(() => {
        context.commit('add')
      }, 1000)
    }
  }
})

2. 在檢視中使用公共資料

(1) 常規方式

在需要用到公共資料的地方,通過計算屬性引進 store 倉庫中資料。

通過 this.$store.state.資料名 可以獲取到公共資料。

// vue 例項
computed: {
  count () {
    return this.$store.state.count
  }
},
<template>
  <div>
    <p>公共資料來了!它是:===> <span style="color:red">{{count}}</span></p>
  </div>
</template>

(2) 輔助函式:mapState

https://vuex.vuejs.org/zh/guide/state.html#mapstate-%E8%BE%85%E5%8A%A9%E5%87%BD%E6%95%B0

當一個元件需要獲取多個狀態的時候,將這些狀態都宣告為計算屬性會有些重複和冗餘。為了解決這個問題,我們可以使用 mapState 輔助函式幫助我們生成計算屬性,讓你少按幾次鍵。(注意,放在計算屬性中!)

import { mapState } from 'vuex' // 首先匯入輔助函式 mapState

export default {
  computed: {
    ...mapState({ // 通過展開運算子將物件展開
      // 傳字串引數 'count' 等同於 `state => state.count`
      count: 'count'
      
      // 箭頭函式可使程式碼更簡練
    	// count: state => state.count
    })
  }
}

關於展開運算子:https://blog.csdn.net/adsadadaddadasda/article/details/79391881

3. 觸發 Mutations 修改資料(同步)

(1) 修改資料 this.$store.commit('xxx')

<!-- html -->
<p>公共資料來了!它是:===> <span style="color:red">{{count}}</span></p>
<button @click="handleAdd">改變公共資料 (add)</button>
// vue 例項
// vue 元件 => commit('變更方法名') => Mutations => state => vue 元件
methods: {
  handleAdd () {
    this.$store.commit('add') // 此時觸發的就是 store 倉庫中 Mutations 下的 add 方法
  }
}
// store 中的變更方法名
mutations: {
  add (state) {
    state.count++
  },
  decrese (state) {
    state.count--
  }
}

(2) 輔助函式:mapMutation

https://vuex.vuejs.org/zh/guide/mutations.html#%E5%9C%A8%E7%BB%84%E4%BB%B6%E4%B8%AD%E6%8F%90%E4%BA%A4-mutation

你可以在元件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 輔助函式將元件中的 methods 對映為 store.commit 呼叫(需要在根節點注入 store)。(注意,放在 methods 中!)

import { mapMutations } from 'vuex' // 首先匯入輔助函式 mapMutations

export default {
  methods: {
    ...mapMutations({
      handleAdd: 'add' // // 將 this.handleAdd() 對映為 this.$store.commit('add')
    })
  }
}

4. 觸發 Actions 修改資料(一般為非同步)

(1) 修改資料 this.$store.dispatch('xxx')

<!-- html -->
<p>公共資料來了!它是:===> <span style="color:red">{{count}}</span></p>
<button @click="handleAdd">改變公共資料 (add)</button>
// vue 例項
// vue 元件 => dispatch('非同步方法名') => Actions => commit('變更方法名') => Mutations => vue 元件
methods: {
  handleAdd () {
    this.$store.dispatch('delayAdd')
  }
}
// store 中的 actions 非同步方法名
actions: {
  delayAdd (context) {
    // 一秒後,呼叫 Mutations 中的 add 方法
    setTimeout(() => {
      context.commit('add')
    }, 1000)
  }
}

(2) 輔助函式:mapActions

https://vuex.vuejs.org/zh/guide/actions.html#%E5%9C%A8%E7%BB%84%E4%BB%B6%E4%B8%AD%E5%88%86%E5%8F%91-action

你在元件中使用 this.$store.dispatch('xxx') 分發 action,或者使用 mapActions 輔助函式將元件的 methods 對映為 store.dispatch 呼叫(需要先在根節點注入 store(注意,放在 methods 中!)

import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions({
      handleAdd: 'delayAdd' // // 將 this.handleAdd() 對映為 this.$store.dispatch('delayAdd')
    })
  }
}

五、Vuex 高階用法

1. Vuex 中的計算屬性:Getters

getters 中的資料依賴於 state 中的資料。

// store
state: {
  count: 0
},
getters: {
  doubleCount (state) {
    return state.count * 2
  }
}

(1) 常規方式

<!-- html -->
<p>公共資料來了!它是:===> <span style="color:red">state: {{count}}</span></p>
<p>公共資料來了!它是:===> <span style="color:green">getters: {{doubleCount}}</span></p>
<button @click="handleAdd">改變公共資料 (add)</button>
// vue 例項
computed: {
	// ...
  doubleCount () {
    return this.$store.getters.doubleCount
  }
}

當點選按鈕時,state.count++,因為 doubleCount 依賴於 state.count,因此會同時發生計算。

(2) 輔助函式:mapGetters

https://vuex.vuejs.org/zh/guide/getters.html#mapgetters-%E8%BE%85%E5%8A%A9%E5%87%BD%E6%95%B0

mapGetters 輔助函式僅僅是將 store 中的 getter 對映到區域性計算屬性

import { mapGetters } from 'vuex'

export default {
  computed: {
    // ...mapGetters(['doubleCount']) // 引數名和方法名一致
    
    ...mapGetters({
      doubleCount: 'doubleCount'
    })
  }
}

2. 模組化:Modules

各個模組各司其職,管理自己的資料。

由於使用單一狀態樹,應用的所有狀態會集中到一個比較大的物件。當應用變得非常複雜時,store 物件就有可能變得相當臃腫。

為了解決以上問題,Vuex 允許我們將 store 分割成模組(module)。每個模組擁有自己的 state、mutation、action、getter、甚至是巢狀子模組——從上至下進行同樣方式的分割。

https://vuex.vuejs.org/zh/guide/modules.html#module

(1) 模組分離

  • 在 store 資料夾下新建一個 js 檔案(模組),將這個模組起名為 handleCount。
// handleCount.js
// handleCount模組
export default {
  state: {
    count: 0
  },
  getters: {
    doubleCount (state) {
      return state.count * 2
    }
  },
  mutations: {
    add (state) {
      state.count++
    },
    decrese (state) {
      state.count--
    }
  },
  actions: {
    delayAdd (context) {
      // 一秒後,呼叫 add 方法
      setTimeout(() => {
        context.commit('add')
      }, 1000)
    }
  }
}
  • 引入 index.js 主模組中
import Vue from 'vue'
import Vuex from 'vuex'
import handleCount from './handleCount' // 引入模組 handleCount

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    handleCount
  }
})

因為使用了模組,所以原來的 state 指向都會發生變化。

例如訪問 count 資料,不再是 this.$store.state.count,而是 this.$store.state.handleCount.count。(this.$store.state.模組名.資料名)

  • 使用箭頭函式
// vue 例項中的 computed 選項
...mapState({
  count: state => state.handleCount.count
})

(2) 名稱空間

如果希望你的模組具有更高的封裝度和複用性,你可以通過新增 namespaced: true 的方式使其成為帶名稱空間的模組。當模組被註冊後,它的所有 getter、action 及 mutation 都會自動根據模組註冊的路徑調整命名。

https://vuex.vuejs.org/zh/guide/modules.html#%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4

// handleCount 模組
export default {
  namespaced: true, // 新增名稱空間欄位,其他照舊
  // ...
}

當添加了名稱空間選項時,所有的輔助函式的對映效果就會發生錯誤,這時要手動調整過來:

// 原始碼:
// computed
...mapGetters({
  doubleCount: 'doubleCount'
})
// methods
...mapActions({
  handleAdd: 'delayAdd'
})

// <=============================================================================================>

// 調整後:
// computed
...mapGetters({
  doubleCount: 'handleCount/doubleCount'
})
// methods
...mapActions({
  handleAdd: 'handleCount/delayAdd'
})

關於名稱空間:https://blog.csdn.net/lzb348110175/article/details/89387495


六、Element UI

1. 安裝依賴

cnpm i element-ui --save

--save 表示依賴包被安裝到了生產環境中。(簡寫 -S)

 i  是 install 的簡寫
-S 就是 --save 的簡寫
-D 就是 --save-dev 的簡寫

npm i module_name -S = > npm install module_name --save 寫入到 dependencies 物件

npm i module_name -D => npm install module_name --save-dev 寫入到 devDependencies 物件

npm i module_name -g 全域性安裝

關於指令:https://www.cnblogs.com/del88/p/13272767.html

2. 引入 Element

// main.js
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import App from './App.vue'

Vue.use(ElementUI)

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

3. 佈局元件使用

<h3>div塊 4等分佈局</h3>
<el-row :gutter="20">
  <el-col :span='6'><div class="content">1</div></el-col>
  <el-col :span='6'><div class="content">2</div></el-col>
  <el-col :span='6'><div class="content">3</div></el-col>
  <el-col :span='6'><div class="content">4</div></el-col>
</el-row>

<h3>整塊頁面佈局</h3>
<el-container>
	<el-header>Header</el-header>
	<el-main>Main</el-main>
	<el-footer>Footer</el-footer>
</el-container>

gutter 表示間隔,span 表示佔用份數。(一行共 24 份)

el-header el-aside el-main el-footer 的父容器只能是 el-container,el-container 的子容器也只能是前四者。


七、彈出型別元件

1. Dialog 對話方塊

https://element.eleme.cn/2.0/#/zh-CN/component/dialog#dialog-dui-hua-kuang

<template>
  <div>
    <el-button type="text" @click="dialogVisible = true">點選開啟 Dialog</el-button>

    <el-dialog title="提示" :visible.sync="dialogVisible" width="30%" :before-close="handleClose">
      <span>這是一段資訊</span>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="dialogVisible = false">確 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'pop',
  data () {
    return {
      dialogVisible: false
    }
  },
  methods: {
    handleClose (done) {
      this.$confirm('確認關閉?')
        .then(_ => {
          done()
        })
        .catch(_ => {})
    }
  }
}
</script>

<style lang='stylus' scoped></style>

2. Popover 彈出框

https://element.eleme.cn/2.0/#/zh-CN/component/popover#popover-dan-chu-kuang

<el-popover
  ref="popover1"
  placement="top-start"
  title="標題"
  width="200"
  trigger="hover"
  content="這是一段內容,這是一段內容,這是一段內容,這是一段內容。">
</el-popover>
<el-button v-popover:popover1>hover 啟用</el-button>

八、表格元件

1. 基礎表格

<el-table
	:data="tableData"
	style="width: 100%"
	height="500"
	border
>
  <el-table-column
		prop="date"
		label="日期"
     width="180">
  </el-table-column>
  <el-table-column
		prop="name"
		label="姓名"
		width="180">
  </el-table-column>
  <el-table-column
		prop="address"
		label="地址">
  </el-table-column>

  <el-table-column label="操作">
    <template slot-scope="scope">
      <el-button
				size="mini"
         @click="handleEdit(scope.$index, scope.row)">編輯</el-button>
      <el-button
				size="mini"
         type="danger"
         @click="handleDelete(scope.$index, scope.row)">刪除</el-button>
    </template>
  </el-table-column>
</el-table>
export default {
  name: 'tableList',
  data () {
    return {
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀區金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀區金沙江路 1517 弄'
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀區金沙江路 1519 弄'
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀區金沙江路 1516 弄'
      }]
    }
  },
  methods: {
    handleEdit (index, row) {
      console.log(index, row)
    },
    handleDelete (index, row) {
      console.log(index, row)
    }
  }
}

2. el-table 表格常用屬性

屬性名 作用
height 給表格設定高度,同時固定表頭。
show-header 設定是否顯示錶頭。
row-class-name 設定一個函式或者固定的名字作為行的類名。
border 是否顯示錶格豎直方向的邊框,設定後可通過改變邊框來設定列寬。

3. el-column 列常用屬性

屬性名 作用
label 當前列的表頭名稱
prop 傳入的表格 json 資料的 key 值
show-overflow-tooltip 是否設定文字超出列寬時懸浮顯示完整內容

4. 通過 v-for 封裝更好的表格

<el-table :data='tableData'>
  <el-table-column v-for="(val, key) of tableLabel" :key='key' :prop='key' :label='val'></el-table-column>
  
  <el-table-column label="操作">
    <template slot-scope="scope">
      <el-button
				size="mini"
         @click="handleEdit(scope.$index, scope.row)">編輯</el-button>
      <el-button
         size="mini"
         type="danger"
         @click="handleDelete(scope.$index, scope.row)">刪除</el-button>
    </template>
  </el-table-column>
</el-table>
export default {
  name: 'tableList',
  data () {
    return {
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀區金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀區金沙江路 1517 弄'
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀區金沙江路 1519 弄'
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀區金沙江路 1516 弄'
      }],
      tableLabel: {
        date: '日期',
        name: '姓名',
        address: '地址'
      }
    }
  },
  methods: {
    handleEdit (index, row) {
      console.log(index, row)
    },
    handleDelete (index, row) {
      console.log(index, row)
    }
  }
}