Vue实现支持搜索和筛选的用户列表

Vue实现支持搜索和筛选的用户列表

功能需求:
  1. 能够渲染用户列表
  2. 能够根据性别筛选数据
  3. 能够根据输入的关键字进行检索
开发思路:

实现上述需求,我们需要创建三个属性:用户列表数据、性别筛选字段、关键词字段

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>
组合式API:

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")

动画样式:

<style>
        .container {
            margin: 50px;
        }
        .content {
            margin: 20px;
        }
        .tab {
            width: 300px;
            position: absolute;
        }
        .item {
            border: gray 1px solid;
            width: 148px;
            text-align: center;
            transition: all 0.8s ease;
            display: inline-block;
        }
        .list-enter-active {
            transition: all 1s ease;
        }

        .list-enter-from,
        .list-leave-to {
            opacity: 0;
        }

        .list-move {
            transition: transform 1s ease;
        }
        .list-leave-active {
            position: absolute;
            transition: all 1s ease;
        }
    </style>

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监听所导致的,改成按钮却又没了实时更新的视觉感,要彻底解决该方法, 就需要支持多重搜索功能,目前毫无思绪。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
基于SpringBoot+Vue的论坛管理系统是一个集成了前端和后端技术的论坛管理平台,用于管理用户的帖子、评论等信息。该系统的源码、部署说明和系统介绍已经打包成一个zip文件,方便用户使用。 该系统的前端部分采用了Vue框架进行开发,主要实现用户界面和交互,包括登录、注册、发布帖子、评论、点赞等功能。而后端部分则采用了SpringBoot框架,负责处理用户请求、管理用户数据并提供相应的API接口。 该系统可以方便地处理用户的帖子、评论等信息,支持多级分类和标签,用户可以根据自己的需求进行筛选搜索,也可以根据不同的类型进行查看和发布帖子。同时,该系统还支持评论、点赞等互动方式,让用户可以更加深入地交流和讨论。 此外,该系统还支持用户权限的管理,可以对不同用户进行分组和授权,确保信息的安全性。 对于管理员而言,该系统可以方便地管理用户的帖子和评论信息,进行管理和审核。而对于用户而言,该系统可以方便地交流和分享经验,获取到最新的信息和知识。 总之,该基于SpringBoot+Vue的论坛管理系统是一个功能齐全、易用、实用性很高的论坛管理平台,能够方便地管理用户的帖子和评论信息,提高了管理效率和信息准确性。同时,对于开发者而言也是一个学习Vue和SpringBoot技术的不错案例,值得一试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高中不复,大学纷飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值