前言
本周继续上周的登录界面,使用less与vuex进行完善。
笔记导航
Vue套件使用
Vuex状态管理学习(
state
&getters
&mutations
&actions
)通过Vuex实现多个组件间的通信
使用less编辑页面样式
详细笔记
1. Vue组件嵌套使用
新建父组件,在script段落内引入子组件,并且在父组件中插入已定义的子组件
<!-- 组件嵌套实例 --> <!-- 父组件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参数中赋值,添加引入的子组件 ******* components: { login, register } // ******* 在components参数中赋值,添加引入的子组件 ******* } </script>
Vue语法缩写:
@ === v-on 事件绑定监听
<!-- 完整语法 --> <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的用处:
通过内部变量(store实例中的state)来管理整个系统的状态,提供多种系统的接口(getters、mutations、actions),使Vue组件可以通过store实例的接口获取store实例中的state变量。
Vuex的好处:
使用state: 实现Vue组件中的通信
使用getters与mutations: 不需要在每一个Vue组件中重写相同的处理函数(比如用于获取state中的参数)
使用actions: 把Vue之间的同步调用转变成异步调用,提高响应效率
Vuex学习资源:
Vuex入门视频(共5个)
Vuex视频对应的练习源码
上面推荐的入门视频中对于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 <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中存储被传到两个组件中的变量 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获取传入参数,可以直接通过this.$store.state.[变量名称]直接对store实例中的state参数进行有效编辑。
原本在app.vue中进行的操作,可以在子组件中直接执行。
// 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中的公共共享参数 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 关于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 <script> // 引入mapGetters import { mapGetters } from 'vuex' export default { computed: mapGetters({ // getters映射的语法规则: // '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用于管理可复用的'获取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 <script> export default { computed: { users() { return this.$store.getters.unregisteredUsers; } }, methods: { registerUser(user) { // 与getters不同,在子组件中使用commit调用mutations中的函数 this.$store.commit('register', user.id); } } } </script>
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 <script> import { mapGetters } from 'vuex' export default { computed: mapGetters({ registrations: 'registeredUser', total: 'totalRegistrations' }), methods: { unregister(registration) { // 调用不可异步的mutations的写法,传入的第一个参数是actions中的函数名 // this.$store.commit('unregister', registration.userId); // 调用可异步的actions的写法 this.$store.dispatch('unregister', registration.userId); } } } </script>
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%
)。
2. css样式笔记
提高样式优先级
在样式的后面添加"!important"
width: 40% !important;
input标签与button标签在同一行内顶部对齐: vertical-align: baseline;
作者:daisimin7
链接:https://www.jianshu.com/p/82fb84be938b