熟悉Vue3常见的父子通信用法:
Tabs1: Props 和 Emits
Tabs2: ref 标识绑定子组件,子组件 Expose 暴露方法供父组件使用
Tabs3: provide 和 inject
01. Tabs1-表格功能的实现
Element-plus
<el-tabs> 作为框架 基于tab进行3个页面的切换
<el-tab-pane label="tabs1">
内容展示的位置(子组件)
<Tabs1 />
</el-tab-pane>
</el-tabs>
1. 列表基本渲染
子组件三部分:el-form 包裹,双向绑定 input 表单数据,为模糊搜索提供先决条件;表格 el-table 绑定数据;el-pagination 实现分页。
父组件定义数组 dataList, props 传至子组件。表格 el-table 绑定 pagedDataList,渲染基本页面。
2. 功能实现(纯前端)
2.1 分页的实现:
由于基于已有数据 dataList 实现分页,我选择使用 computed 属性 实现 pagedDataList。
需要得到起始位置和结束位置,slice(start, end) 方法返回一个新数组。
javascript
const pagedDataList = computed(() => {
const startIndex = (params.page - 1) * params.pageSize
const endIndex = startIndex + params.pageSize
return props.dataList?.slice(startIndex, endIndex)
})
el-pagination 提供了 current-change 事件,携带参数为当前页。
属性值 handleChange 方法中 形参传给页码 params.page ==> 致使 索引 startIndex 和 endIndex 改变,截取的数组改变 ==> 渲染到表格的数据改变 ==> 实现分页
2.2 查询按钮:
纯前端实现模糊查找
表单收集数据,查询按钮 doSearch() 方法使用四个变量存储筛选条件。
我的想法:
虽然表格页面由 pagedDataList 渲染,看似我们要对分页列表进行筛选,但我们选择原数组 dataList 进行筛选更为简单,最后得到的数据分页列表还会基于 computed 得到。
由于每次筛选都要基于原数组,而不能将过滤后的数据赋值给原数组 dataList,所以想到父组件 onMounted 中给 dataList存一份 localStorage,子组件 doSearch() 中每次筛选就可以 localStorage.getItem() 取得原列表,别忘了取得的是字符串,还要用 JSON.parse()包裹得到数组。
我没有想出更好的办法,选择四个 if 判断。每个关键词存在都要 筛选后赋值给 filteredList,筛选的最终列表通过 emit 赋值给父组件提供的 dataList ,分页列表随之变化,得到模糊查找的列表啦!!!
javascript
const doSearch = () => {
const keyword1 = state.username.trim()
const keyword2 = state.gender
const keyword3 = state.status
const keyword4 = state.date
const list = JSON.parse(localStorage.getItem('list') as string)
let filteredList = [...list]
if (keyword1) {
filteredList = filteredList.filter((item:any) => item.name.includes(keyword1);
}
if (keyword2) {
filteredList = filteredList.filter((item:any) => item.gender === keyword2);
}
if (keyword3) {
filteredList = filteredList.filter((item:any) => item.status === keyword3);
}
if (keyword4) {
filteredList = filteredList.filter((item:any) => item.date.includes(keyword4))
}
emit('changeList', filteredList)
}
2.3 新增按钮
el-dialog 配置 v-if="dialogVisible" ,默认 false,包裹 form 表单,以供填写。新增按钮绑定方法,设置 dialogVisible 为 true。
弹框表单需要做校验,根据饿了吗UI库提供的方法,配置 rules, 还需要给 form 表单绑定一个 ref 属性,确认添加时作为参数传递,validate() 方法 通过则在父组件传递的 dataList 列表数组首个添加,便于检查是否成功。
考虑到之后删除需要id,dataList 原数组中已配置好id。新增数组个人随意的外部定义了一个变量 let nextId = props.dataList.length,则就通过长度配置id。
typescript
const confirmAdd = (ruleFormRef:any) => {
ruleFormRef.validate((flag:boolean) => {
if(!flag) {
ElMessage.warning('不完整,提交不合法!')
return
}
props.dataList?.unshift({...ruleForm, id: `asd${nextId}`})
nextId.value++
// console.log('确认提交')
dialogVisible.value = false
}
})
}
2.4 批量删除按钮
使用组件库,要首先考虑有没有现成的方法可以使用。基于表格实现的批量删除,首先在表格中找有没有方法。
发现 selection-change 事件 自定义属性值 handleSelectionChange 方法,打印参数,发现是数组。选择用 const selectedVal = ref([]) 变量接收。
由于根据 id 做筛选 (filter) 删除 ==> 需要对勾选的变量数组 map 遍历 return 返回 ids 数组 ==> filter() 方法满足条件为true 保留 ==> ids.includes(item.id) 包含(true) 则属于被删除数据,我们要保留未勾选的,所以加 ! 筛选出剩余列表 updatedList ==> emit 赋值给父组件 dataList。
typescript
// 勾选删除数据
const selectionVal = ref([])
const handleSelectionChange = (val:any) => {
// console.log(val)
selectionVal.value = val
console.log(selectionVal.value)
}
// 批量删除
const batchDeletion = () => {
if (selectionVal.value.length === 0) {
ElMessage.warning('请选择要删除的数据!')
return
}
const selectedIds = (selectionVal.value as {id: any} []).map((item) => item.id)
const updatedList = props.dataList?.filter((item:any) => !selectedIds.includes(item.id))
selectionVal.value = []
emit('changeList', updatedList)
ElMessage.success('批量删除成功!')
}
2.5 表格每行的插槽-删除操作
单个删除使用插槽比较方便。 table 绑定了 :data="pagedDataList",所以操作一栏使用template作用域插槽包裹 删除 button,具体如下。
javascript
<el-table-column label="操作">
<template #default="{row}">
<el-button link type="primary" size="small" @click="deletion(row.id)">删除</el-button>
</template>
</el-table-column>
javascript
const deletion = (id:any) => {
// console.log(id)
const newList = props.dataList?.filter((item:any) => item.id !== id)
emit('changeList', newList)
ElMessage.success('删除成功!')
}
02. Tabs2-走马灯的添加和删除
由于目的是为熟悉 ref 标识的用法,添加、删除按钮在父组件中渲染。Vue3 中 ref 标识使用只需声明时名字和组件中属性值一致,而不再用 this.$refs. 的方法( Vue2 ) 获取组件实例。
csharp
const carouselRef = ref<any>(null)
1.添加
想法为点击实现单个添加在尾部。数组的 push 方法可以实现。
javascript
// 添加幻灯片
const addItem = () => {
const newItem = `新增内容${list.length + 1}`
list.push(newItem)
}
2.删除
通常想到删除,肯定需要通过id或索引才能精准删除。查看饿了吗组件库提供的 carousel 组件,提供了change 方法。可以发现提供了当前幻灯片的索引,那我们就需要定义一个全局变量接收当前索引。同样 splice 方法实现删除。
javascript
const current_item = ref(0)
const handleChange = (newVal:any) => {
// console.log(oldVal, newVal)
current_item.value = newVal
}
// 删除幻灯片
const delItem = () => {
// console.log('删除')
if (list.length <= 1) return
// console.log(current_item.value)
list.splice(current_item.value, 1)
}
// 最后再暴露出方法供父组件按钮调用
defineExpose({
addItem,
delItem
})
// ========================父组件中:
const addCarousel = () => {
if(carouselRef.value) {
carouselRef.value.addItem()
}
}
const delCarousel = () => {
if(carouselRef.value) {
carouselRef.value.delItem()
}
}
03. Tabs3-树形控件(Tree)的基本使用
该案例中父组件使用了 provide('唯一标识key', 数据) 传递数据,子组件 inject 通过唯一标识 key 接收。
具体用法查看vuejs官方文档。
要用好组件库,仔细看文档一定少不了。
我想实现的是拖拽功能和默认展开所有节点,属于组件自带属性,直接使用就可以了。
以上就是我完成的一些小玩具,欢迎大家提出宝贵的想法和建议。