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

    动画样式:

    
    

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

  • 相关阅读:
    20220705开发板BL602的SDK编译以及刷机
    GO Http 请求
    干掉 “重复代码”,这三种方式绝了!
    浅谈C/S vs. B/S的区别
    二分查找算法解析
    TCP/IP协议
    【滤波跟踪】基于matlab扩展卡尔曼滤波的无人机路径跟踪【含Matlab源码 2236期】
    【双向数据绑定原理 vue2.0 与 vue3.0】
    项目经理每天,每周,每月的工作清单
    HarmoneyOS星河版 安装和启动
  • 原文地址:https://blog.csdn.net/qq_44760912/article/details/127103326