2017.4.17-4.21
前言
本周繼續(xù)上周的登錄界面,使用less與vuex進(jìn)行完善。
筆記導(dǎo)航
- Vue套件使用
- Vuex狀態(tài)管理學(xué)習(xí)(
state
&getters
&mutations
&actions
) - 通過Vuex實(shí)現(xiàn)多個(gè)組件間的通信
- 使用less編輯頁面樣式
詳細(xì)筆記
1. Vue組件嵌套使用
新建父組件,在script段落內(nèi)引入子組件,并且在父組件中插入已定義的子組件
<!-- 組件嵌套實(shí)例 -->
<!-- 父組件Entry.Vue -->
<!-- 子組件Login.Vue & Register.Vue -->
<template>
<div class="entry-box">
<h1>entry</h1>
<login></login>
<register></register>
</div>
</template>
<script>
// 聲明引入子組件變量
import login from './Login'
import register from './Register'
export default {
name: 'entry',
// ******* 在components參數(shù)中賦值,添加引入的子組件 *******
components: {
login,
register
}
// ******* 在components參數(shù)中賦值,添加引入的子組件 *******
}
</script>
Vue語法縮寫:
@ === v-on 事件綁定監(jiān)聽
<!-- 完整語法 -->
<a v-on:click="doSomething"></a>
<!-- 縮寫 -->
<a @click="doSomething"></a>
: === v-bind 元素綁定
<!-- 完整語法 -->
<a v-bind:href="url"></a>
<!-- 縮寫 -->
<a :href="url"></a>
2. 使用Vuex
Vuex的用處:
通過內(nèi)部變量(store實(shí)例中的state)來管理整個(gè)系統(tǒng)的狀態(tài),提供多種系統(tǒng)的接口(getters、mutations、actions),使Vue組件可以通過store實(shí)例的接口獲取store實(shí)例中的state變量。
Vuex的好處:
使用state: 實(shí)現(xiàn)Vue組件中的通信
使用getters與mutations: 不需要在每一個(gè)Vue組件中重寫相同的處理函數(shù)(比如用于獲取state中的參數(shù))
使用actions: 把Vue之間的同步調(diào)用轉(zhuǎn)變成異步調(diào)用,提高響應(yīng)效率
Vuex學(xué)習(xí)資源:
Vuex入門視頻(共5個(gè))
Vuex視頻對應(yīng)的練習(xí)源碼
2.1 關(guān)于Store & State
Step1: 安裝Vuex
npm install --save vuex
Step2: 聲明store實(shí)例,并引用到application中
// 新建store.js文件
// store.js 配置Vuex實(shí)例
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(vuex)
export const store = new Vuex.Store({
state: {
//填充用于管理狀態(tài)的共享變量
}
})
//在main.js中引入Store實(shí)例
// main.js
// 使用{}引入store實(shí)例,因?yàn)閟tore是一個(gè)const變量
import { store } from './store'
new Vue({
router,
store,
// 其他屬性 ...
}).$mount('#app')
Step3: 傳遞Store實(shí)例中的state參數(shù)中的共享變量
在使用store之前,需要在App.vue中將公共狀態(tài)傳遞給子組件(通過props獲取)。
相當(dāng)于子組件中傳入的數(shù)據(jù)只是數(shù)據(jù),而非數(shù)據(jù)地址,不可修改數(shù)據(jù)本身,因此自身操作不會影響全局,需要拋出事件給父組件。
而使用js操作變量時(shí),子組件需要通過emit-on機(jī)制向App.vue發(fā)起事件冒泡,由app.vue執(zhí)行操作并改變內(nèi)部的data,進(jìn)而更新子組件中的參數(shù)變化。
// App.vue
<template>
<div id="app">
// 通過綁定:users="unregisteredUsers" 向app-registration模塊中傳遞props值
<app-registration @userRegistered="userRegistered" :users="unregisteredUsers"></app-registration>
<app-registrations @userUnregistered="userUnregistered" :registrations="registrations"></app-registrations>
</div>
</template>
<script>
import Registration from './components/Registration.vue';
import Registrations from './components/Registrations.vue';
export default {
data() { // data中存儲被傳到兩個(gè)組件中的變量
return {
registrations: [],
users: [
{id: 1, name: 'Max', registered: false},
{id: 2, name: 'Anna', registered: false},
{id: 3, name: 'Chris', registered: false},
{id: 4, name: 'Sven', registered: false}
]
}
}
computed: {
unregisteredUsers() {
return this.users.filter((user) => {
return !user.registered;
});
}
},
// 聲明引用的子組件
components: {
appRegistration: Registration,
appRegistrations: Registrations
}
}
</script>
在使用store之后,不需要再在子組件中通過props獲取傳入?yún)?shù),可以直接通過this.$store.state.[變量名稱]直接對store實(shí)例中的state參數(shù)進(jìn)行有效編輯。
原本在app.vue中進(jìn)行的操作,可以在子組件中直接執(zhí)行。
// Registration.vue
<template>
<div id="registration">
<h3>Register here</h3>
<hr>
<div class="row" v-for="user in users">
<h4>{{ user.name }}</h4>
<button @click="registerUser(user)">Register</button>
</div>
</div>
</template>
<script>
export default {
computed: {
// 通過user() 獲取store中的公共共享參數(shù)
users() {
return this.$store.state.users.filter(user => {
return !user.registered; // filter:條件過濾,只返回user.registered===false的元素
})
}
},
methods: {
registerUser(user) {
user.registered = true;
const date = new Date;
this.$store.state.registrations.push({userId: user.id, name: user.name, date: date.getMonth() + '/' + date.getDay()})
}
}
}
</script>
2.2 關(guān)于getters與mutations
概念:這一對Vuex實(shí)例屬性,在一般情況下被理解作getter與setter
或accessor和mutator
getters [new store property]
getters用于簡化子組件從store.js中獲取公共變量的代碼
使用getters優(yōu)化前:
// store.js
export const store = new Vuex.Store({
state: {
registrations: [],
users: [
{id: 1, name: 'Max', registered: false},
{id: 2, name: 'Anna', registered: false},
{id: 3, name: 'Chris', registered: false},
{id: 4, name: 'Sven', registered: false}
]
}
})
// 子組件 Registration.vue
export default {
computed: {
users() {
return this.$store.state.users.filter(user => {
return !user.registered;
})
}
}
}
使用getters優(yōu)化后:
// store.js
export const store = new Vuex.Store({
state: {
registrations: [],
users: [
{id: 1, name: 'Max', registered: false},
{id: 2, name: 'Anna', registered: false},
{id: 3, name: 'Chris', registered: false},
{id: 4, name: 'Sven', registered: false}
]
},
getters: {
unregisteredUsers(state) {
return state.users.filter(user => {
return !user.registered;
})
},
registerUser(state) {
return state.registrations;
}
totalRegistration(state) {
return state.registrations.length;
}
}
})
// 子組件 Registration.vue
export default {
computed: {
users() {
// 以屬性的形式調(diào)用getters中的方法,不需要傳入?yún)?shù)
return this.$store.getters.unregisteredUsers;
}
}
}
使用mapGetters的二度簡化
安裝mapGetters的編譯工具
npm install --save-dev babel-preset-stage-2
配置mapGetters的編譯參數(shù)
// .babelrc 文件
{
"presets": [
["es2015", { "modules": false }],
["stage-2"] //新增參數(shù)
]
}
// 子組件 Registrations.vue
<script>
// 引入mapGetters
import { mapGetters } from 'vuex'
export default {
computed: mapGetters({
// getters映射的語法規(guī)則:
// 'customized name' : 'name of getters'
registrations: 'registeredUser',
total: 'totalRegistrations'
}),
methods: {
unregister(registration) {
const user = this.$store.state.users.find(user => {
return user.id == registration.userId;
});
user.registered = false;
this.$store.state.registrations.splice(this.$store.state.registrations.indexOf(registration), 1);
}
}
}
</script>
mutations [new store property]
getters用于管理可復(fù)用的'獲取state參數(shù)的操作
';相應(yīng)地,mutations用于管理可復(fù)用的'修改state參數(shù)的js操作
'。
// mutations 的定義與聲明
// store.js
export const store = new Vuex.Store({
state: { ··· },
getters: { ··· },
mutations: {
register(state, userId) {
const user = state.users.find(user => {
return user.id == userId;
});
user.registered = true;
const date = new Date;
const registration = {
userId: userId,
name: user.name,
date: date.getMonth() + '/' + date.getDay()
}
state.registrations.push(registration);
},
unregister(state, userId) {
const user = state.users.find(user => {
return user.id == userId;
});
user.registered = false;
// 使用findIndex定位目標(biāo)刪除元素
const registrationIndex = state.registrations.findIndex(registration => {
return registration.userId == userId;
})
state.registrations.splice(registrationIndex, 1);
// 使用find函數(shù)定位目標(biāo)刪除元素
// const registration = state.registrations.find(registration => {
// return registration.userId == userId;
// })
// state.registrations.splice(state.registrations.indexOf(registration), 1);
}
}
})
// mutations在組件中的調(diào)用
// Registration.vue
<script>
export default {
computed: {
users() {
return this.$store.getters.unregisteredUsers;
}
},
methods: {
registerUser(user) {
// 與getters不同,在子組件中使用commit調(diào)用mutations中的函數(shù)
this.$store.commit('register', user.id);
}
}
}
</script>
2.3 關(guān)于actions
在nodejs中,我們認(rèn)識到最深刻的一點(diǎn)就是異步調(diào)用。但是在Vuex中,mutations屬性中包含了大量函數(shù)接口,并且具有同步執(zhí)行的特點(diǎn)。因此在必須在執(zhí)行完mutations中某個(gè)被調(diào)用的函數(shù)之后,才能繼續(xù)調(diào)用下一個(gè),效率大大降低。
這個(gè)問題,就是actions屬性所要解決的問題 ==> 異步調(diào)用(Async)
// store.js
// 聲明actions, 可以在其中的函數(shù)中加入異步代碼
export const store = new Vuex.Store({
state: { ··· },
getters: { ··· },
mutations: {
register(state, userId) {
······
},
unregister(state, userId) {
······
}
},
actions: {
// actions中的函數(shù)名可自定義,此處為了方便練習(xí)與mutations中函數(shù)同名
// 寫法一:
register(context, userId) {
context.commit('register', userId);
},
// 寫法二:
unregister( { commit } , userId) {
commit('unregister', userId);
}
}
})
// 在子組件中使用dispatch,調(diào)用可異步執(zhí)行的actions
// Registrations.vue
<script>
import { mapGetters } from 'vuex'
export default {
computed: mapGetters({
registrations: 'registeredUser',
total: 'totalRegistrations'
}),
methods: {
unregister(registration) {
// 調(diào)用不可異步的mutations的寫法,傳入的第一個(gè)參數(shù)是actions中的函數(shù)名
// this.$store.commit('unregister', registration.userId);
// 調(diào)用可異步的actions的寫法
this.$store.dispatch('unregister', registration.userId);
}
}
}
</script>
2.3 關(guān)于store.js的合理分裝
store.js中包含了getters、mutations以及actions,隨著application的功能擴(kuò)展,函數(shù)將會越來越多,因此把這三個(gè)屬性分裝出去,是十分有必要的。
在src目錄下新增store文件夾,更新后當(dāng)前目錄如下:
.
├── build/
├── config/
├── node_modules
├── src/
│ ├── main.js
│ ├── App.vue
│ ├── store/
│ │ ├── store.js
│ │ ├── getters.js
│ │ ├── mutations.js
│ │ └── actions.js
│ ├── components/
│ │ └── ...
│ └── assets/
│ └── ...
├── .babelrc
├── .postcssrc.js
├── .eslintrc.js
├── .editorconfig
├── index.html
└── package.json
分裝方法如下:
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import mutations from './mutations'
import actions from './actions'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
registrations: [],
users: [
{id: 1, name: 'Max', registered: false},
{id: 2, name: 'Anna', registered: false},
{id: 3, name: 'Chris', registered: false},
{id: 4, name: 'Sven', registered: false}
]
},
getters,
mutations,
actions
})
// getters.js
export default {
unregisteredUsers(state) {
return state.users.filter(user => {
return !user.registered;
})
},
registeredUser(state) {
return state.registrations;
},
totalRegistrations(state) {
return state.registrations.length;
}
}
// mutations.js 與 actions.js同getters的做法
3.使用less修改Vue界面
首先:安裝less依賴:
npm install less less-loader --save
然后:修改webpack.base.conf.js文件,配置loader加載依賴,讓其支持外部的less。
在modules.rules屬性中添加一個(gè)新的對象
{
test: /\.less$/,
loader: "style-loader!css-loader!less-loader",
}
最后:在Vue組件中使用的時(shí)候在style標(biāo)簽里加上lang="less"
less語法
4. Vue組件布局與路由
1. App.vue是整個(gè)application的主容器,根據(jù)不同的路由放入不同的組件。
即使當(dāng)前Vue中沒有html標(biāo)簽,也同樣可以設(shè)置html、body標(biāo)簽的屬性(width:100%
)。
2. css樣式筆記
提高樣式優(yōu)先級
在樣式的后面添加"!important"
width: 40% !important;
input標(biāo)簽與button標(biāo)簽在同一行內(nèi)頂部對齊: vertical-align: baseline;