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

2017.4.17-4.21

前言

本周继续上周的登录界面,使用less与vuex进行完善。

笔记导航

  • Vue套件使用
  • Vuex状态管理学习( state & getters & mutations & actions
  • 通过Vuex实现多个组件间的通信
  • 使用less编辑页面样式

详细笔记

1. Vue组件嵌套使用

新建父组件,在script段落内引入子组件,并且在父组件中插入已定义的子组件








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视频对应的练习源码

Vuex实现组件通信-Vue学习笔记(2).md_第1张图片
上面推荐的入门视频中对于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



在使用store之后,不需要再在子组件中通过props获取传入参数,可以直接通过this.$store.state.[变量名称]直接对store实例中的state参数进行有效编辑。
原本在app.vue中进行的操作,可以在子组件中直接执行。

// Registration.vue



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


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;

你可能感兴趣的:(Vuex实现组件通信-Vue学习笔记(2).md)