三、vuex状态管理 ---kkb

render函数

一些场景中需要 JavaScript 的完全编程能力,这时可以用渲染函数,它比模板更接近编译器

render(h) {

  return h(tag, {...}, [children])

}

createElement 函数

{
  // 与 `v-bind:class` 的 API 相同, 
  // 接受⼀一个字符串串、对象或字符串串和对象组成的数组  
  'class': {
    foo: true,
    bar: false
  },
  // 与 `v-bind:style` 的 API 相同, 
  // 接受⼀一个字符串串、对象,或对象组成的数组 
  style: {
    color: 'red',
    fontSize: '14px'
  },
  // 普通的 HTML 特性 
  attrs: {
    id: 'foo'
  },
  // 组件 prop  
  props: {
    myProp: 'bar'
  },
  // DOM 属性 
  domProps: {
    innerHTML: 'baz'
  },
  // 事件监听器器在 `on` 属性内, 
  // 但不不再⽀支持如 `v-on:keyup.enter` 这样的修饰器器。 
  // 需要在处理理函数中⼿手动检查 keyCode。 
  on: {
    click: this.clickHandler
  }
}

插件

// 插件定义 
MyPlugin.install = function (Vue, options) {
  // 1. 添加全局⽅方法或属性  
  Vue.myGlobalMethod = function () {
    // 逻辑...  
  }
  // 2. 添加全局资源  
  Vue.directive('my-directive', {
    bind(el, binding, vnode, oldVnode) {
      // 逻辑...    
    }
    // ...  
  })
  // 3. 注⼊入组件选项
  Vue.mixin({
    created: function () {
      // 逻辑...    
    }
    //...  
  })
  // 4. 添加实例例⽅方法 
  Vue.prototype.$myMethod = function (methodOptions) {
    // 逻辑...  
  }
}
// 插件使⽤用 
Vue.use(MyPlugin)

例如:移动 $bus 到插件

//   plugins/bus.js
class Bus {
  constructor(){}
  emit(){}
  on(){}
}

Bus.install = function(Vue){
  Vue.prototype.$bus = new Bus()
}

export default Bus
// main.js import Bus from './plugins/bus.js' Vue.use(Bus)

组件混入:mixin

混入(mixin)提供了一种分发Vue组件中可复用功能的灵活方式

// 定义⼀一个混⼊入对象 
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}
// 定义⼀一个使⽤用混⼊入对象的组件
var Component = Vue.extend({
  mixins: [myMixin]
})

例如:移动dispatch 和 broadcast到mixins

//   mixins/emmiter.js
// mixin 其实是一个对象
export default {
  methods: {
    dispatch(eventName, data) {
      let parent = this.$parent
      // 查找父元素
      while (parent) {
        // 父元素用$emit触发
        parent.$emit(eventName, data)
        // 递归查找父元素
        parent = parent.$parent
      }
    },
    boardcast(eventName, data) {
      boardcast.call(this, eventName, data)
    }
  }
}

function boardcast(eventName, data) {
  this.$children.forEach(child => {
    // 子元素触发$emit
    child.$emit(eventName, data)
    if (child.$children.length) {
      // 递归调用,通过call修改this指向child
      boardcast.call(child, eventName, data)
    }
  })
}

上面的混入(mixin),哪个组件想用的话,加入下面的代码就行了

import emmiter from '@/mixin/emmiter.js'

// mixins 与 data、props、methods同级
mixins: [emmiter]

Vuex数据管理

Vuex是一个专为Vue.js应用开发的状态管理模式,集中式存储管理应用所有组件的状态。

Vuex遵循“单向数据流” 理念,易于问题追踪以及提高代码可维护性。

Vue中多个视图依赖于同一状态时,视图间传参和状态同步比较困难,Vuex能够很好解决该问题。

安装:

vue add vuex

核心概念

  • state 状态、数据
  • mutations 更改状态的函数
  • actions 异步操作
  • sotre 包含以上概念的容器

状态和状态变更

state 保存数据状态,mutations 用于修改状态

// store.js
export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state, n=1) {
      state.count += n
    }
  }
})

使用状态

// test.vue
<template>
  <div class="home">
    <h3>vuex test</h3>
    <p>count: {{$store.state.count}}</p>
    <button @click="addHandler">add</button>
  </div>
