热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vuex刷新数据消失插件_手写简易的Vuex

前言本文适合使用过Vuex的人阅读,来了解下怎么自己实现一个Vuex。基本骨架这是本项目的srcstoreindex.js文件,看看一般vuex的使用i

前言

本文适合使用过 Vuex 的人阅读,来了解下怎么自己实现一个 Vuex。

基本骨架

这是本项目的src/store/index.js文件,看看一般 vuex 的使用

import Vue from 'vue'
import Vuex from './myvuex' // 引入自己写的 vuex
import * as getters from './getters'
import * as actions from './actions'
import state from './state'
import mutations from './mutations'

Vue.use(Vuex) // Vue.use(plugin)方法使用vuex插件

// vuex 导出一个类叫Store,并传入对象作为参数
export default new Vuex.Store({
  state,
  mutations,
  actions,
  getters,
})

Vue.use的用法:

安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象。

  • 该方法需要在调用 new Vue() 之前被调用。
  • 当 install 方法被同一个插件多次调用,插件将只会被安装一次。

即是我们需要在./myvuex.js中导出 install方法,同时导出一个类Store,于是第一步可以写出代码:

let Vue = null

class Store {
  constructor(options) {}
}

function install(_Vue) {
  Vue = _Vue // 上面Store类需要能获取到Vue
}

export default {
  Store,
  install,
}

install 方法

当我们使用 vuex 的时候,每一个组件上面都有一个this.$store属性,里面包含了 state,mutations, actions, getters 等,所以我们也需要在每个组件上都挂载一个$store 属性,要让每一个组件都能获取到,这里我们使用Vue.mixin(mixin),用法介绍如下:

全局注册一个混入,影响注册之后所有创建的每个 Vue 实例。可以使用混入向组件注入自定义的行为,它将影响每一个之后创建的 Vue 实例。

function install(_Vue) {
  Vue = _Vue // install方法调用时,会将Vue作为参数传入(上面Store类需要用到Vue)
  // 实现每一个组件,都能通过this调用$store
  Vue.mixin({
    beforeCreate() {
      // 通过this.$options可以获取new Vue({参数}) 传递的参数
      if (this.$options && this.$options.store) {
        // 证明这个this是根实例,也就是new Vue产生的那个实例
        this.$store = this.$options.store
      } else if (this.$parent && this.$parent.$store) {
        // 子组件获取父组件的$store属性
        this.$store = this.$parent.$store
      }
    },
  })
}

state

由于 Vuex 是基于 Vue 的响应式原理基础,所以我们要让数据改变可刷新视图,则需要创建一个 vue 实例 由于

class Store {
  // options 即是 Vuex.Store({})传入的参数
  constructor(options) {
    // vuex 的核心就是借用了vue的实例,因为vue的实例数据变化,会刷新视图
    let vm = new Vue({
      data: {
        state: options.state,
      },
    })
    // state
    this.state = vm.state
  }
}

commit

我们使用 vuex 改变数据时,是触发 commit 方法,即是这样使用的:

this.$store.commit('eventName', '参数' );

所以我们要实现一个commit方法,把 Store 构造函数传入的 mutations 做下处理

class Store {
  constructor(options) {
    // 实现 state ...

    // mutations
    this.mutations = {} // 存储传进来的mutations
    let mutations = options.mutations || {}
    // 循环取出事件名进行处理(mutations[事件名]: 执行方法)
    Object.keys(mutations).forEach(key => {
      this.mutations[key] = params => {
        mutations[key].call(this, this.state, params) // 修正this指向
      }
    })
  }

  commit = (key, params) => {
    // key为要触发的事件名
    this.mutations[key](params)
  }
}

dispatch

跟上面的 commit 流程同理

class Store {
  constructor(options = {}) {
    // ...

    // actions
    this.actions = {}
    let actions = options.actions || {}
    Object.keys(actions).forEach(key => {
      this.actions[key] = params => {
        actions[key].call(this, this, params)
      }
    })
  }

  dispatch = (type, payload) => {
    this.actions[type](payload)
  }
}

getters

getters 实际就是返回 state 的值,在使用的时候是放在 computed 属性,每一个 getter 都是函数形式;

getters 是需要双向绑定的。但不需要双向绑定所有的 getters,只需要绑定项目中事件使用的 getters。

这里使用Object.defineProperty()方法,它会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

class Store {
  constructor(options = {}) {
    // ...

    // getters
    this.getters = {}
    let getters = options.getters || {}
    Object.keys(getters).forEach(key => {
      Object.defineProperty(this.getters, key, {
        get: () => {
          return getters[key].call(this, this.state)
        },
      })
    })
  }
}

到此为止,已经可以使用我们自己写的 vuex 做一些基本操作了,但只能通过this.$store.xx的形式调用,故需要再实现方法。

map 辅助函数

先来说说 mapState

没有 map 辅助函数之前这样使用:

computed: {
  count () {
    return this.$store.state.count
  }
}

当映射的计算属性的名称与 state 的子节点名称相同时,给 mapState 传一个字符串数组。

computed: {
  // 使用对象展开运算符将此对象混入到外部对象中
  ...mapState(['count'])
}

