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. 路由的跳轉
(1) router-link
<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
你可以在元件中使用 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
你在元件中使用 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)
}
}
}