vue3.2+typescript+pinia(todolist案例)
vue3.2+typescript+pinia(todolist案例)
目录
1.安装和导入pinia(用于todolist案例的数据共享)
2.安装elementPlus和sass,sass-loader(进行快速构建页面样式)
4.创建types文件夹,并创建todo.ts的类型规范文件向外共享
6.创建utils模块封装本地存储todolist数据的模块localStorageUtils.ts
8.1.header组件输入框回车后增加数据(这里用到store里面添加数据的方法)
1.在setup语法糖使用toRefs解构(vue3.0的...toRefs())
3.typescript接口在vue的使用 ,快速获取表单数据的v-model指令
4.数组方法(unshift,splice,forEach,filter)
4.1.unshift方法(数组头部加入新数据,push是后面追加)
4.3.forEach遍历数组(可以每次遍历都对数组数据进行操作)
4.4.filter过滤筛选数组得到新数组(数组声明里面的数据类型arr : Array)
基于vite创建vue3.2 + typescript项目
见官网:Vite中文网
npm init vite@latest
1.安装和导入pinia(用于todolist案例的数据共享)
‘’官网:Pinia
npm i pinia -S
在main.ts导入:
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia())
创建store文件夹,并创建todo.ts作为需要数据共享的模块
import { defineStore } from "pinia";
export const todoStore = defineStore('todos', {
state: () => {
return {
}
},
getters: {
},
},
actions: {
}
})
2.安装elementPlus和sass,sass-loader(进行快速构建页面样式)
安装sass-loader和sass
npm i sass sass-loader -S
安装elementPlus:
官网:一个 Vue 3 UI 框架 | Element Plus
npm install element-plus --save
需要安装unplugin-vue-components
和 unplugin-auto-import
这两款插件
npm install -D unplugin-vue-components unplugin-auto-import
参照官网进行安装配置自动按需导入:基于vite的配置
最后在页面测试是否生效。
3.组件化开发todolist
将上面拆分为四个组件
- Header:输入框
- List:任务的容器
- item:任务
- footer:底部信息和按钮
利用elementPlus快速构建页面
4.创建types文件夹,并创建todo.ts的类型规范文件向外共享
/* 定义一个接口,约束state的数据类型 */
export interface Todo {
id: number,
title: string,
isCompleted: boolean
}
5.在store的todo.ts数据共享模块进行初始化数据
具体定义store的方法可以参照pinia官网
import { defineStore } from "pinia";
/* 引入接口 */
import { Todo } from '../types/todo'
export const todoStore = defineStore('todos', {
state: () => {
return {
/* 数据应该用数组来存储,
数组中的每一个数据都是一个对象,
对象中应该有三个属性(id,title,isCompleted) */
todos: [
{ id: 1,title: '迪丽热巴', isCompleted: false},
{ id: 1,title: '迪丽热巴', isCompleted: false},
{ id: 1,title: '迪丽热巴', isCompleted: false}
] as Todo[]
}
},
getters: {
},
},
actions: {
},
})
6.创建utils模块封装本地存储todolist数据的模块localStorageUtils.ts
import { Todo } from "../types/todo";
/* 保存数据到浏览器的缓存中 */
export function saveTodos(todos: Todo[]) {
localStorage.setItem('todos_key', JSON.stringify(todos))
}
/* 从浏览器的缓存中读取数据 */
export function readTodos(): Todo[] {
return JSON.parse(localStorage.getItem('todos_key') || '[]')
}
7.在item组件渲染假数据(利用pinia)
v-for指令
<script setup lang='ts'>
import { todoStore } from "../store/todo";
const store = todoStore()
</script>
<template>
<!-- 鼠标进入和鼠标离开事件 -->
<div class="item" v-for="(todo, index) in store.todos" :key="todo.id">
<el-checkbox :label="todo.title" size="large" v-model="todo.isCompleted" />
<div class="btn">
<el-button type="danger" round size="small">删除</el-button>
</div>
</div>
</template>
8.实现各项功能
8.1.header组件输入框回车后增加数据(这里用到store里面添加数据的方法)
先在store的todo.ts的action节点创建添加数据的方法:
actions: {
/* 添加数据的方法 */
addTodo(todo: Todo) {
this.todos.unshift(todo)
/* 存储数据到本地 */
saveTodos(this.todos)
}
}
store.addTodo(todo)
<script setup lang='ts'>
import { Todo } from '../types/todo'
import { onMounted, ref } from "vue";
import { todoStore } from "../store/todo";
import { readTodos } from "../utils/localStorageUtils";
const store = todoStore()
const title = ref('')
const id = ref(3)
onMounted(() => {
store.todos = readTodos()
})
/* 回车的事件回调函数,用来添加数据 */
const add = () => {
/* 获取到的表单数据 */
const text = title.value
if (!text.trim()) return
/* 此时有数据,创建一个todo对象 */
const todo = {
id: ++id.value,
title: text,
isCompleted: false
} as Todo
/* 调用增加数组数据的方法 */
store.addTodo(todo)
/* 清空文本框 */
title.value = ''
}
</script>
<template>
<el-input placeholder="请输入你的任务,按回车确认" @keyup.enter="add" v-model="title" />
</template>
8.2item组件实现删除数据的功能
同理先在store的todo.ts的action节点创建删除数据的方法:
actions: {
/* 删除数据的方法 */
delTodo(index: number) {
if (window.confirm('确定要删除任务吗?')) {
/* 数组删除元素方法,splice(index,len,[item])
如果len为0则数组不变
*/
this.todos.splice(index, 1)
}
}
}
在item组件:
<script setup lang='ts'>
import { todoStore } from "../store/todo";
const store = todoStore()
</script>
<template>
<!-- 鼠标进入和鼠标离开事件 -->
<div class="item" v-for="(todo, index) in store.todos" :key="todo.id">
<el-checkbox :label="todo.title" size="large" v-model="todo.isCompleted" @change="store.isAllChecked" />
<div class="btn">
<el-button type="danger" round size="small" @click="store.delTodo(index)">删除</el-button>
</div>
</div>
</template>
<style lang='scss'>
.item {
border-bottom: 1px solid #409eff;
position: relative;
.btn {
position: absolute;
right: 0;
bottom: 0;
}
}
.item:hover {
background-color: #aad1f7;
}
</style>
8.3实现其他功能(数组方法和pinia等知识点的应用)
footer组件:
<script setup lang='ts'>
import { todoStore } from "../store/todo";
const store = todoStore()
</script>
<template>
<el-checkbox size="large" v-model="store.status" @change="store.isChecked" /> 已完成 {{ store.isCompleteds }} / 全部 {{
store.todos.length
}}
<el-button type="danger" style="margin-left:120px" @click="store.clearAllCompletedTodos">清除已完成的任务</el-button>
</template>
<style lang='scss' scoped>
</style>
store的todo.ts状态管理模块:
import { defineStore } from "pinia";
/* 引入接口 */
import { Todo } from '../types/todo'
import { saveTodos } from "../utils/localStorageUtils";
export const todoStore = defineStore('todos', {
state: () => {
return {
/* 数据应该用数组来存储,数组中的每一个数据都是一个对象,对象中应该有三个属性(id,title,isCompleted) */
/* 全选状态 */
status: false,
todos: [] as Todo[]
}
},
getters: {
/* 选中个数 */
isCompleteds(state) {
/* 用数组filter方法过滤选择的数据组成新数组 */
const arr: Array<Todo> = state.todos.filter(item => item.isCompleted == true)
/* 返回数组的长度就是数组的多少条数据 */
return arr.length
},
},
actions: {
/* 添加数据的方法 */
addTodo(todo: Todo) {
this.todos.unshift(todo)
/* 存储数据到本地 */
saveTodos(this.todos)
},
/* 删除数据的方法 */
delTodo(index: number) {
if (window.confirm('确定要删除任务吗?')) {
/* 数组删除元素方法,splice(index,len,[item])
如果len为0则数组不变
*/
this.todos.splice(index, 1)
}
},
/* 全选按钮是否选中 */
isChecked() {
if (this.status) {
/* 遍历数组逐个改变其选择状态 */
this.todos.forEach(item => {
item.isCompleted = true
})
} else if (!this.status) {
this.todos.forEach(item => {
item.isCompleted = false
})
}
},
/* 控制全选按钮选中 */
isAllChecked() {
if (this.isCompleteds == this.todos.length) {
this.status = true
} else {
this.status = false
}
},
/* 清除所有选中的数据 */
clearAllCompletedTodos() {
/* 筛选出未选中的数组数据组成新数组 */
const arr: Array<Todo> = this.todos.filter(item => item.isCompleted == false)
this.todos = arr
/* 存储数据到本地 */
saveTodos(this.todos)
}
},
})
效果图:
案例涉及的一些知识点:
1.在setup语法糖使用toRefs解构(vue3.0的...toRefs())
toRefs创建多个ref对象,即响应式供外界使用
在vue3.0中
- return ...toRefs(对象名)
- 这样在模板中就可以直接title这样使用,不用再使用state.todos,直接todos就行
在vue3.2setup语法糖中没有return则需要改变写法,如下:
import { reactive, toRefs } from "vue"
const state = reactive<{ todos: Todo[] }>({
todos:[
{ id: 1,title: '迪丽热巴', isCompleted: false},
{ id: 1,title: '迪丽热巴', isCompleted: false},
{ id: 1,title: '迪丽热巴', isCompleted: false}
]
})
//vue3.0的写法:
return{
...toRefs(state)
}
//vue3.2setup语法糖写法,因为语法糖没有return
/* 第一种写法 */
let { todos } = toRefs(state)
/* 第二种写法 */
let todos = toRefs(state).todos
2.defineProps的写法
/* 第一种类型写法 */
defineProps<{ todos: Array<Todo> }>()
/* 第二种写法 */
defineProps({
todos: Array<Todo>
})
3.typescript接口在vue的使用 ,快速获取表单数据的v-model指令
定义接口的ts文件:
/* 定义一个接口,约束state的数据类型 */
export interface Todo {
id: number,
title: string,
isCompleted: boolean
}
在组件内使用:
<script setup lang='ts'>
import { Todo } from '../types/todo'
import { ref } from "vue";
const title = ref('')
const id = ref(3)
/* 回车的事件回调函数,用来添加数据 */
const add = () => {
/* 获取到的表单数据 */
const text = title.value
if (!text.trim()) return
/* 此时有数据,创建一个todo对象 */
const todo = {
id: ++id.value,
title: text,
isCompleted: false
} as Todo
/* 清空文本框 */
title.value = ''
}
</script>
<template>
<el-input placeholder="请输入你的任务,按回车确认" @keyup.enter="add" v-model="title" />
</template>
4.数组方法(unshift,splice,forEach,filter)
4.1.unshift方法(数组头部加入新数据,push是后面追加)
arr.unshift(数据)
4.2.splice方法:数组删除元素方法
数组删除元素方法,splice(index,len,[item]),如果len为0则数组不变
arr.splice(索引, 1)
4.3.forEach遍历数组(可以每次遍历都对数组数据进行操作)
/* 遍历数组逐个改变其选择状态 */
this.todos.forEach(item => {
item.isCompleted = true
})
4.4.filter过滤筛选数组得到新数组(数组声明里面的数据类型arr : Array<string>)
const 新数组 = arr.filter(循环数组每一项=>筛选条件)
/* 清除所有选中的数据 */
clearAllCompletedTodos() {
/* 筛选出未选中的数组数据组成新数组 */
const arr: Array<Todo> = this.todos.filter(item => item.isCompleted == false)
this.todos = arr
/* 存储数据到本地 */
saveTodos(this.todos)
}
更多推荐
所有评论(0)