一、写在前面+效果图 二、Vuex 2.1 Codepen:html+js+css 2.1.1 一个可能更加通顺的思路 2.2 本地:App.vue,components/component1.vue,store/index.js
写在前面+效果图 本次是探索性质,肯定有一定差错和不足,我会继续学习。
不做详细的vue和vuex语法、功能介绍,因为官方文档讲得比我清楚,我主要是提供撰写的顺序思路,以及完整的代码。
目录在上面,自取所需。
效果图:
Vuex Codepen:html+js+css 如何在这个界面使用vuex?只需要在html里写上:
<script src ="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js" > </script > <script src ="https://cdn.jsdelivr.net/npm/vuex@3.6.2/dist/vuex.js" > </script >
codepen这里的意思就是不分文件层级,所有js都在一个js里,html、css也是,确实很简洁。
一个可能更加通顺的思路 对于js部分,首先把框架写出来,三个部分:new Vue、vue的组件、Vuex部分:
Const store = new Vuex .Store ({ mutations :{ }, getters :{ }, actions :{ }, }); vue.component ('c1' ,{ template :` ` , data ( ){ }, computed ( ){ }, methods :{ }, }); vue.component ('c2' ,{ }); New Vue ({ el : '#app' , store, created ( ){ this .$store .commit ("loadTodos" ); } });
然后,根据界面里有什么,构想各个component应该长什么样,譬如我认为,我需要一个header,还需要一个content。
html:对的,用组件就这么简单明了。
<div id ="app" > <header-component > </header-component > <content-component > </content-component > </div > <script src ="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js" > </script > <script src ="https://cdn.jsdelivr.net/npm/vuex@3.6.2/dist/vuex.js" > </script >
根据html设计思路,在Vue.component里填写template内容:譬如div、button
,以及一些要用的变量,一开始只写个框,譬如<button>增加</button>,{{total}}
,先不考虑这个变量存不存在,以便于排除冗杂的信息;
接着,根据文字说明,具体地填写功能,譬如我要实现增加,我就要点这个按钮调用函数,所以我扩充为<button @click="addTodo">增加</button>
:
Vue.component("header-component", { template: ` <div class ="header" > <div class ="filter" > <button @click ="myFilter('all')" > 全部</button > <button @click ="myFilter('finished')" > 已完成</button > <button @click ="myFilter('not-finished')" > 未完成</button > <span > 总共{{ total }}条,已完成{{ completed }}条,剩余{{ remaining }}条</span > <button @click ="clearCompleted" > 清除已完成</button > <button @click ="checkAll" > 全部完成</button > <button class ="headerAdd" @click ="addTodo" > 增加新的TODO</button > </div > </div > `, // 以下省略 }
既然写了一些想实现的方法,譬如addTodo,那么接下来就在各个component的methods里写上要让vuex调用数据驱动的方法的大概样子(有点像先写个抽象类,之后再完善),格式都是this.$store.commit(‘vuex里的方法名’,要传的变量);
变量也是如此,在computed里写。vuex里已有的变量用this.$store.state,要计算的变量用this.$store.getters(这个目前还不知道要不要计算,所以先写一个试试)
那么现在vue的部分完成了,要写vuex了。根据之前的这些commit、state、getters的内容,填充Vuex,先写mutation,再写getters,过程中会发现需要变量,就往state里加。大概长图片那样
mutations和getters:每个函数的第一个变量都是state,修改state{}里的数据必须用这个前缀;第二个开始的参数是传入的,根据之前写的来
具体功能就在这里实现,这就是数据驱动的精妙之处,具体的操作都让vuex执行,不用vue的component之前传来传去的麻烦
getters需要return,之前的computed也要写return,别忘了就是。
最后,进行功能检查:getters和computed用对了吗,dispatch和commit用对了吗,其他各种检查。那么vuex的功能差不多也完成了。
codepen这种情况下的总体代码:
html里:
<div id ="app" > <header-component > </header-component > <content-component > </content-component > </div > <script src ="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js" > </script > <script src ="https://cdn.jsdelivr.net/npm/vuex@3.6.2/dist/vuex.js" > </script >
js里:
Vue .component ("header-component" , { template : ` <div class="header"> <div class="filter"> <button @click="myFilter('all')">全部</button> <button @click="myFilter('finished')">已完成</button> <button @click="myFilter('not-finished')">未完成</button> <span>总共{{ total }}条,已完成{{ completed }}条,剩余{{ remaining }}条</span> <button @click="clearCompleted">清除已完成</button> <button @click="checkAll">全部完成</button> <button class="headerAdd" @click="addTodo">增加新的TODO</button> </div> </div> ` , computed : { total ( ) { return this .$store .state .todoList .length ; }, completed ( ) { return this .$store .getters .completed ; }, remaining ( ) { return this .$store .getters .remaining ; } }, methods : { myFilter (status ) { this .$store .commit ("setFilterStatus" , status); }, clearCompleted ( ) { this .$store .commit ("clearCompleted" ); }, checkAll ( ) { this .$store .commit ("checkAll" ); }, addTodo ( ) { this .$store .commit ("addTodo" ); } } }); Vue .component ("content-component" , { template : ` <div class="content"> <div class="todo-item" v-for="(item, index) in filteredTodoList" :key="item.id" transition="zj"> <input class="checkbox" type="checkbox" @click="check(index, item.id)" v-model="item.isChecked"> <input class="item-input" v-model="item.text" type="text" :disabled="item.isChecked" @blur="handleBlur()"> <input type="datetime-local" v-model="item.time" @blur="handleBlur"> <button @click="removeTodo(index, item.id)">删除</button> </div> </div> ` , computed : { filteredTodoList ( ) { return this .$store .getters .filteredTodoList ; } }, methods : { check (index, id ) { this .$store .commit ("check" , { index, id }); }, removeTodo (index, id ) { this .$store .commit ("removeTodo" , { index, id }); }, handleBlur ( ) { this .$store .commit ("saveTodos" ); } } }); const store = new Vuex .Store ({ state : { todoList : [], filterStatus : "all" }, getters : { filteredTodoList (state ) { if (state.filterStatus === "finished" ) { return state.todoList .filter ((item ) => item.isChecked ); } else if (state.filterStatus === "not-finished" ) { return state.todoList .filter ((item ) => !item.isChecked ); } else { return state.todoList ; } }, total (state ) { return state.todoList .length ; }, completed (state ) { return state.todoList .filter ((item ) => item.isChecked ).length ; }, remaining (state ) { return state.todoList .filter ((item ) => !item.isChecked ).length ; } }, mutations : { setFilterStatus (state, status ) { state.filterStatus = status; }, addTodo (state ) { state.todoList .unshift ({ id : Number (Math .random ().toString ().substr (2 , 10 ) + Date .now ()).toString ( 10 ), isChecked : false , text : "" , time : new Date ().toISOString ().slice (0 , 16 ) }); localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); }, removeTodo (state, { index, id } ) { if (state.todoList [index].id === id) { state.todoList .splice (index, 1 ); localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); } }, check (state, { index, id } ) { if (state.todoList [index].id === id) { state.todoList [index].isChecked = !state.todoList [index].isChecked ; localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); } }, checkAll (state ) { state.todoList .forEach ((item ) => { item.isChecked = true ; }); localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); }, clearCompleted (state ) { state.todoList = state.todoList .filter ((item ) => !item.isChecked ); localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); }, saveTodos (state ) { localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); }, loadTodos (state ) { const tmp = localStorage .getItem ("todoList1" ); if (tmp) { state.todoList = JSON .parse (tmp); } else { state.todoList = [ { id : Number (Math .random ().toString ().substr (2 , 10 ) + Date .now ()).toString ( 10 ), text : "请点击上方的添加按钮添加事件" , isChecked : false , time : new Date ().toISOString ().slice (0 , 16 ) } ]; } } } }); new Vue ({ el : "#app" , store, created ( ) { this .$store .commit ("loadTodos" ); } });
css部分请自由发挥。
本地:App.vue,components/component1.vue,store/index.js,main.js 内容还是基本一样的,本地的问题主要是看东西放在哪个文件夹。
首先你得装了vue;然后在一个文件夹启动环境;而且要在同一个文件夹装vuex。
这样的话,你将会看到的结构:(TEST_VUE是根目录;store文件夹本来没有,自己建一个。)
App.vue同级还需要一个main.js:
请看各个文件
App.vue几乎完全一样:
<template > <div id ="app" > <header-component > </header-component > <content-component > </content-component > </div > </template > <style > </style >
store/index.js:放的是vuex的东西,记得import和Vue.use(vuex)
注意export default new Vuex.Store代替了之前的new store = Vuex.Store,不改的话会报错:We‘re sorry but doesn’t work properly without JavaScript enabled. Please enable it to continue
import Vue from 'vue' import Vuex from 'vuex' Vue .use (Vuex )export default new Vuex .Store ({ state : { todoList : [], filterStatus : "all" }, getters : { filteredTodoList (state ) { if (state.filterStatus === "finished" ) { return state.todoList .filter ((item ) => item.isChecked ); } else if (state.filterStatus === "not-finished" ) { return state.todoList .filter ((item ) => !item.isChecked ); } else { return state.todoList ; } }, total (state ) { return state.todoList .length ; }, completed (state ) { return state.todoList .filter ((item ) => item.isChecked ).length ; }, remaining (state ) { return state.todoList .filter ((item ) => !item.isChecked ).length ; } }, mutations : { setFilterStatus (state, status ) { state.filterStatus = status; }, addTodo (state ) { state.todoList .unshift ({ id : Number (Math .random ().toString ().substr (2 , 10 ) + Date .now ()).toString ( 10 ), isChecked : false , text : "" , time : new Date ().toISOString ().slice (0 , 16 ) }); localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); }, removeTodo (state, { index, id } ) { if (state.todoList [index].id === id) { state.todoList .splice (index, 1 ); localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); } }, check (state, { index, id } ) { if (state.todoList [index].id === id) { state.todoList [index].isChecked = !state.todoList [index].isChecked ; localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); } }, checkAll (state ) { state.todoList .forEach ((item ) => { item.isChecked = true ; }); localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); }, clearCompleted (state ) { state.todoList = state.todoList .filter ((item ) => !item.isChecked ); localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); }, saveTodos (state ) { localStorage .setItem ("todoList1" , JSON .stringify (state.todoList )); }, loadTodos (state ) { const tmp = localStorage .getItem ("todoList1" ); if (tmp) { state.todoList = JSON .parse (tmp); } else { state.todoList = [ { id : Number (Math .random ().toString ().substr (2 , 10 ) + Date .now ()).toString ( 10 ), text : "请点击上方的添加按钮添加事件" , isChecked : false , time : new Date ().toISOString ().slice (0 , 16 ) } ]; } } } });
main.js:注意下面的东西路径正确,注意header-component是最终使用在html的名字,不能写错;注意这里用了mount,和之前不一样了
import Vue from 'vue' ;import store from './store/index.js' ;import app from './App.vue' ;import HeaderComponent from './components/header.vue' ;import ContentComponent from './components/content.vue' ;Vue .component ('header-component' , HeaderComponent );Vue .component ('content-component' , ContentComponent );new Vue ({ store, render : (h ) => h (app) }).$mount('#app' );
components/content.vue:注意export default的变化。header那个也类似地调整一下。
<template > <div class ="content" > <div class ="todo-item" v-for ="(item, index) in filteredTodoList" :key ="item.id" transition ="zj" > <input class ="todo-item__checkbox" type ="checkbox" @click ="check(index, item.id)" v-model ="item.isChecked" > <input class ="todo-item__item-input" v-model ="item.text" type ="text" :disabled ="item.isChecked" @blur ="handleBlur()" > <input type ="todo-item__datetime-local" v-model ="item.time" @blur ="handleBlur" > <button @click ="removeTodo(index, item.id)" > 删除</button > </div > </div > </template > <script > export default { computed : { filteredTodoList ( ) { return this .$store .getters .filteredTodoList ; } }, methods : { check (index, id ) { this .$store .commit ("check" , { index, id }); }, removeTodo (index, id ) { this .$store .commit ("removeTodo" , { index, id }); }, handleBlur ( ) { this .$store .commit ("saveTodos" ); } } }; </script > <style > </style >
差不多就完成了。
其他的具体配置我也不懂了,主要还是跟着其他人的教程进行安装,有问题就找攻略修。希望大家都写得顺利!