手记

Vuex实现组件通信-Vue学习笔记(2).md

前言

本周继续上周的登录界面,使用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与setteraccessor和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%)。

URL中的#号作用——定位页面元素

2. css样式笔记

提高样式优先级
在样式的后面添加"!important"

width: 40% !important;

input标签与button标签在同一行内顶部对齐: vertical-align: baseline;



作者:daisimin7
链接:https://www.jianshu.com/p/82fb84be938b


0人推荐
随时随地看视频
慕课网APP