2017.4.17-4.21
前言
本周继续上周的登录界面,使用less与vuex进行完善。
笔记导航
- Vue套件使用
- Vuex状态管理学习(
state
&getters
&mutations
&actions
) - 通过Vuex实现多个组件间的通信
- 使用less编辑页面样式
详细笔记
1. Vue组件嵌套使用
新建父组件,在script段落内引入子组件,并且在父组件中插入已定义的子组件
entry
Vue语法缩写:
@ === v-on 事件绑定监听
: === v-bind 元素绑定
2. 使用Vuex
Vuex的用处:
通过内部变量(store实例中的state)来管理整个系统的状态,提供多种系统的接口(getters、mutations、actions),使Vue组件可以通过store实例的接口获取store实例中的state变量。
Vuex的好处:
使用state: 实现Vue组件中的通信
使用getters与mutations: 不需要在每一个Vue组件中重写相同的处理函数(比如用于获取state中的参数)
使用actions: 把Vue之间的同步调用转变成异步调用,提高响应效率
Vuex学习资源:
Vuex入门视频(共5个)
Vuex视频对应的练习源码
2.1 关于Store & State
Step1: 安装Vuex
npm install --save vuex
Step2: 声明store实例,并引用到application中
// 新建store.js文件
// store.js 配置Vuex实例
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(vuex)
export const store = new Vuex.Store({
state: {
//填充用于管理状态的共享变量
}
})
//在main.js中引入Store实例
// main.js
// 使用{}引入store实例,因为store是一个const变量
import { store } from './store'
new Vue({
router,
store,
// 其他属性 ...
}).$mount('#app')
Step3: 传递Store实例中的state参数中的共享变量
在使用store之前,需要在App.vue中将公共状态传递给子组件(通过props获取)。
相当于子组件中传入的数据只是数据,而非数据地址,不可修改数据本身,因此自身操作不会影响全局,需要抛出事件给父组件。
而使用js操作变量时,子组件需要通过emit-on机制向App.vue发起事件冒泡,由app.vue执行操作并改变内部的data,进而更新子组件中的参数变化。
// App.vue
// 通过绑定:users="unregisteredUsers" 向app-registration模块中传递props值
在使用store之后,不需要再在子组件中通过props获取传入参数,可以直接通过this.$store.state.[变量名称]直接对store实例中的state参数进行有效编辑。
原本在app.vue中进行的操作,可以在子组件中直接执行。
// Registration.vue
Register here
{{ user.name }}
2.2 关于getters与mutations
概念:这一对Vuex实例属性,在一般情况下被理解作getter与setter
或accessor和mutator
getters [new store property]
getters用于简化子组件从store.js中获取公共变量的代码
使用getters优化前:
// 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优化后:
// 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() {
// 以属性的形式调用getters中的方法,不需要传入参数
return this.$store.getters.unregisteredUsers;
}
}
}
使用mapGetters的二度简化
安装mapGetters的编译工具
npm install --save-dev babel-preset-stage-2
配置mapGetters的编译参数
// .babelrc 文件
{
"presets": [
["es2015", { "modules": false }],
["stage-2"] //新增参数
]
}
// 子组件 Registrations.vue
mutations [new store property]
getters用于管理可复用的'获取state参数的操作
';相应地,mutations用于管理可复用的'修改state参数的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定位目标删除元素
const registrationIndex = state.registrations.findIndex(registration => {
return registration.userId == userId;
})
state.registrations.splice(registrationIndex, 1);
// 使用find函数定位目标删除元素
// const registration = state.registrations.find(registration => {
// return registration.userId == userId;
// })
// state.registrations.splice(state.registrations.indexOf(registration), 1);
}
}
})
// mutations在组件中的调用
// Registration.vue
2.3 关于actions
在nodejs中,我们认识到最深刻的一点就是异步调用。但是在Vuex中,mutations属性中包含了大量函数接口,并且具有同步执行的特点。因此在必须在执行完mutations中某个被调用的函数之后,才能继续调用下一个,效率大大降低。
这个问题,就是actions属性所要解决的问题 ==> 异步调用(Async)
// store.js
// 声明actions, 可以在其中的函数中加入异步代码
export const store = new Vuex.Store({
state: { ··· },
getters: { ··· },
mutations: {
register(state, userId) {
······
},
unregister(state, userId) {
······
}
},
actions: {
// actions中的函数名可自定义,此处为了方便练习与mutations中函数同名
// 写法一:
register(context, userId) {
context.commit('register', userId);
},
// 写法二:
unregister( { commit } , userId) {
commit('unregister', userId);
}
}
})
// 在子组件中使用dispatch,调用可异步执行的actions
// Registrations.vue
2.3 关于store.js的合理分装
store.js中包含了getters、mutations以及actions,随着application的功能扩展,函数将会越来越多,因此把这三个属性分装出去,是十分有必要的。
在src目录下新增store文件夹,更新后当前目录如下:
.
├── 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属性中添加一个新的对象
{
test: /\.less$/,
loader: "style-loader!css-loader!less-loader",
}
最后:在Vue组件中使用的时候在style标签里加上lang="less"
less语法
美出天际的登录界面模板
4. Vue组件布局与路由
1. App.vue是整个application的主容器,根据不同的路由放入不同的组件。
即使当前Vue中没有html标签,也同样可以设置html、body标签的属性(width:100%
)。
URL中的#号作用——定位页面元素
2. css样式笔记
提高样式优先级
在样式的后面添加"!important"
width: 40% !important;
input标签与button标签在同一行内顶部对齐: vertical-align: baseline;