我们这里简单就只实现数组的情况

export const mapState = args => {
  let obj = {}
  args.forEach(item => {
    obj[item] = function () {
      return this.$store.state[item]
    }
  })
  return obj
}

之后几个 map 辅助函数都是类似

  • mapGetters

export const mapGetters = args => {
  let obj = {}
  args.forEach(item => {
    obj[item] = function () {
      return this.$store.getters[item]
    }
  })
  return obj
}

  • mapMutations

export const mapMutations = args => {
  let obj = {}
  args.forEach(item => {
    obj[item] = function (params) {
      return this.$store.commit(item, params)
    }
  })
  return obj
}

  • mapActions

export const mapActions = args => {
  let obj = {}
  args.forEach(item => {
    obj[item] = function (payload) {
      return this.$store.dispatch(item, payload)
    }
  })
  return obj
}

完整代码

let Vue = null

class Store {
  constructor(options) {
    // vuex 的核心就是借用了vue的实例,因为vue的实例数据变化,会刷新视图
    let vm = new Vue({
      data: {
        state: options.state,
      },
    })
    // state
    this.state = vm.state

    // mutations
    this.mutations = {} // 存储传进来的mutations
    let mutations = options.mutations || {}
    Object.keys(mutations).forEach(key => {
      this.mutations[key] = params => {
        mutations[key].call(this, this.state, params)
      }
    })

    // actions
    this.actions = {}
    let actions = options.actions || {}
    Object.keys(actions).forEach(key => {
      this.actions[key] = params => {
        actions[key].call(this, this, params)
      }
    })

    // getters
    this.getters = {}
    let getters = options.getters || {}
    Object.keys(getters).forEach(key => {
      Object.defineProperty(this.getters, key, {
        get: () => {
          return getters[key].call(this, this.state)
        },
      })
    })
  }

  commit = (key, params) => {
    this.mutations[key](params)
  }

  dispatch = (type, payload) => {
    this.actions[type](payload)
  }
}

export const mapState = args => {
  let obj = {}
  args.forEach(item => {
    obj[item] = function () {
      return this.$store.state[item]
    }
  })
  return obj
}

export const mapGetters = args => {
  let obj = {}
  args.forEach(item => {
    obj[item] = function () {
      return this.$store.getters[item]
    }
  })
  return obj
}

export const mapMutations = args => {
  let obj = {}
  args.forEach(item => {
    obj[item] = function (params) {
      return this.$store.commit(item, params)
    }
  })
  return obj
}

export const mapActions = args => {
  let obj = {}
  args.forEach(item => {
    obj[item] = function (payload) {
      return this.$store.dispatch(item, payload)
    }
  })
  return obj
}

function install(_Vue) {
  Vue = _Vue // install方法调用时,会将Vue作为参数传入(上面Store类需要用到Vue)
  // 实现每一个组件,都能通过this调用$store
  Vue.mixin({
    beforeCreate() {
      // 通过this.$options可以获取new Vue({参数}) 传递的参数
      if (this.$options && this.$options.store) {
        // 证明这个this是根实例,也就是new Vue产生的那个实例
        this.$store = this.$options.store
      } else if (this.$parent && this.$parent.$store) {
        // 子组件获取父组件的$store属性
        this.$store = this.$parent.$store
      }
    },
  })
}

export default {
  Store,
  install,
}

整个项目的源码地址:mini-vuex

欢迎关注我掘金账号和Github技术博客:

  • 掘金:https://juejin.im/user/1257497033714477
  • Github:https://github.com/Jacky-Summer
  • 觉得对你有帮助或有启发的话欢迎 star,你的鼓励是我持续创作的动力~
  • 如需在微信公众号平台转载请联系作者授权同意,其它途径转载请在文章开头注明作者和文章出处。

dbb4f54d5091201a5f265b0d4f3d78b4.png




推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • PHP中的单例模式与静态变量的区别及使用方法
    本文介绍了PHP中的单例模式与静态变量的区别及使用方法。在PHP中,静态变量的存活周期仅仅是每次PHP的会话周期,与Java、C++不同。静态变量在PHP中的作用域仅限于当前文件内,在函数或类中可以传递变量。本文还通过示例代码解释了静态变量在函数和类中的使用方法,并说明了静态变量的生命周期与结构体的生命周期相关联。同时,本文还介绍了静态变量在类中的使用方法,并通过示例代码展示了如何在类中使用静态变量。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
  • PHP引用的概念和用法详解
    本文详细介绍了PHP中引用的概念和用法。引用是指不同的变量名访问同一个变量内容,类似于Unix文件系统中的hardlink。文章从引用的定义、作用、语法和注意事项等方面进行了解释和示例。同时还介绍了对未定义变量使用引用的情况,以及在函数和new运算符中使用引用的注意事项。 ... [详细]
  • php缓存ri,浅析ThinkPHP缓存之快速缓存(F方法)和动态缓存(S方法)(日常整理)
    thinkPHP的F方法只能用于缓存简单数据类型,不支持有效期和缓存对象。S()缓存方法支持有效期,又称动态缓存方法。本文是小编日常整理有关thinkp ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
author-avatar
手机用户2502895293
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有