当前位置: 首页 > 编程日记 > 正文

详解 Vue Vuex 实践

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

随着应用复杂度的增加,我们需要考虑如何进行应用的状态管理,将业务逻辑与界面交互相剥离,详细讨论参考笔者的2016-我的前端之路:工具化与工程化。Vue 为我们提供了方便的组件内状态管理的机制,下面这个例子就是常见的获取列表数据然后渲染到界面中:

import axios from 'axios'
export default {name: 'projects',data: function () {return {projects: []}},methods: {loadProjects: function () {axios.get('/secured/projects').then((response) => {this.projects = response.data}, (err) => {console.log(err)})}},mounted: function () {this.loadProjects()}
}
</script>

在 template 中我们可以方便的访问项目列表并且进行过滤、排序等操作,不过如果我们在另一个列表中也需要来展示相同的数据信息,继续按照这种方式实现的话我们不得不重新加载一遍数据。更麻烦的是如果用户在本地修改了某个列表数据,那么如何同步两个组件中的列表信息会是个头疼的问题。Vue 官方推荐使用Vuex,类似于 Redux 的集中式状态管理工具来辅助解决这个问题。

何谓 Vuex?

根据 Vuex 文档中的描述,Vuex 是适用于 Vue.js 应用的状态管理库,为应用中的所有组件提供集中式的状态存储与操作,保证了所有状态以可预测的方式进行修改。

Vuex 中 Store 的模板化定义如下:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({state: {},actions: {},mutations: {},getters: {},  modules: {}
})
export default store

上述代码中包含了定义 Vuex Store 时关键的 5 个属性:

  • state: state 定义了应用状态的数据结构,同样可以在这里设置默认的初始状态。

state: {projects: [],userProfile: {}
}
  • actions:Actions 即是定义提交触发更改信息的描述,常见的例子有从服务端获取数据,在数据获取完成后会调用store.commit()来调用更改 Store 中的状态。可以在组件中使用dispatch来发出 Actions。

actions: {LOAD_PROJECT_LIST: function ({ commit }) {axios.get('/secured/projects').then((response) => {commit('SET_PROJECT_LIST', { list: response.data })}, (err) => {console.log(err)})}}
  • mutations: 调用 mutations 是唯一允许更新应用状态的地方。

mutations: {SET_PROJECT_LIST: (state, { list }) => {state.projects = list}}
  • getters: Getters 允许组件从 Store 中获取数据,譬如我们可以从 Store 中的 projectList 中筛选出已完成的项目列表:

getters: {completedProjects: state => {return state.projects.filter(project => project.completed).length}
}
  • modules: modules 对象允许将单一的 Store 拆分为多个 Store 的同时保存在单一的状态树中。随着应用复杂度的增加,这种拆分能够更好地组织代码,更多细节参考这里。

Example

在理解了 Vuex 的基础概念之后,我们会创建一个真正的应用来熟悉整个使用流程。该应用承接自这个博客,在准备好基础项目之后,我们需要将 vuex 引入项目中:

$ yarn add vuex

该步骤完成之后,我们需要在 src 目录下创建名为 store 的目录来存放状态管理相关代码,首先创建 index.js:

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
const store = new Vuex.Store({state: {},actions: {},mutations: {},getters: {}
})
export default store

然后在 main.js 文件中我们需要将该 Store 实例添加到构造的 Vue 实例中:

import store from './store'
/* eslint-disable no-new */
new Vue({template: `<div><navbar /><section class="section"><div class="container is-fluid"><router-view></router-view></div></section></div>`,router,store,components: {navbar}
}).$mount('#app')

然后,我们需要去完善 Store 定义:

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
const store = new Vuex.Store({state: {projects: []},actions: {LOAD_PROJECT_LIST: function ({ commit }) {axios.get('/secured/projects').then((response) => {commit('SET_PROJECT_LIST', { list: response.data })}, (err) => {console.log(err)})}},mutations: {SET_PROJECT_LIST: (state, { list }) => {state.projects = list}},getters: {openProjects: state => {return state.projects.filter(project => !project.completed)}}
})
export default store

在本项目中,我们将原本存放在组件内的项目数组移动到 Store 中,并且将所有关于状态的改变都通过 Action 进行而不是直接修改:

