實(shí)現(xiàn)vuex原理的示例
效果圖如下:
1. 準(zhǔn)備好環(huán)境
使用 vue/cil 初始化項(xiàng)目配置:
npm install -g @vue/cli //全局安裝@vue/cli vue create demo-vue //創(chuàng)建項(xiàng)目
yarn add vuex安裝vuex創(chuàng)建一個(gè)store文件夾并使用:
2. 實(shí)現(xiàn)目的
stroe/index.js內(nèi)容如下:(我們的目的將引入自寫(xiě)的vuex實(shí)現(xiàn)vuex基礎(chǔ)功能)
import Vue from 'vue' import Vuex from 'vuex' // import Vuex from './myvuex' //我們實(shí)現(xiàn)的 青銅版vuex // import Vuex from './myvuexplus' //我們實(shí)現(xiàn)的 白銀版vuex Vue.use(Vuex) //執(zhí)行install方法 將new Vuex.Store掛載到this.$store export default new Vuex.Store({ state: { counter: 0, userData: { name: '時(shí)間', age: 18 } }, getters: { name(state) { return state.userData.name } }, mutations: { add(state) { state.counter++ }, updateName(state, payload) { state.userData.name = payload } }, actions: { add({ commit }) { setTimeout(() => { commit('add') }, 1000); } } })
- 青銅版vuexmyvuex.js代碼如下:
let Vue class Store { constructor(options) { this._vm = new Vue({ data: { state: options.state } }) let getters = options.getters this.getters = {} Object.keys(getters).forEach((val) => { Object.defineProperty(this.getters, val, { //getters響應(yīng)式 get: () => { return getters[val](this.state) } }) }) this._actions = Object.assign({}, options.actions) this._mutations = Object.assign({}, options.mutations) } // get/set state目的:防止外部直接修改state get state() { return this._vm.state } set state(value) { console.error('please use replaceState to reset state') } commit = (funName, params) => { //this執(zhí)行問(wèn)題 // 在mutations中找到funName中對(duì)應(yīng)的函數(shù)并且執(zhí)行 this._mutations[funName](this.state, params) } dispatch(funName, params) { this._actions[funName](this, params) } } function install(vue) { Vue = vue vue.mixin({ beforeCreate () { // 將 new Store() 實(shí)例掛載到唯一的根組件 this 上 if (this.$options?.store) { this.$store = this.$options.store } else { this.$store = this.$parent && this.$parent.$store } } }) } export default { Store, install }
青銅版vuex this.$stroe:
- 白銀版vuexmyvuexplus.js代碼如下:
let _Vue const install = function(Vue, opts) { _Vue = Vue _Vue.mixin({ // 因?yàn)槲覀兠總€(gè)組件都有 this.$store這個(gè)東西,所以我們使用混入模式 beforeCreate () { // 從根組件向子組件遍歷賦值,這邊的 this 就是每個(gè) Vue 實(shí)例 if (this.$options && this.$options.store) { // 這是根節(jié)點(diǎn) this.$store = this.$options.store } else { this.$store = this.$parent && this.$parent.$store } } }) } class ModuleCollection { constructor(opts) { this.root = this.register(opts) } register(module) { let newModule = { _raw: module, _state: module.state || {}, _children: {} } Object.keys(module.modules || {}).forEach(moduleName => { newModule._children[moduleName] = this.register(module.modules[moduleName]) }) return newModule } } class Store { constructor(opts) { this.vm = new _Vue({ data () { return { state: opts.state // 把對(duì)象變成響應(yīng)式的,這樣才能更新視圖 } } }) this.getters = {} this.mutations = {} this.actions = {} // 先格式化傳進(jìn)來(lái)的 modules 數(shù)據(jù) // 嵌套模塊的 mutation 和 getters 都需要放到 this 中 this.modules = new ModuleCollection(opts) console.log(this.modules) Store.installModules(this, [], this.modules.root) } commit = (mutationName, value) => { // 這個(gè)地方 this 指向會(huì)有問(wèn)題,這其實(shí)是掛載在實(shí)例上 this.mutations[mutationName].forEach(f => f(value)) } dispatch(actionName, value) { this.actions[actionName].forEach(f => f(value)) } get state() { return this.vm.state } } Store.installModules = function(store, path, curModule) { let getters = curModule._raw.getters || {} let mutations = curModule._raw.mutations || {} let actions = curModule._raw.actions || {} let state = curModule._state || {} // 把子模塊的狀態(tài)掛載到父模塊上,其他直接掛載到根 store 上即可 if (path.length) { let parent = path.slice(0, -1).reduce((pre, cur) => { return pre[cur] }, store.state) _Vue.set(parent, path[path.length - 1], state) } Object.keys(getters).forEach(getterName => { Object.defineProperty(store.getters, getterName, { get: () => { return getters[getterName](state) } }) }) Object.keys(mutations).forEach(mutationName => { if (!(store.mutations && store.mutations[mutationName])) store.mutations[mutationName] = [] store.mutations[mutationName].push(value => { mutations[mutationName].call(store, state, value) }) }) Object.keys(actions).forEach(actionName => { if (!(store.actions && store.actions[actionName])) store.actions[actionName] = [] store.actions[actionName].push(value => { actions[actionName].call(store, store, value) }) }) Object.keys(curModule._children || {}).forEach(module => { Store.installModules(store, path.concat(module), curModule._children[module]) }) } // computed: mapState(['name']) // 相當(dāng)于 name(){ return this.$store.state.name } const mapState = list => { // 因?yàn)樽詈笠?computed 中調(diào)用 let obj = {} list.forEach(stateName => { obj[stateName] = () => this.$store.state[stateName] }) return obj } const mapGetters = list => { // 因?yàn)樽詈笠?computed 中調(diào)用 let obj = {} list.forEach(getterName => { obj[getterName] = () => this.$store.getters[getterName] }) return obj } const mapMutations = list => { let obj = {} list.forEach(mutationName => { obj[mutationName] = (value) => { this.$store.commit(mutationName, value) } }) return obj } const mapActions = list => { let obj = {} list.forEach(actionName => { obj[actionName] = (value) => { this.$store.dispatch(actionName, value) } }) return obj } export default { install, Store, mapState, mapGetters, mapMutations, mapActions }
白銀版vuex this.$stroe:
3. App.vue 內(nèi)使用自寫(xiě)的vuex:
<template> <div id="app"> <button @click="$store.commit('add')">$store.commit('add'): {{$store.state.counter}}</button> <br> <button @click="$store.commit('updateName', new Date().toLocaleString())">$store.commit('updateName', Date): {{$store.getters.name}}</button> <br> <button @click="$store.dispatch('add')">async $store.dispatch('add'): {{$store.state.counter}}</button> </div> </template> <script> ...
以上就是實(shí)現(xiàn)vuex原理的示例的詳細(xì)內(nèi)容,更多關(guān)于實(shí)現(xiàn)vuex原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
淺析vue中常見(jiàn)循環(huán)遍歷指令的使用 v-for
這篇文章主要介紹了vue中常見(jiàn)循環(huán)遍歷指令的使用 v-for,包括v-for遍歷數(shù)組,v-for遍歷json對(duì)象,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2018-04-04Vue中使用addEventListener添加事件、removeEventListener移除事件的示例詳解
最近在項(xiàng)目中需要用到addEventListener監(jiān)聽(tīng)滾動(dòng)條滾動(dòng)的高度,所以就研究了一下在vue中是怎么進(jìn)行事件監(jiān)聽(tīng)的,添加事件和移除事件結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-12-12vuejs2.0實(shí)現(xiàn)分頁(yè)組件使用$emit進(jìn)行事件監(jiān)聽(tīng)數(shù)據(jù)傳遞的方法
這篇文章主要介紹了vuejs2.0實(shí)現(xiàn)分頁(yè)組件使用$emit進(jìn)行事件監(jiān)聽(tīng)數(shù)據(jù)傳遞的方法,非常不錯(cuò),具有參考借鑒價(jià)值,,需要的朋友可以參考下2017-02-02vue實(shí)現(xiàn)計(jì)數(shù)器簡(jiǎn)單制作
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)計(jì)數(shù)器簡(jiǎn)單制作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06Vue CLI4.0 webpack配置屬性之productionSourceMap用法
這篇文章主要介紹了Vue CLI4.0 webpack配置屬性之productionSourceMap用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06Vue實(shí)現(xiàn)JSON字符串格式化編輯器組件功能
這篇文章主要介紹了Vue實(shí)現(xiàn)JSON字符串格式化編輯器組件,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01vue 項(xiàng)目打包時(shí)樣式及背景圖片路徑找不到的解決方式
今天小編就為大家分享一篇vue 項(xiàng)目打包時(shí)樣式及背景圖片路徑找不到的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11