TodoList:记初次Vuex探索(本地+Codepen)(使用component)(版本:vue2, vuex3)

目录

写在前面+效果图

Vuex

Codepen:html+js+css

一个可能更加通顺的思路

本地: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里加。大概长图片那样

  1. mutations和getters:每个函数的第一个变量都是state,修改state{}里的数据必须用这个前缀;第二个开始的参数是传入的,根据之前写的来
  2. 具体功能就在这里实现,这就是数据驱动的精妙之处,具体的操作都让vuex执行,不用vue的component之前传来传去的麻烦
  3. 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>

差不多就完成了。

其他的具体配置我也不懂了,主要还是跟着其他人的教程进行安装,有问题就找攻略修。希望大家都写得顺利!

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值