// /src/components/projectList.vue
<template lang="html"><div class=""><table class="table"><thead><tr><th>Project Name</th><th>Assigned To</th><th>Priority</th><th>Completed</th></tr></thead><tbody><tr v-for="item in projects"><td>{{item.name}}</td><td>{{item.assignedTo}}</td><td>{{item.priority}}</td><td><i v-if="item.completed" class="fa fa-check"></i></td></tr></tbody></table></div>
</template>
<script>
import { mapState } from 'vuex'
export default {name: 'projectList',computed: mapState(['projects'])
}
</script>
<style lang="css">
</style>

这个模板还是十分直观,我们通过computed对象来访问 Store 中的状态信息。值得一提的是这里的mapState函数,这里用的是简写,完整的话可以直接访问 Store 对象:

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

mapState 是 Vuex 提供的简化数据访问的辅助函数。我们视线回到 project.vue 容器组件,在该组件中调用this.$store.dispatch('LOAD_PROJECT_LIST)来触发从服务端中加载项目列表:

<template lang="html"><div id="projects"><div class="columns"><div class="column is-half"><div class="notification">Project List</div><project-list /></div></div></div>
</template>
<script>
import projectList from '../components/projectList'
export default {name: 'projects',components: {projectList},mounted: function () {this.$store.dispatch('LOAD_PROJECT_LIST')}
}
</script>

当我们启动应用时,Vuex 状态管理容器会自动在数据获取之后渲染整个项目列表。现在我们需要添加新的 Action 与 Mutation 来创建新的项目:

// under actions:
ADD_NEW_PROJECT: function ({ commit }) {axios.post('/secured/projects').then((response) => {commit('ADD_PROJECT', { project: response.data })}, (err) => {console.log(err)})
}
// under mutations:
ADD_PROJECT: (state, { project }) => {state.projects.push(project)
}

然后我们创建一个简单的用于添加新的项目的组件 addProject.vue:

<template lang="html"><button type="button" class="button" @click="addProject()">Add New Project</button>
</template>
<script>
export default {name: 'addProject',methods: {addProject () {this.$store.dispatch('ADD_NEW_PROJECT')}}
}
</script>

该组件会派发某个 Action 来添加组件,我们需要将该组件引入到 projects.vue 中:

<template lang="html"><div id="projects"><div class="columns"><div class="column is-half"><div class="notification">Project List</div><project-list /><add-project /></div></div></div>
</template>
<script>
import projectList from '../components/projectList'
import addProject from '../components/addProject'
export default {name: 'projects',components: {projectList,addProject},mounted: function () {this.$store.dispatch('LOAD_PROJECT_LIST')}
}
</script>

重新运行下该应用会看到服务端返回的创建成功的提示,现在我们添加另一个功能,就是允许用户将某个项目设置为已完成。我们现在添加新的组件 completeToggle.vue:

<template lang="html"><button type="button" class="button"  @click="toggle(item)"><i class="fa fa-undo" v-if="item.completed"></i><i class="fa fa-check-circle" v-else></i></button>
</template>
<script>
export default {name: 'completeToggle',props: ['item'],methods: {toggle (item) {this.$store.dispatch('TOGGLE_COMPLETED', { item: item })}}
}
</script>

该组件会展示一个用于切换项目是否完成的按钮,我们通过 Props 传入具体的项目信息然后通过触发 TOGGLE_COMPLETED Action 来使服务端进行相对应的更新与相应:

// actions
TOGGLE_COMPLETED: function ({ commit, state }, { item }) {axios.put('/secured/projects/' + item.id, item).then((response) => {commit('UPDATE_PROJECT', { item: response.data })}, (err) => {console.log(err)})
}
// mutations
UPDATE_PROJECT: (state, { item }) => {let idx = state.projects.map(p => p.id).indexOf(item.id)state.projects.splice(idx, 1, item)
}

UPDATE_PROJECT 会触发项目列表移除对应的项目并且将服务端返回的数据重新添加到数组中:

app.put('/secured/projects/:id', function (req, res) {let project = data.filter(function (p) { return p.id == req.params.id })if (project.length > 0) {project[0].completed = !project[0].completedres.status(201).json(project[0])} else {res.sendStatus(404)}
})

最后一步就是将 completeToggle 组件引入到 projectList 组件中,然后将其添加到列表中:

// new column in table
<td><complete-toggle :item="item" /></td>
// be sure import and add to the components object

再谈引入状态管理的意义

现在我们的应用已经具备了基本的特性,这里我们再度回顾下文首的讨论,为什么我们需要大费周章的引入外部状态管理,将业务逻辑切分到组件外。譬如这里我们需要另一个组件来展示项目的统计信息,譬如项目的总数或者已完成项目的数目。我们肯定要避免重复地从服务端抓取数据,而是所谓的 Single Source Of Truth。这里我们添加新的 projectStatus.vue 组件来展示项目的统计信息:

<template lang="html"><article class="message"><div class="message-header"><p>Project Status:</p></div><div class="message-body"><div class="control"><span class="tag is-info">Number of projects: {{projectCount}}</span></div><div class="control"><span class="tag is-success">Completed: {{completedProjects}}</span></div></div></article>
</template>
<script>
import { mapGetters } from 'vuex'
export default {name: 'projectStatus',computed: {...mapGetters(['completedProjects','projectCount'])}
}
</script>

该组件会展示项目的总数与已完成项目的总数,上面我们使用了maoGetters辅助函数来减少冗余代码:

getters: {completedProjects: state => {return state.projects.filter(project =>project.completed).length},projectCount: state => {return state.projects.length}
}

最后我们将该统计信息添加到项目列表中,效果图示如下:

v2-276a3bc29b68f766daa828e859230b9f_b.jpg

转载于:https://my.oschina.net/u/2456768/blog/858673

相关文章:

可控制的页面内滚动区域

效果预览 下面我们就来详细讲解一下这种效果的制作方法&#xff1a; 首先&#xff0c;我们在样式表里加入“.opacity {FILTER: alpha(opacity100)”&#xff0c;看下面&#xff01; <style type"text/css"><!--.opacity {FILTER: alpha(opacity100)}-->&…

提升对ASP.NET网站性能和多并发的设计的讨论

对于如何提高应用程序的性能&#xff08;无论是互联网应用还是企业级应用&#xff09;我的观点一直是考虑一个核心&#xff1a;IO处理。因为我认为目前的CPU的处理能力已经是非常高了&#xff0c;正常编写的在内存中处理的代码没有太严重的问题都不会对CPU造成很大的影响&#…

算力至上?四大AI芯片大对决

来源 | 老石谈芯&#xff08;ID: laoshi_tanxin&#xff09;目前&#xff0c;全世界超过90%的数据都是在过去的两三年之内产生的。随着人工智能、自动驾驶、5G、云计算等各种技术的不断发展&#xff0c;海量数据都将会继续源源不断的产生。预计到2025年&#xff0c;数据总量将比…

JavaScript作用域原理——预编译

JavaScript是一种脚本语言, 它的执行过程, 是一种翻译执行的过程。并且JavaScript是有预编译过程的&#xff0c;在执行每一段脚本代码之前, 都会首先处理var关键字和function定义式&#xff08;函数定义式和函数表达式&#xff09;。 一、变量执行之前&#xff0c;会被赋为unde…

VC++实现QQ聊天工具【源代码】

http://down.51cto.com/data/53416转载于:https://blog.51cto.com/6297123/1094981

​炸了!程序员现在没有这点技能都还不能就业了?

数据正在变得越来越常见&#xff0c;小到我们每个人的社交网络、消费信息、运动轨迹……&#xff0c;大到企业的销售、运营数据&#xff0c;产品的生产数据&#xff0c;交通网络数据……如何从海量数据中获得别人看不见的知识&#xff0c;如何利用数据来武装营销工作、优化产品…

javascript表单之间的数据传递

今天有朋友问我关于用javascript来进行页面各表单之间的数据传递的问题&#xff0c;我以前也写过&#xff0c;不过从来没有注意&#xff0c;今天总结了一下&#xff0c;希望能够给大家一些帮助&#xff0c;也帮助我总结以前学过&#xff0c;用过的知识。 一&#xff0c;最简单的…

Vue从Hello World到打包(后端适读)

Vue从Hello World到上线 Vue 简介 Vue是个MVVM框架。 特点&#xff1a;简单易学、体积小、性能高。并且它的源码耦合性非常低&#xff0c;了解它的过程也就是思想进步的过程。 当然&#xff0c;只学这一个框架&#xff0c;无法完成前端的全部工作&#xff0c;除了Vue之外&#…

Android和iOS那个好?

Android和iOS那个好&#xff1f; 应该先往哪个上面投入资源&#xff1f; 多次被人问到此类问题&#xff0c;笔者刚好自己的项目也需要考虑iOS版本。就索性进行了一番调研&#xff0c;于是有了本文&#xff08;本次不讨论越狱的iOS&#xff09; 首先从情感上&#xff0c;你…

对话谢宝友:搞真正自研的国产操作系统,而不是伪创新

作者 | 郑丽媛责编 | 屠敏出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;从国外操作系统的长期垄断到中国自主研发操作系统数十年的起落浮沉&#xff0c;技术自主创新独立已成为国产基础软件的主要突破口。近几年间&#xff0c;随着物联网时代的到来&#xff0c;以…

ASP.NET 学习历程

[注意我不推荐高级技术的书&#xff0c;因为你如果是个高手了就可以自己选择甄别书了&#xff0c;此文只对初学者&#xff0c;因为他们此时没有辨别好快的能力&#xff0c;本人几乎买尽所有的.NET书&#xff0c;有好有坏。] 你所看的第一本书对你以后影响最重要&#xff01;&a…

http头部消息中的cache-control解释

网页的缓存是由HTTP消息头中的“Cache-control”来控制的&#xff0c;max-age&#xff1a;&#xff08;只接受 Age 值小于 max-age 值&#xff0c;并且没有过期的对象&#xff09;max-stale&#xff1a;&#xff08;可以接受过去的对象&#xff0c;但是过期时间必须小于 max-st…

iframe自动调整高度能在IE5里实现吗

偶已经理解到style"height:expression(main.document.body.scrollHeight)"只对第一次显示的内嵌网页有效&#xff0c;如果里面的内容更新必须把主页刷新一遍才能自动适应新的高度&#xff0c;那么惟一的解决办法就是点击链接后整个页面都刷新一次&#xff0c;如何写成…

SQL Server-流程控制 5,Goto 语句

ylbtech-SQL Server:SQL Server-流程控制 5,Goto 语句SQL Server 流程控制中的 Goto 语句。 1&#xff0c;Goto 语句1 --2 -- 1, Goto语句3 -- Desc:Goto语句可以让程序跳转到一个指定的标签处并执行其后的代码。Goto语句和标签可以在程序4 -- 、批处理和语句块中的任意位置使用…

MLPerf基准测试再发榜,浪潮AI服务器刷新18项纪录

近日&#xff0c;全球倍受瞩目的权威AI基准测试MLPerf公布今年的推理测试榜单&#xff0c;其中浪潮AI服务器NF5488A5一举创造18项性能纪录&#xff0c;在数据中心AI推理性能上遥遥领先其他厂商产品。 MLPerf是当前全球最具影响力的AI计算基准评测组织&#xff0c;由图灵奖得主大…

Web充斥着存在漏洞的过期JavaScript库

虽然使用第三方软件库通常会降低开发的时间&#xff0c;但同时也会增加网站暴露出的攻击表面&#xff0c;对此我们应有充分的认识。因此需要保持第三方软件库的最新版本依赖&#xff0c;以便从安全更新中获益。即便如此&#xff0c;一份近期研究表明&#xff0c;在Alexa排名前7…

asp.net实现C#代码加亮显示

以下是代码片段&#xff1a;StringWriter textBuffer new StringWriter();Match match Regex.Match(HTMLStr,"/",RegexOptions.IgnoreCase | RegexOptions.Compiled);if(matchnull){Response.Write(HTMLStr);return;} string codeType match.Groups["codeType…

应用在大规模推荐系统,Facebook提出组合embedding方法 | KDD 2020

来源 | 深度传送门&#xff08;ID: deep_deliver&#xff09;Facebook团队考虑embedding的存储瓶颈&#xff0c;提出了一种新颖的方法&#xff0c;通过利用类别集合的互补分区为每个类别生成唯一的embedding向量&#xff0c;无需明确定义&#xff0c;从而以端到端的方式减小emb…

Android大图裁剪解决办法

某些功能需要拍照或者从相册选择照片后经过裁剪再上传的时候&#xff0c; cropp_w_picpath 可以调用手机自带的com.android.camera.action.CROP这个Intent进行裁剪 通过设置输出大小可以得到图片的大小&#xff1a; intent.putExtra(“outputX”, outputX); intent.putExtra(“…

day03-字符编码与转换

1、编码常识 在python 2中默认编码是 ASCII&#xff0c;而在python 3中默认编码是 unicodeunicode 分为utf-32 (占4个字节),utf-16(占两个字节)&#xff0c;utf-8(占1-4个字节)&#xff0c;所以utf-16 是最常用的unicode版本&#xff0c;但是在文件里存的还是utf-8&#xff0c;…

Asp.Net下的DataGrid的多层表头

先看下表&#xff1a; 业务员地 区 北京上海深圳张三100200300实际上Asp.Net下的DataGrid只不过是一个HtmlTable&#xff0c;只不过在HtmlTable的基础上添加了很多属性、方法&#xff0c;纳入ViewState机制&#xff0c;来生成、控制它&#xff1b;有了这一点认识&#xff0c;事…

Selenium的延迟等待

2019独角兽企业重金招聘Python工程师标准>>> Selenium的延迟等待分为 显式等待(Explicit Wait) & 隐式等待(Implicit Wait). 1.显式等待 显式等待,就是明确的要等到某个元素的出现或者是某个元素的可点击等条件,等不到,就一直等,除非在规定的时间之内都没找到…

瞧瞧,这样的代码才叫Pythonic

来源 | Python编程时光&#xff08;ID: Cool-Python&#xff09;Python由于语言的简洁性&#xff0c;让我们以人类思考的方式来写代码&#xff0c;新手更容易上手&#xff0c;老鸟更爱不释手。要写出 Pythonic&#xff08;优雅的、地道的、整洁的&#xff09;代码&#xff0c;还…

linux基础(一)安装系统Centos6.5

安装有常用有&#xff1a;远程网络安装、U盘安装、光盘安装三种方式&#xff0c;以下为光盘进行安装1.出现引导界面&#xff0c;选择安装或升级现有系统&#xff0c;选择第一个安装系统。Install or upgrade an existing system 安装或升级现有的系统 install system with basi…

使用 .NET 对事件进行编程

作者:Ted Pattison  您可能已经对事件进行编程若干年了&#xff0c;但是迁移到 .NET Framework 仍然需要您重新检查事件的内部工作&#xff0c;因为 .NET Framework 中的事件位于委托的顶层。 对委托的了解越多&#xff0c;对事件进行编程时所具有的驾驭能力越强。 开始使用公…

tomcat项目自动发布脚本.脚本运行效果

./update -------------------------------------------------------------- | 确定特定用户执行,否则退出 | -------------------------------------------------------------- Yes,we are the user of testtomcat --------------------------------------------------…

11.11大促来袭,京东如何保障云安全?

2020年4月&#xff0c;国家发改委首次就“新基建”概念作出正式解释。云计算被纳入信息基础设施中的新技术基础设施。据IDC统计&#xff0c;2019年全球云计算基础设施规模超过传统IT基础设施&#xff0c;占全球IT基础设施的50%以上。云计算发展势如破笋&#xff0c;云计算也成为…

分享Kali Linux 2017年第11周镜像文件

分享Kali Linux 2017年第11周镜像文件 Kali?Linux官方于3月12日发布2017年的第11周镜像。这次维持了11个镜像文件的规模。默认的Gnome桌面的4个镜像&#xff0c;E17、KDE、LXDE、MATE、XFCE桌面的各一个&#xff0c;手机版的包括ARMEL和ARMHF。有最近要安装Kali?Linux系统的&…

实现无刷新DropDownList联动效果

在做一个文章添加功能时&#xff0c;想在选择大类后&#xff0c;自动将其所属二级小类显示出来&#xff0c;使用DropDownList的SelectedIndexChanged事件可以很容易实现&#xff0c;但每次选择后页面总要刷新一次&#xff0c;让人感觉很不爽。为实现DropDownList无刷新二级联动…

偷天换日,逼真的天空置换算法

责编 | 晋兆雨来源 | Jack Cui头图 | CSDN付费下载于视觉中国前言天空&#xff0c;是摄像中的一个关键元素。游戏的天空&#xff0c;我们可以随意调节&#xff0c;可以是晴空万里&#xff0c;也可以是风雨交加。现实的天空&#xff0c;我们也可以使用算法进行调整&#xff0c;算…