</template>

export default {
  methods: {
    addHandler(){
      this.$store.commit('increment', 2)
    }
  }
}

派生状态 --- getters

从state派生出新状态,类似计算属性

export default new Vuex.Store({
  getters: {
    score(state){
      return 'score记录:' + state.count
    }
  }
})

使用方式

<span>{{$store.getters.score}}</span>

动作 --- actions

复杂业务逻辑,类似于controller

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state, n=1) {
      state.count += n
    }
  },
  actions: {
    incrementAsync({ commit }){
      setTimeout(()=>{
        commit('increment', 2)
      }, 1000)
    }
  }
})

使用actions

<template>
  <div class="home">
    <p>count: {{$store.state.count}}</p>
    <button @click="addAsync">add</button>
  </div>
</template>

<script>
export default {
  methods: {
    addAsync(){
      this.$store.dispatch('incrementAsync')
    }
  }
}
</script>

模块化

按模块化的方式编写代码

// store.js
// 这里可以提出另一个文件,来进行单独管理
const count = {
  namespaced: true,
  state: {
    count: 0
  },
  mutations: {
    increment(state, n=1) {
      state.count += n
    }
  },
  getters: {
    score(state){
      return 'score记录:' + state.count
    }
  },
  actions: {
    incrementAsync({ commit }){
      setTimeout(()=>{
        commit('increment', 2)
      }, 1000)
    }
  }
}

export default new Vuex.Store({
  modules: {
    a: count
  }
})

使用方式发生变化

<template>
  <div class="home">
    <h3>vuex test</h3>
    <p>count: {{$store.state.a.count}}</p>
    <p>{{$store.getters['a/score']}}</p>
    <button @click="addAsync">add</button>
  </div>
</template>

<script>
export default {
  methods: {
    addAsync(){
      this.$store.dispatch('a/incrementAsync')
    }
  }
}
</script>

mapState,mapGetter,mapMutations  好处在于和$store 脱耦了

Vuex原理解析

 功能实现:

  • 维护状态state
  • 修改状态commit
  • 业务逻辑控制dispatch
  • 状态派发getter
  • 实现state响应式
  • 插件
  • 混入
// kvue.js
let Vue

function install(_Vue) {
  Vue = _Vue

  // 这样store执行的时候,就有了vue,不用import
  // 这也是为什么Vue.use必须在新建store之前
  // 混入:把store选项指定到Vue原型上
  Vue.mixin({
    beforeCreate() {
      // 这样才能获取到传递进来的store
      // 只有root元素才有store,判断一下
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store
      }
    },
  })
}

class Store {
  // options: {state:{count:0}, mutations:{...}}
  constructor(options = {}) {
    // 利用Vue的数据响应式---和Vue的紧耦合
    this.state = new Vue({
      data: options.state
    })

    // 初始化mutations
    this.mutations = options.mutations || {}
  }
  // 触发mutations,需要实现commit
  // 注意这里用箭头函数形式,后面actions实现时会有作用
  commit = (type, arg) => {
    // this指向Store实例
    const fn = this.mutations[type] // 获取变更函数
    fn(this.state, arg)
  }
}

// 这个就是Vuex,Vuex.Store 就是可以拿到store实例了
export default { Store, install }

实现dispatch

class Store {
  constructor(options = {}) {
    this.actions = options.actions || {}
  }

  commit = (type, arg) => {
    const fn = this.mutations[type]
    fn(this.state, arg)
  }

  dispatch(type, arg) {
    const fn = this.actions[type]
    return fn({ commit: this.commit, state: this.state }, arg)
  }
}

实现getter

class Store {
  constructor(options = {}) {
    options.getters && this.handleGetters(options.getters);
  }
  handleGetters(getters) {
    this.getters = {}; // 定义this.getters   
    // 遍历getters选项,为this.getters定义property  
    // 属性名就是选项中的key,只需定义get函数保证其只读性 
    Object.keys(getters).forEach(key => {
      // 这样这些属性都是只读的   
      Object.defineProperty(this.getters, key, {
        get: () => { // 注意依然是箭头函数    
          return getters[key](this.state);
        }
      });
    });
  }
}
原文地址:https://www.cnblogs.com/haishen/p/11772142.html