码农之家

Vue3 + Element-Plus 小练习(纯前端的分页列表、走马灯及树形控件)

熟悉Vue3常见的父子通信用法:

Tabs1: Props 和 Emits

Tabs2: ref 标识绑定子组件,子组件 Expose 暴露方法供父组件使用

Tabs3: provide 和 inject

01. Tabs1-表格功能的实现

<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) 方法返回一个新数组。

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 ,分页列表随之变化,得到模糊查找的列表啦!!!

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。

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。

// 勾选删除数据

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,具体如下。

<el-table-column label="操作">

    <template #default="{row}">

    <el-button link type="primary" size="small" @click="deletion(row.id)">删除</el-button>

    </template>

</el-table-column>
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 ) 获取组件实例。

const carouselRef = ref<any>(null)

1.添加

​ 想法为点击实现单个添加在尾部。数组的 push 方法可以实现。

// 添加幻灯片

const addItem = () => {

 const newItem = `新增内容${list.length + 1}`

 list.push(newItem)
    
}

2.删除

​ 通常想到删除,肯定需要通过id或索引才能精准删除。查看饿了吗组件库提供的 carousel 组件,提供了change 方法。可以发现提供了当前幻灯片的索引,那我们就需要定义一个全局变量接收当前索引。同样 splice 方法实现删除。

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官方文档。

​ 要用好组件库,仔细看文档一定少不了。

​ 我想实现的是拖拽功能和默认展开所有节点,属于组件自带属性,直接使用就可以了。


以上就是我完成的一些小玩具,欢迎大家提出宝贵的想法和建议。

原文链接:https://juejin.cn/post/7356434494511906852 作者:苋菜好好吃