Vite官网:开始 | Vite 官方中文文档镜像
Vuex官网:Vuex 是什么? | Vuex
本文章有用到Vue3+Vite+Vuex相关技术,不懂的地方可以查看相关文档。
使用Vite创建Vue3项目相关npm yarn 在此不多演示,此文章提供相关技术代码,安装方式可见Vue官方文档。
上图为创建完项目的目录和Vuex官网基本思想(其中store为自行创建,因为要用Vuex)
Vuex的五种属性,基本用法:
1、state: vuex的基本数据,用来存储变量;
2、getters: 从基本数据(state)派生的数据,相当于state的计算属性;
3、mutations: 提交更新数据的方法,是同步的(异步使用action)。
4、action: 可以异步,但不能直接操作State
5、modules: Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter。
项目截图
接下来在store内创建index.js
store/index.js
// const { createStore } = require("vuex");
const store = createStore({
state: {
todos: [
{
id: 1,
title: '抽烟',
done: true,
},
{
id: 2,
title: '喝酒',
done: false,
},
{
id: 3,
title: '打麻将',
done: false,
},
],
state: 'all',
visible: 'all',
},
getters: {
all(state) {
return state.todos;
},
active(state) {
return state.todos.filter((todo) => !todo.done);
},
done(state) {
return state.todos.filter((todo) => todo.done);
},
filterTodo(state) {
if (state.state == 'all') {
return state.todos;
} else if (state.state == 'active') {
return state.todos.filter((todo) => !todo.done);
} else if (state.state == 'complete') {
return state.todos.filter((todo) => todo.done);
}
},
},
mutations: {
createTodo(state, payload) {
console.log(state, payload);
state.todos.push(payload);
},
removeTodo(state, payload) {
state.todos = state.todos.filter((todo) => todo.id != payload.id);
},
clearTodo(state, payload) {
let todos = state.todos;
for (let index = todos.length - 1; index >= 0; index--) {
const todo = todos[index];
if (todo.done) {
todos.splice(index, 1);
}
}
},
changeTodo(state, payload) {
state.state = payload;
state.visible = payload;
console.log('state.visible', state.visible);
},
},
actions: {
removeTodo({ commit }, payload) {
setTimeout(() => {
commit('removeTodo', payload);
}, 100);
},
},
});
export default store;
App.vue(在App.vue中引用组件)
<template>
<div id="todoapp">
<todo-header />
<div class="content">
<!-- <todo-create @createTodo="createTodo"/> -->
<todo-create :createTodo="createTodo" />
<todo-list :todos="todos" />
<todo-footer :todos="todos" :clearDone="clearDone" />
</div>
</div>
</template>
<script setup>
import { computed, provide } from '@vue/runtime-core';
import { useStore } from 'vuex';
const store = useStore();
let todos = computed(() => store.getters.filterTodo);
console.log(todos);
const createTodo = (title) => {
console.log('createTodo', title);
const todo = {
id: Math.random(),
title,
done: false,
};
store.commit('createTodo', todo);
};
const deleteTodo = (id) => {
store.dispatch('removeTodo', { id });
};
const clearDone = () => {
store.commit('clearTodo');
};
console.log(todos);
provide('deleteTodo', deleteTodo);
</script>
<style scoped></style>
Components/TodoCreate.vue(用来显示输入框)
<template>
<div id="create-todo">
<input
id="new-todo"
placeholder="请输入任务,按回车键确认"
autocomplete="off"
type="text"
v-model="newTodo"
@keyup.enter="handleCreateTodo"
/>
</div>
</template>
<script setup>
let newTodo = ref('')
let props = defineProps({
createTodo: Function,
})
const handleCreateTodo = ()=>{
console.log('props',props);
let title = newTodo.value.trim()
if (title.length > 0) {
console.log("handleCreateTodo", title);
props.createTodo(title);
newTodo.value = "";
} else {
alert("输入不能为空");
}
}
</script>
<style lang="scss" scoped>
</style>
Components/TodoHeader(只用来显示头部Todos)
<template>
<div class="title">
<h1>Todos</h1>
</div>
</template>
<script>
export default {
// name: "TodoHeader",
setup() {
return {};
},
};
</script>
<style scoped>
</style>
Components/TodoList(引用todoItem展示todos信息)
<template>
<ul id="todo-list">
<todo-item v-for="todo in todos" :key="todo.id" :todo="todo"> </todo-item>
</ul>
</template>
<script setup>
defineProps({
todos:Array,
});
</script>
<style lang="scss" scoped>
</style>
Components/TodoItem.vue(展示添加的todos信息)
<template>
<li>
<div class="todo" :class="{ done: todo.done }">
<div class="display">
<input class="check" type="checkbox" v-model="todo.done" />
<div class="todo-content">{{ todo.title }}</div>
<span class="todo-destroy" @click="handleDeleteTodo(todo.id)"></span>
</div>
</div>
</li>
</template>
<script setup>
const deleteTodo = inject('deleteTodo')
const props = defineProps({
todo: Object,
});
const handleDeleteTodo = (id) => {
deleteTodo(id);
};
</script>
<style lang="scss" scoped>
</style>
Components/TodoFooter.vue(显示底部信息,展示未完成已完成的,清除全部已完成的)
<template>
<div id="todo-stats">
<span class="todo-count">
<span class="number">{{ undone }}</span>
<span class="word">项待完成</span>
</span>
<span class="todo-filter">
<todo-filter />
</span>
<span>
<Status></Status>
</span>
<span class="todo-clear">
<a @click="clearDone()">
Clear <span>{{ done }}</span> 已完成事项
</a>
</span>
</div>
</template>
<script setup>
import { computed } from '@vue/runtime-core';
const props = defineProps({
todos: {
type: Array,
required: true,
},
clearDone: Function,
changeStatus: Function,
});
const done = computed(() => {
return props.todos.filter((item) => item.done == true).length;
});
const undone = computed(() => {
return props.todos.filter((item) => item.done == false).length;
});
</script>
<style lang="scss" scoped></style>
Components/State.vue(用来显示全部、未完成、已完成。)
<template>
<a>
<span
@click="changeStatus('all')"
:class="{ active: store.state.visible == 'all' }"
>
全部
</span>
<span
@click="changeStatus('active')"
:class="{ active: store.state.visible == 'active' }"
>未完成</span
>
<span
@click="changeStatus('complete')"
:class="{ active: store.state.visible == 'complete' }"
>已完成</span
>
</a>
</template>
<script setup>
import { computed, provide } from '@vue/runtime-core';
import { useStore } from 'vuex';
const store = useStore();
let visible = store.state.visible;
const changeStatus = (state) => {
store.commit('changeTodo', state);
visible = state;
console.log(store.state.visible);
};
const props = defineProps({
changeStatus: Function,
});
</script>
<style scoped>
span {
padding: 7px;
padding-left: 10px;
padding-right: 10px;
border: 1px solid white;
margin-left: 2px;
}
span:nth-child(1) {
margin-left: 70px;
}
span:hover {
cursor: pointer;
border: 1px solid rgb(187, 187, 187);
border-radius: 10px;
background-color: rgb(244, 244, 244);
}
.active {
border: 1px solid rgb(187, 187, 187);
border-radius: 10px;
background-color: rgb(244, 244, 244);
}
</style>