最近在学习Vue.js的时候,看到一篇国外的文章,讲的是如何使用Vue.js和Vuex构建一个单页的简单笔记的应用。我觉得我收获了很多。我根据它的例子做了一些优化和自定义函数。我想在这里和大家分享一下我的学习经验。
在本教程中,我们将构建一个note应用程序来学习如何在我们的Vue项目中使用Vuex。我们将对Vuex.js是什么、何时在项目中使用它以及如何构建我们的Vue应用程序进行概述。
这是我们项目的预览图:
项目源代码:vuex-notes-app;有需要的同学可以直接下载源代码。
主要知识点是Vuex状态管理机制的使用,vue-CLI支架的安装,Vue.js的基本API,以及vur-router使用的ES6的语法。在这里,推荐大家看一下阮一峰的入门教程
Vuex概述在我们迫不及待地开始项目之前,我们最好花几分钟时间来了解Vuex的核心概念。
Vuex是专门为Vue.js应用程序设计的集中式状态管理架构。它借鉴了Flux和Redux的设计思想,但简化了概念,采用了专门为充分发挥Vue.js的数据响应机制而设计的实现
状态这个概念刚接触的时候可能会觉得有点模糊。简单地说,我们将状态视为项目中使用的数据集合。然后,Vuex使得组件本地状态和应用级状态有一些区别。
组件本地状态:这个状态表示它只在组件内部使用,有点类似于通过配置选项传入Vue组件的意思。应用层状态:应用层状态,表示多个组件同时共享的状态级别。
假设有一个场景,我们有一个父组件和两个子组件。通过使用props属性,父组件可以轻松地将数据传递给子组件。
但问题是,我们的两个子组件是如何相互通信的?或者子组件如何将数据传递给其父组件?当我们的项目很小的时候,这两个问题不会太难,因为我们可以通过事件调度和监控来完成父组件和子组件之间的通信。
然而,随着我们项目的发展:
1.跟踪所有事件将变得非常困难。哪个组件调度哪个事件,哪个组件应该监听哪个事件?2.项目逻辑分散在各个组件中,容易导致逻辑混乱,不利于我们项目的维护。3.父组件将越来越严重地与子组件耦合,因为它需要显式地调度和监视子组件的某些事件。
这就是Vuex试图解决的问题。Vuex的四个核心概念是:
状态树:Vuex使用单个状态树,它包含一个对象的所有应用程序级状态。此时,它作为唯一的数据源(ssot)存在。这也意味着每个应用程序将只包含一个存储实例。单一状态树使我们能够直接定位任何特定的状态段,并且可以在调试期间轻松地拍摄整个当前应用程序状态的快照。Getters:用于从商店获取Vue组件数据。变异器:事件处理程序用于驱动状态变化。动作:组件可以用来驱动事件处理程序突变的函数。这四个概念你还不太懂。别担心,我们会在实际项目中详细解释它们。
下图详细说明了Vuex应用中的数据流(Vuex官方地图)
简单解释一下:
Vuex规定属于应用层的状态只能用突变中的方法修改,调度突变中的事件只能用动作修改。
从左到右,从组件开始,在组件中调用操作。在操作层面,我们可以与后台数据进行交互,比如获取初始化的数据源或者过滤中间数据。然后派遣突变行动。突变触发状态变化,状态变化会触发视图更新。
需要注意的事项
数据流为单向的组件可以调用actionaction来调度突变。只有突变才能改变状态。存储是响应的,每当状态更新时,组件将同步更新
此应用程序的环境安装将使用webpack进行模块打包、处理和热重启。使用Vue官方提供的脚手架Vue-CLI。
安装vue-clinpm install -g vue-cli注意:Node.js=4.x,5.x最好
初始化应用程序
vue nit webpack vue-notes-appcdvue-notes-appnpm install//安装依赖包npm run dev //启动服务初始化名为vue-notes-app的应用程序,并选择使用web pack打包方法。在命令行中,按照提示选择初始化配置项目。其中,选择JSLint验证时推荐使用AirBNB规范。
使用您最喜欢的编辑器打开我们新建的项目。项目结构大致如下:
组件/文件夹用于存储我们的Vue组件。vuex/folder存储与Vuex store相关的东西(state object、actions、mutators)build//file是webpack的包和编译配置文件。配置/文件夹存储一些配置项目。例如,dist/this文件夹在开始时不存在,App.vue的根组件将在我们的项目构建完成后生成。所有子组件都将在这里被index.html整个项目的门户文件引用,并将引用我们的根组件App.vuemain.js门户文件的js逻辑,该文件将在webpack打包后注入index.html。
功能模块添加一个新注释和一个新注释。编辑区域显示空的注释内容并删除注释。删除便笺后,编辑区显示当前便笺类别的第一个便笺列表开关,分为两种类型:所有便笺和收藏便笺。切换后,编辑区域显示当前列表中的第一个音符,并将当前激活的音符标记为收藏音符。
项目组件分为这个项目,我们将总共使用四个组件:根组件App.vue、操作栏组件Toolbar.vue、其他表格组件NotesList.vue和笔记编辑组件Editor.vue
根据上面列出的功能模块,我们在Vuex/下创建了一个store.js文件。
从“Vue”导入Vue;从“Vuex”导入Vuex;vue . use(Vuex);//需要维护的状态为const state={notes: [],activenote: {},show : ' ' };const variants={//init state init _ store(state,data) {state.notes=data.notes,state . show=data . show;state . activenote=data . activenote;},//new note new _ note(state){ var new note={ id : new date(),title : ' ',内容: ' ',收藏夹: false };state . notes . push(new note);state.activeNote=newNote},//修改note edit _ note (state,note) {state。activenote=note//修改原始数据为(var I=0;I state . notes . length;i ) { if(state.notes[i]。id===note . id){ state . notes[I]=note;打破;} };},//delete note delete _ note(state){ state . notes . $ remove(state . active note);state . activenote=state . notes[0]| | { };},//在收集和取消笔记之间切换toggle _收藏夹(state) {state.activenote .收藏夹=!state.activeNote .收藏夹;},//切换显示数据列表类型:全部或收藏夹set _ show _ all (state,show) {state。show=显示;//要切换数据显示,需要更新activenote if (show==='收藏夹'){state。active note=state . notes . filter(note=note .收藏夹)[0] | | {}同步;} else { state . activenote=state . notes[0]| | { };}},//设置当前活动的note set _ active _ note(状态,note) {state。活动音符=音符;}};导出默认的新Vuex。存储({状态,突变});要创建Vuex Actions,在Vuex/下创建一个action.js,给出组件使用的函数。
函数makeAction(类型){退货({派单},args=调度(类型,args);};const initNote={ id: new Date(),title: '我的笔记,content: '第一篇笔记内容,最爱:假};//模拟初始化数据const initData={ show: 'all ',notes: [initNote],active note : init note };export const INIT STORE=({ dispatch })={ dispatch(' INIT _ STORE ',INIT数据);};//更新当前activeNote对象export const updateActiveNote=make action(' SET _ ACTIVE _ NOTE ');//添加一个注意对象导出常量新注释=采取行动('新注释');//删除一个注意对象导出常量DELETE NOTE=进行操作(' DELETE _ NOTE ');导出常量收藏夹=执行操作(' TOGGLE _收藏夹');export const editNote=make action(' EDIT _ NOTE ');//更新列表展示导出常量updateShow=进行操作(' SET _ SHOW _ ALL ');创建Vuex吸气器在vuex/下面建立一个getter.js文件,用来从商店获取数据。//获取注意列表,这里将会根据状态显示的状态做数据过滤导出常量筛选的注释=(状态)={ if(状态)。show===' all '){返回状态。notes | | { };}else if(state.show==='收藏夹){返回状态。笔记。过滤器(注意=注意。收藏夹)| | { };}};//获取列表展示状态:全部或favoriteexport const show=(state)={ return state。展示;};//获取当前激活注释导出常量活动注释=(状态)={返回状态。活动便笺;};以上就是我们Vuex的所有逻辑了,在定下了我们需要完成的功能之后,接下来就是只需要在组件中去调用行为来实现对应的功能了。
路由配置在这里我们将使用某视频剪辑软件路由器来做路由,引用引导程序样式。
index.html
!DOCTYPE html html head meta charset=' utf-8 ' title vuex-notes-app/title link rel='样式表href=' https://最大cdn。bootstrapcdn。com/bootstrap/3。3 .6/CSS/bootstrap。量滴CSS '/头体div id=' app '/div!内置文件将自动注入/正文/html所有的入口逻辑我们都将在main.js中编写
main.js
从“Vue”导入Vue从""导入应用程序/App ';从“vue路由器”导入VueRouter从“vue-resource”导入VueResource//路由模块和超文本传送协议模块vue。使用(VueResource);vue。使用(VueRouter);const router=new VueRouter();路由器。地图({ "/index " : { component : App } });路由器。重定向({ ' * ' : '/index ' });router.start(App,' # App ');根组件App.vue
模板div id='app' class='app '工具栏/工具栏注释-列表/注释-列表编辑器/编辑器/div/templatestyle html,# app { height : 100%;}正文{边距: ^ 0;padd : 0;边框: 0;高度: 100%;最大高度: 100%;相对位置:}/stylescript从""导入工具栏。/组件/工具栏;从""导入便笺列表“/组件/注释列表”;从""导入编辑器。/组件/编辑器;从""导入存储/vuex/store ';从""导入{ initStore } ./vuex/actions ';导出默认{组件: {工具栏、注释列表、编辑器}、存储、vuex: {操作3360 { initStore } }、ready(){ this。init store()}/脚本在根组件中引用了三个子组件:Toolbar.vue,NotesList.vue,Editor.vue。
注意:我们在配置里面加入了vuex这么一个选项,这里用来将我们行为里面定义的方法给暴露出来,我们在根组件中只做了一件事情,那就是初始化模拟数据,因此我们在组件生命周期的准备好的阶段调用了行动里面的initStore来初始化我们的商店里面的状态
工具栏。某视频剪辑软件
模板div id='工具栏I class=' glyphicon徽标' img src=' http :/资产/徽标。png ' width=' 30 ' height=' 30 '/I I @ click=' new note ' class=' glyphicon glyphicon-plus '/I I @ click=' toggle收藏夹' class=' glyphicon glyphicon-star ' : class=' { starred : active note。收藏夹} '/I @ click=' delete note ' class=' glyphicon-remove '/I/div/模板脚本导入{新建注释,删除注释,切换./vuex/actions ';从""导入{ activeNote }./vuex/getter ';导出默认的{ vuex : { getter s : { activeNote }、actions: { newNote、deleteNote、toggle收藏夹} }/脚本样式lang=' SCS '作用域#工具栏{左侧浮动:宽度: 80px高度: 100%;背景-颜色: # 30414dcolor : # 767676 padd : 35px 25px 25px 25px .主演{ color : # f7ae 4f } I { font-size : 30px;保证金-底部: 35px光标:指针;opa city 3360 0.8 transition :不透明度0.5s容易;悬停{ opa city 3360 1;} } }/样式在这里,我们用到了Vuex的一个案例就是我们需要知道当前的激活的笔记是否是收藏类别的,如果是,我们需要高亮收藏按钮,那么如何知道呢?那就是通过vuex里面的吸气剂获取当前激活的笔记对象,判断它的最喜爱的是否为真的。
始终牢记一个概念,vuex中数据是单向的,只能从商店获取,而我们这个例子中的activeNote也是始终都在store.js中维护的,这样子就可以给其他组件公用了
//需要维护的状态const state={ notes: [],activeNote: {},show : ' ' };笔记列表。vuetemplate div id=' notes-list ' div id=' list-header ' H2笔记| heavenru.com/h2 div class=' BTN-BTN小组-小组对齐'角色='group '!- all - div class='btn-group '角色='group '按钮类型=' button ' class=' BTN BTN-默认' @ click=' togglesshow(' All ')' : class=' { active : show==' All ' } ' All Notes/button/div!-收藏夹- div class='btn-group '角色='group '按钮类型=' button ' class=' BTN BTN-默认' @ click=' toggleShow('收藏夹)' :class='{active: show=='收藏夹' } '收藏夹/按钮/div /div /div!-渲染笔记列表-div class=' container ' div class=' list-group ' a v-for=' note in filtered notes ' class=' list-group-item ' href=' # ' : class=' { active 3360 activeNote=' note } ' @ click=' updateActiveNote(note)' H4 class=' list-group-item-heading ' { note。标题。trim().substring(0,30)} }/H4/a/div/div/模板脚本导入{ updateActiveNote,updateShow } from './vuex/actions ';从导入{显示,过滤笔记,活动笔记}./vuex/getter ';导出默认值{ vuex: { getters: { show,filteredNotes,activeNote },actions: { updateActiveNote,updateShow } },方法: { toggleShow(show){ this。updateShow(显示);} } }/脚本笔记列表组件,主要有三个操作
渲染笔记切换渲染笔记点击列表标题,切换activeNote
我们通过吸气剂中的过滤笔记方法获取笔记列表
//获取注意列表,这里将会根据状态显示的状态做数据过滤导出常量筛选的注释=(状态)={ if(状态)。show===' all '){返回状态。notes | | { };}else if(state.show==='收藏夹){返回状态。笔记。过滤器(注意=注意。收藏夹)| | { };}};可以看到,我们获取的列表是依赖于状态显示这个状态的。而我们的切换列表操作恰好就是调用行动里面的方法来更新状态。显示,这样一来,实现了数据列表的动态刷新,而且我们对树的操作都是通过调用行动的方法来实现的。
我们再看,在切换列表的时候,我们还需要动态的更新活动便笺。看看我们在store.js中是如何做的:
//切换显示数据列表类型:全部或收藏夹set _ show _ all (state,show) {state。show=显示;//要切换数据显示,需要更新activenote if (show==='收藏夹'){state。active note=state . notes . filter(note=note .收藏夹)[0] | | {}同步;} else { state . activenote=state . notes[0]| | { };}}触发这些操作的是我们将自定义函数绑定到两个按钮上,通过传入不同的参数给函数,然后调用actions中的方法来过滤和更新数据。
编辑. vue
模板div id=' note-editor ' div class=' form-group '输入类型=' text ' name=' title ' class=' title form-control '占位符='请输入一个title ' @ input=' updateNote ' V-model=' currentnote . title ' textarea V-model=' currentnote . content ' name=' content ' class=' form-control ' row=' 3 '占位符='请输入text ' @ input=' updateNote '/textarea/div/template script import { editNote } from './vuex/actions ';从“”导入{ activeNote }./vuex/getter ';export default { vuex 3360 { getter s : { active note },actions : {editnote}},computed : {//一个通过计算属性得到的对象,这样我们就可以愉快地使用v-model,currentnote 3360 activenote},methods : {//我们为什么要这样做?因为在严格模式下,不允许修改update note(){ this }的值。editnote(这。currentnote );}} }/script在Editor.vue组件中,我们需要能够实时更新当前activeNote组件的内容以及我们正在修改的列表中对应的Note对象。
正如我们前面提到的,不允许在组件中直接修改store.js中的状态值,所以在这里,我们通过一个计算属性将store中的状态值赋给一个对象,然后调用action并在用户定义的updateNotes()方法中传入currentNote对象。
在store.js中,我们这样做,找到对应id的对象并重新分配,因为如前所述,我们的数据是有响应的,对应的视图会在这里被刷新和更改,从而实现实时编辑和实时渲染的功能。
//修改note edit _ note (state,note) {state。activenote=note//修改原始数据为(var I=0;I state . notes . length;i ) { if(state.notes[i]。id===note . id){ state . notes[I]=note;打破;} };},QA
在这个项目中,我们没有引入vue-resource插件,而是自己模拟了一些数据,感兴趣的同学可以自己尝试一下。
因为我们的例子比较简单,不涉及太多深入,更深层次的研究需要更多的时间去实践。
最后,假设在实际操作中,我们实际上可以做得更多,比如根据id动态异步获取笔记等。这些感兴趣的学生可以试着稍微丰富一下这个例子。
原地址:https://coligo.io/learn-vuex-by-building-notes-app/
本文已整理成《Vue.js前端组件学习教程》,欢迎大家学习阅读。
以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。