实现上述需求,我们需要创建三个属性:用户列表数据、性别筛选字段、关键词字段
data() {
return {
//性别筛选字段 初始化取值为-1 其中-1代表全部 0代表男 1代表女
sexFilter: -1,
//展示的用户列表数据
showDatas: [],
//搜索的关键词
searchKey: "",
}
}
关于数据源,我们使用本地定义的模拟数据,赋值给变量mock,并使用延迟函数来模拟从网络上请求用户数据
//学号 学生名 性别 年龄 爱好
let mock = [
{
"s_id": 2018400601,"name": "小王","sex": 0,"age": 22,"like": "只因"
},
{
"s_id": 2018400602,"name": "小蔡","sex": 0,"age": 20,"like": "小黑子"
},
{
"s_id": 2018400603,"name": "小美","sex": 1,"age": 18,"like": "鸡你太美"
},
{
"s_id": 2018400604,"name": "甜甜","sex": 1,"age": 18,"like": "篮球"
}
]
//数据来源某位不知名的ikun
除了属性之外,我们还需要定义三个功能函数来分别实现功能需求
methods: {
//获取用户数据
queryAllData() {
this.showDatas = mock
},
//进行性别筛选
FilterData() {
this.searchKey = ""
//默认获取全部数据
if(this.sexFilter == -1) {
this.showDatas = mock
} else {
//mock为对象数组
this.showDatas = mock.filter(data => {
//返回与列表数据中用户选择的sex匹配的数据,下方等式返回布尔值为true的结果 =赋值 ==布尔判断 ===全等
return data.sex == this.sexFilter
})
}
},
//进行关键词检索
}
关于对象数组或者数组操作filter()的详解请自行百度,这里的目的就是返回匹配的所有数据,由于sexFilter、searchKey都是响应式数据,并且双向绑定在了input中,所以后续可以用watch进行监听
searchData() {
this.sexFilter = -1
//当用户输入为空
if(this.searchKey.length == 0) {
this.showDatas = mock
} else {
this.showDatas = mock.filter(data => {
//名字中包含输入的关键词则表示匹配成功 指定字段匹配
return data.name.search(this.searchKey) != -1
})
}
}
str.search(key)可以匹配str中是否包含key,匹配成功返回>-1的值(好像是这样的,如有错误请指正),反之返回-1
以data.age为例,由于data.age的类型是int,故在此之前我们需要将其类型转换成string
//起初我使用toString(),但没有效果 直接使用String即可
String(data.age)
为节省时间,我在csdn找到了相关的解决办法,详情见这篇文章https://blog.csdn.net/lee_amazing/article/details/122323763
将需要多个筛选的字段写入一个新的对象中,然后匹配
const searchField = {
// 选择搜索的字段,此处对应数组对象的字段,可以多个筛选
name: data.name,
age: data.age,
}
// 返回处理后的结果
return Object.keys(searchField).some(function (key) {
return String(data[key]).toLowerCase().search(this.searchKey) > -1
})
测试发现不报错,有返回结果,但是无法实现检索功能,于是我们需要层层分析这块代码的作用
Object.keys(searchField)
作用:Object.keys()处理对象数据时:返回可枚举的属性数组
console.log(Object.keys(searchField)) //打印结果为 [name , age]
可以使用Object.keys(searchField).forEach(key => {
console.log(key); //打印结果为 name , age console.log(searchField[key]); //打印结果为对应的value值
})
同理Object.values(searchField).forEach() 可以直接遍历value值
Object.keys(searchField).some()
其中的some方法只要有一个满足条件就返回true
toLowerCase():将大小写转化为小写
假设return String(data[key]).toLowerCase().search(this.searchKey) > -1 匹配成功返回true,那么some也返回true,所以仔细分析代码是没有问题的
最终解决:将function() 写成 箭头函数 () => {} 形式 初步判断应该是this的指向不一样
方法参考链接:https://blog.csdn.net/weixin_42260975/article/details/120722006
多个字段匹配检索完整代码:分享一个小技巧,代码粘贴前面有空格不对称,快捷键shift+alt+手动选择空格行往下拉,选中删除
searchData() {
this.sexFliter = -1
if (this.searchKey.length == 0) {
this.showDatas = mock
} else {
//这里需要使用箭头函数
this.showDatas = mock.filter(data => {
//单个字段检索
//return data.name.search(this.searchKey) != -1
//两个字段检索
//return data.name.search(this.searchKey) != -1 || String(data.age).search(this.searchKey) != -1
//多字段检索
const searchField = {
// 选择搜索的字段,此处对应数组对象的字段,可以多个筛选
name: data.name
age: data.age,
}
// 返回处理后的结果,需要使用箭头函数保证this的指向问题
return Object.values(searchField).some(value => {
return String(value).toLowerCase().search(this.searchKey) != -1
})
})
}
},
这里11行代码的效果其实等价于12-20行的代码块,但是在实际开发中,如果需求是更多的字段,显然后者会更加清晰明了,更具有可读性
定义好了功能函数,我们需要在合适的时机对其进行调用,比如我们的数据需要页面加载时延迟3秒显示,这意味着需要将queryAllData方法挂载在组件上
mouted() {
//模拟请求过程 由于没有使用定时器,并不需要销毁事件
setTimeout(this.queryAllData, 3000);
}
这样当页面加载后,延时3秒就能获取到我们定义给mock的模拟数据啦,而对于性别筛选和关键词检索功能,我们需要使用watch监听对应的属性,以便于这些属性发生变化时能够执行对应的方法更新页面
watch: {
sexFilter(oldValue, newValue) {
this.filterData();
},
searchKey(oldValue, newValue) {
this.searchData();
}
}
到这里我们的逻辑代码就已经基本完成了,接下来就是在html中引入vue.js以及挂载组件到我们定义好的HTML元素上了
//引入在线vue.js
<script src="https://unpkg.com/vue@next"></script>
const App = Vue.createApp({
//所有逻辑代码
})
App.mount("#Application")
html页面框架搭建代码:
<div id="Application">
<div class="container">
<div class="content">
<input type="radio" :value="-1" v-model="sexFliter" />全部
<input type="radio" :value="0" v-model="sexFliter" />男
<input type="radio" :value="1" v-model="sexFliter" />女
div>
<div class="content">搜索:<input type="text" v-model="searchKey" />div>
<div class="content">
<table border="1" width="300px">
<tr>
<th>学号th>
<th>姓名th>
<th>性别th>
<th>年龄th>
<th>爱好th>
tr>
<tr v-for="(data, index) in showDatas">
<td>{{data.s_id}}td>
<td>{{data.name}}td>
<td>{{data.sex == 0 ? '男' : '女'}}td>
<td>{{data.age}}td>
<td>{{data.like}}td>
tr>
table>
div>
div>
div>
到此整个页面就大功告成了,对了css样式就没怎么写了,后续会引入css动画
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户列表title>
<script src="https://unpkg.com/vue@next">script>
<style>
.container {
margin: 50px;
}
.content {
margin: 20px;
}
style>
head>
<body>
<div id="Application">
<div class="container">
<div class="content">
<input type="radio" :value="-1" v-model="sexFliter" />全部
<input type="radio" :value="0" v-model="sexFliter" />男
<input type="radio" :value="1" v-model="sexFliter" />女
div>
<div class="content">搜索:<input type="text" v-model="searchKey" />div>
<div class="content">
<table border="1" width="300px">
<tr>
<th>学号th>
<th>姓名th>
<th>性别th>
<th>年龄th>
<th>爱好th>
tr>
<tr v-for="(data, index) in showDatas">
<td>{{data.s_id}}td>
<td>{{data.name}}td>
<td>{{data.sex == 0 ? '男' : '女'}}td>
<td>{{data.age}}td>
<td>{{data.like}}td>
tr>
table>
div>
div>
div>
<script>
let mock = [
{
"s_id": 2018400601, "name": "小王", "sex": 0, "age": 22, "like": "只因"
},
{
"s_id": 2018400602, "name": "小蔡", "sex": 0, "age": 20, "like": "小黑子"
},
{
"s_id": 2018400603, "name": "小美", "sex": 1, "age": 18, "like": "鸡你太美"
},
{
"s_id": 2018400604, "name": "甜甜", "sex": 1, "age": 18, "like": "篮球"
}
]
const App = Vue.createApp({
data() {
return {
sexFliter: -1,
showDatas: [],
searchKey: "",
list: [32, 33, 16, 40, '']
}
},
mounted() {
// 模拟请求过程
setTimeout(this.queryAllData, 3000);
},
methods: {
queryAllData() {
this.showDatas = mock
},
fliterData() {
this.searchKey = ""
if (this.sexFliter == -1) {
this.showDatas = mock
} else {
this.showDatas = mock.filter((data) => {
return data.sex == this.sexFliter
})
}
},
searchData() {
this.sexFliter = -1
if (this.searchKey.length == 0) {
this.showDatas = mock
} else {
this.showDatas = mock.filter(data => {
//return data.name.search(this.searchKey) != -1 || String(data.age).search(this.searchKey) != -1
const searchField = {
// 选择搜索的字段,此处对应数组对象的字段,可以多个筛选
name: data.name,
age: data.age,
like: data.like,
}
// 返回处理后的结果
return Object.values(searchField)
.some(value => {
console.log(String(value).toLowerCase().search(this.searchKey) != -1);
return String(value).toLowerCase().search(this.searchKey) != -1
})
})
}
},
},
watch: {
sexFliter(oldValue, newValue) {
this.fliterData()
},
searchKey(oldValue, newValue) {
this.searchData()
}
}
})
App.mount("#Application")
script>
body>
html>
vue3引入了组合式API的全新写法,因此我们尝试用组合式API来重构该页面
const App = Vue.createApp({
setup() {
// 数据类变量用const 值类变量用let 为啥呢
//用户列表
const showDatas = Vue.ref([])
const queryAllData = () => {
//模拟请求过程
setTimeout(()=>{
showDatas.value = mock
},3000);
}
//组件挂载时请求数据
Vue.onMounted(queryAllData)
let sexFilter = Vue.ref(-1)
let searchKey = Vue.ref("")
let filterData = () => {
searchKey.value = ""
if(sexFilter.value == -1) {
showDatas.value = mock
} else {
showDatas.value = mock.filter((data) => {
return data.sex == sexFilter.value
})
}
}
searchData = () => {
sexFilter.value = -1
if(searchKey.value.length == 0) {
showDatas.value = mock
} else {
showDatas.value = mock.filter((data) => {
return data.name.search(searchKey.value) != -1
})
}
}
// 添加侦听
Vue.watch(sexFilter, filterData)
Vue.watch(searchKey, searchData)
return {
showDatas,searchKey,sexFilter
}
},
template: `
这里放html代码
`
})
App.mount("#Application")
动画样式:
html部分,写在template中
<div class="container">
<div class="content">
<input type="radio" :value="-1" v-model="sexFilter"/>全部
<input type="radio" :value="0" v-model="sexFilter"/>男
<input type="radio" :value="1" v-model="sexFilter"/>女
div>
<div class="content">搜索:<input type="text" v-model="searchKey" />div>
<div class="content">
<div class="tab" width="300px">
<div>
<div class="item">姓名div>
<div class="item">性别div>
div>
<transition-group name="list">
<div v-for="(data, index) in showDatas" :key="data.name">
<div class="item">{{data.name}}div>
<div class="item">{{data.sex == 0 ? '男' : '女'}}div>
div>
transition-group>
div>
div>
div>
现在有个问题哈,也就是二者同时使用会冲突,导致后者执行失效,原因是watch监听所导致的,改成按钮却又没了实时更新的视觉感,要彻底解决该方法, 就需要支持多重搜索功能,目前毫无思绪。