1. 基础配置(vite版本)
第一步配置 ![[Pasted image 20221030232813.png]]
- 第二步配置(告诉vue单文件 @路径) ![[Pasted image 20221030233235.png]]
2.拆分组件
- 拆分组件
- 引入组件到App组件中
- 使用组件 ![[Pasted image 20221030234210.png]]
3.动态页面(初始化动态数据)
1.在App组件使用ref定义动态数据
- 引入ref
- 使用ref定义数据 这样的数据具有响应式
import {ref} from 'vue'
const todolist = ref([
{id:1,count:'抽烟',isOver:false}, //是否选中?
{id:1,count:'喝酒',isOver:true},
{id:1,count:'烫头',isOver:false}
])
2.传递数据到Main组件
App.vue
<Main :todolist="todolist"></Main>
Main.vue
- 通过props接收*
//遍历数据
<Item v-for="(item,index) in todolist" :key="index"></Item>
//在模板中操作数据 可以直接写
//在ts代码逻辑中需要 props.xxxx
const props = defineProps(['todolist'])
3.定义数据类型(做类型限制)
- 定义的是对象类型,用interface
- 定义复合类型 一般用type >1.定义数据类型 ![[Pasted image 20221101093137.png]]
2.子组件接收数据(对数据进行类型限定) ![[Pasted image 20221101094417.png]]
//接收数据,进行类型限定
//1.原始写法
interface PropsData{ //定义接口
todoList : TodolistData
}
const props = defineProps<TodolistData>()
//2.进阶写法
const props = defineProps<{
todoList:todoListData
}>()
3.将数据传递到各组件
- App=> Main ![[Pasted image 20221102095338.png]]
- Main=> Item ![[Pasted image 20221102095620.png]]
- App =>Footer* ![[Pasted image 20221102100017.png]]
4.Footer 组件中
- 通过计算属性 计算出 全部的数量 已完成的数量
//使用计算属性 计算
const overNum = computed(()=>{
return props.todoList.reduce((prev:number,item:TodoData)=>{
if (item.isOver){//计算 已完成 如果被选中就是 已完成
prev +=1
}
return prev
},0)
- 通过计算属性计算属性 计算出是否全选
//使用计算属性 计算是否全选 可读可写传递的是对象
const isCheckAll = computed({
get(){//这里 类型都是 布尔值 ts是强类型 和之前无关
return props.todoList.every(item=>item.isOver) && props.todoList.length > 0 //数组方法 要是声明类型 就得加括号
},
set(){}
})
4.交互之添加 todo
1.收集数据
- 定义ref数据 通过v-model双向绑定实时收集数据
- 判断输入的类型是否为空
//紧接着 我们就要判断 传入的数据是否是空的
const addT = () =>{
if(content.value && content.value.trim()){
//此处的字符串trim方法去除两侧空格,如果为空 去除空格后就是空的
let obj = {
id:Date.now(),
content:content.value,
isOver:false
}
}
}
2.回车事件
* 输入内容 按下回车之后添加到列表里面
* 通过回车事件 来搞定这一步操作
//接收定义好的函数 确定它的类型
const props = defineProps<{
addTodo(todo:TodoData):void, //接收函数以及定义它的类型
//addTodo:()=>void
}>()
const addT = () =>{
if(content.value && content.value.trim()){
//此处的字符串trim方法去除两侧空格,如果为空 去除空格后就是空的
let obj = {
id:Date.now(),
content:content.value,
isOver:false
}
}
//把定义好的 数据类型 在传回父组件
props.addTodo(obj)
}
3.总结逻辑
- 输入 回车 显示而且添加在最前面
- 首先 收集数据 : 你输进去的收集到
- 判断输入的是否为空
- 如果是空的 报错
- 如果不是空的 把它添加到列表里面 (定义添加进去的类型 )*
- 按下回车 数据会添加到 列表的最前面
- 要添加的数据类型 要通过props 拿到*
- 再把要添加的数据类型 传到父组件
注意 : header中通过props 拿到 addtodo 这个函数, 此时我们已经定义好数据obj传参,通过 props.addtodo(obj) 调用这个函数
实现 添加功能
本质就是一个通过传参改变属性的过程
5.交互之删除高亮
1.删除原来的
- 删掉原来的样式
- 删掉原来的css*
2.给删除按钮设置 v-show
- 定义isshow 为ref响应式数据 放false*
3.给li绑定移入移出事件
- @mouseenter="isShow=true" @mouseleave="isShow=false"*
4.给li设置高亮样式
强制绑定 class css &.active { background-color: hotpink;} js :class="{ active: isShow }"
6.交互之修改单选框
核心就是 通过在下标 修改单选框是否被选中 各组件之间传递的就是 下标
1.点击事件
- 设置点击事件 定义函数 updataT
2.传递参数index
把下标index(item)=>(main)=>(app) 组件之间传递 最后修改isOver
- 我们需要下标 就得传递过来 通过props拿到这个函数 同时他携带参数index(下标)
- 在定义的点击事件中 props.updateOneTodo(props.index)
- 通过调用函数 把下标传进去 传到父组件(main)中* * 且在main组件中定义函数类型 *updataone():void updataoentodo:()=>void ![[Pasted image 20221102100813.png]]
- 后面操作都与其类似 顾不细说明*
7.删除操作
- 把下标index(item)=>(main)=>(app) 组件之间传递
- 也是通过传递参数 index 通过删除index 删除这个数据*
- 一层一层传递*
8.全选全不选
- v-model 双向数据绑定 对这一项操作之后 遍历每一项 让每一项操作一样*
- 或选中或不选中
- 得通过计算属性 算出来的
- 通过set去修改 计算出新的属性
- 接收函数 传递参数* ![[Pasted image 20221102101503.png]]
9.清除已完成
![[Pasted image 20221102101224.png]]
10.本地化存储
- 需要去用watch监视 是否发生变化 一旦变化就把变化的数据存储起来
- 这里的数据是数组类型 所以要深度监视 ![[Pasted image 20221102094010.png]]
11.总结
- 1、数据在哪,修改数据的方法就在哪
- 2、数据从父组件传递给子组件,无论传递的是基本值还是对象地址,都是让子组件去使用的,而不是让你去修改的
- 3、props接收到的数据相当于是子组件data当中的数据
- 但是最大的区别就是data的数据,子组件可以随意改 而父组件传递过来的数据,不能在子组件修改,如果非要对传递过来的数据进行修改 那么可以根据传递过来的数据,计算自己的一份数据,然后可以修改,修改的时候修改的是自己计算的属性数据 在计算的属性数据当中set,里面也不能直接操作传递过来的数据,得调用传过来的方法去修改