一、开源项目地址
二、应用场景
优化长列表或无限列表性能
三、原理
窗口化渲染,只需渲染少数的有效数据,减少创建 DOM 节点和重新渲染组件时间
四、使用示例
1、创建 Vue 项目
vue create demo
【注】这里用脚手架创建的是vue2.x项目。
2、通过 NPM 安装
npm install vue-virtual-scroll-list --save
3、main.js 引入组件
import Vue from 'vue'
import App from './App.vue'
import VirtualList from 'vue-virtual-scroll-list'
Vue.component('virtual-list', VirtualList)
Vue.config.productionTip = false
new Vue({
render: h => h(App)
}).$mount('#app')
【注】这里需要全局引入滑动窗口组件,否则在 App.vue 没有办法解析组件标签。
4、data.js 模拟生成数据
let idCounter = 0
export function getData(count) {
const data = []
for (let index = 0; index < count; index++) {
data.push({
id: String(idCounter++),
text: Math.random()
.toString(16)
.substr(10)
})
}
return data
}
data 为对象数组,每个对象包括 id,text 字段属性,text 由随机函数生成。
5、Item 组件
<template>
<div class="item">
<div class="id">{
{ source.id }} - {
{ source.text }}</div>
</div>
</template>
<script>
export default {
name: 'item-component',
props: {
source: {
type: Object,
default() {
return {}
}
}
}
}
</script>
<style scoped>
.item {
display: flex;
flex-direction: column;
border-bottom: 1px solid lightgrey;
padding: 1em;
}
</style>
Item 组件用于渲染每一项。
6、App.vue 引用组件
<template>
<div id="app">
<div class="wrapper">
<virtual-list class="list" style="height: 360px; overflow-y: auto;" :data-key="'id'" :data-sources="items"
:data-component="item" :estimate-size="50" />
</div>
</div>
</template>
<script>
import Item from './Item'
import { getData } from './data'
export default {
name: 'App',
data() {
return {
item: Item,
items: getData(1000)
}
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 1em;
padding: 1em;
}
.list {
border: 2px solid steelblue;
border-radius: 3px;
}
</style>
创建一个滑动窗口,渲染一千条数据。
7、测试效果
npm run serve
渲染一千条数据非常流畅。
五、实时模糊搜索实现
1、实现原理
通过 dataset 与关键字 keywor 进行正则匹配
2、App.vue 代码修改
新增输入框,实时监听输入内容,然后将输入内容作为 keyword 在 dataset 中搜索,若符合正则匹配关系,则将该数据保存在结果集 resultArray,最后返回给滑动窗口渲染。
<template>
<div id="app">
<div class="wrapper">
<!-- 输入框 -->
<input type="text" placeholder="请输入关键字" v-model="inputVal" @input="initSearchList" value=""
class="searcher-text" />
<!-- 动态滑动窗口 -->
<virtual-list class="list" style="height: 360px; overflow-y: auto;" :data-key="'id'" :data-sources="items"
:data-component="item" :estimate-size="50" />
</div>
</div>
</template>
<script>
import Item from './Item'
import { getData } from './data'
export default {
name: 'App',
data() {
return {
item: Item,
items: [],
allDataSet: getData(1000),
inputVal: ''
}
},
mounted() {
this.items = this.allDataSet;
},
methods: {
// 捕获输入关键字,动态渲染滑动串口内容
initSearchList() {
const keyword = this.inputVal;
this.items = this.searchKeywordsByRegExp(keyword,this.allDataSet);
},
// 从 dataset 中匹配 keyword
searchKeywordsByRegExp(keyword, dataset) {
if (!(dataset instanceof Array)) {
return [];
}
var len = dataset.length;
var resultArray = [];
var reg = new RegExp(keyword);
for (var i = 0; i < len; i++) {
// 如果字符串中不包含目标字符会返回-1
if (dataset[i]['text'].match(reg)) {
resultArray.push(dataset[i]);
}
}
return resultArray;
}
},
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 1em;
padding: 1em;
}
.list {
border: 2px solid steelblue;
border-radius: 3px;
}
.searcher-text {
width: 99%;
height: 28px;
margin-bottom: 10px;
border: 2px solid steelblue;
border-radius: 3px;
}
</style>
3、效果测试
可以看到,在 1000 条数据里匹配 ab 可以实现模糊匹配,精度越高,则实现精准匹配。