要在您的應(yīng)用程序中顯示大量數(shù)據(jù),一次加載所有內(nèi)容不是一個(gè)好的解決方案靖避。加載大列表會(huì)加重用戶計(jì)算機(jī)資源的負(fù)擔(dān)跋理。因此,我們需要一個(gè)更好的解決方案筷厘。最有效的解決方案是一次加載少量數(shù)據(jù)鸣峭。僅加載屏幕上顯示的所有內(nèi)容。此解決方案稱為虛擬滾動(dòng)酥艳。
使用Vue.js摊溶,我們可以使用位于https://www.npmjs.com/package/vue-virtual-scroll-list的vue-virtual-scroll-list程序包將虛擬滾動(dòng)添加到我們的Vue.js應(yīng)用程序中。這是為此目的使用的最簡(jiǎn)單的軟件包之一充石。
在本文中莫换,我們將制作一個(gè)應(yīng)用程序,使我們可以生成大量假數(shù)據(jù)并將其顯示在虛擬滾動(dòng)列表中骤铃。它將詢問用戶要?jiǎng)?chuàng)建多少個(gè)條目拉岁,然后在用戶提交編號(hào)時(shí)創(chuàng)建它。
首先惰爬,我們使用Vue CLI創(chuàng)建Vue.js項(xiàng)目喊暖。我們運(yùn)行npx @vue/cli create data-generator
來創(chuàng)建應(yīng)用程序。在向?qū)е兴呵疲覀冞x擇“手動(dòng)選擇功能”陵叽,然后選擇包括Babel和Vue-Router。
接下來丛版,我們需要安裝一些軟件包巩掺。我們需要使用BootstrapVue進(jìn)行樣式設(shè)置,使用Faker創(chuàng)建虛假數(shù)據(jù)页畦,使用Vee-Validate進(jìn)行用戶輸入驗(yàn)證以及使用Vue-Virtual-Scroll-List來顯示虛擬滾動(dòng)列表中的項(xiàng)目列表胖替。我們通過運(yùn)行以下命令安裝所有組件:
npm i bootstrap-vue faker vee-validate vue-virtual-scrolling-list
安裝軟件包后,我們將添加頁(yè)面寇漫。首先刊殉,我們Address.vue
在views
文件夾中創(chuàng)建并添加:
<template>
<div class="page">
<h1 class="text-center">Generate Addresses</h1>
<ValidationObserver ref="observer" v-slot="{ invalid }">
<b-form [@submit](http://twitter.com/submit).prevent="onSubmit" novalidate>
<b-form-group label="Number" label-for="number">
<ValidationProvider
name="number"
rules="required|min_value:1|max_value:100000"
v-slot="{ errors }"
>
<b-form-input
:state="errors.length == 0"
v-model="form.number"
type="text"
required
placeholder="Number"
name="number"
></b-form-input>
<b-form-invalid-feedback :state="errors.length == 0">{{errors.join('. ')}}</b-form-invalid-feedback>
</ValidationProvider>
</b-form-group>
<b-button type="submit" variant="primary">Generate</b-button>
</b-form>
</ValidationObserver><br /><h2>Addresses</h2><virtual-list :size="itemHeight" :remain="3">
<div v-for="(item, index) of list" :key="index" class="result-row">
<div class="index">{{index + 1}}</div>
<div class="column">{{item.streetAddress}}</div>
<div class="column">{{item.streetName}}</div>
<div class="column">{{item.city}}</div>
<div class="column">{{item.county}}</div>
<div class="column">{{item.state}}</div>
<div class="column">{{item.country}}</div>
<div class="column">{{item.zipCode}}</div>
</div>
</virtual-list>
</div>
</template><script>
const faker = require("faker");
import virtualList from "vue-virtual-scroll-list";export default {
name: "home",
data() {
return {
form: {},
list: [],
itemHeight: 80
};
},
components: { "virtual-list": virtualList },
methods: {
async onSubmit() {
const isValid = await this.$refs.observer.validate();
if (!isValid) {
return;
}
this.list = Array.from({ length: this.form.number }).map((l, i) => {
return {
city: faker.address.city(),
streetName: faker.address.streetName(),
streetAddress: faker.address.streetAddress(),
county: faker.address.county(),
state: faker.address.state(),
country: faker.address.country(),
zipCode: faker.address.zipCode()
};
});
}
}
};
</script><style scoped>
.column {
padding-right: 20px;
width: calc(80vw / 7);
overflow: hidden;
text-overflow: ellipsis;
}.result-row {
height: 80px;
}
</style>
在此頁(yè)面中,我們讓用戶輸入1到100000之間的數(shù)字來生成虛假地址州胳,然后在用戶輸入該數(shù)字后记焊,onSubmit
就會(huì)調(diào)用該地址來生成商品。Faker庫(kù)用于生成項(xiàng)目栓撞。表單驗(yàn)證是通過將表單包裝在ValidationObserver
組件中并將輸入包裝在ValidationProvider
組件中來完成的遍膜。我們提供的驗(yàn)證規(guī)則rules
的道具ValidationProvider
碗硬。規(guī)則將在main.js
以后添加。
在b-form-invalid-feedback
組件中顯示錯(cuò)誤消息顯示瓢颅。獲取錯(cuò)誤ValidationProvider
作用恩尾。這是我們從中獲取errors
對(duì)象的地方。
用戶提交號(hào)碼后挽懦,將onSubmit
調(diào)用該函數(shù)翰意。這是ValidationObserver
有用的地方,因?yàn)樗鼮槲覀兲峁┝?code>this.$refs.observer.validate()檢查表單有效性的功能信柿。
如果isValid
解析為true
冀偶,則我們使用該Array.from
方法生成列表,方法是映射生成用戶輸入的長(zhǎng)度為(this.form.number
)的數(shù)組渔嚷,然后將每個(gè)條目映射到假地址行进鸠。
我們virtual-list
在本script
節(jié)中從Vue-Virtual-Scroll-List 添加組件,以便可以在模板中使用它形病。這些項(xiàng)目在virtual-list
組件中客年,因此我們一次只顯示一些。該remain
道具是我們指定一次在屏幕上顯示的項(xiàng)目數(shù)的地方漠吻。該size
道具用于設(shè)置每行的高度量瓜。
接下來的Home.vue
,我們將現(xiàn)有代碼替換為:
<template>
<div class="page">
<h1 class="text-center">Generate Emails</h1>
<ValidationObserver ref="observer" v-slot="{ invalid }">
<b-form [@submit](http://twitter.com/submit).prevent="onSubmit" novalidate>
<b-form-group label="Number" label-for="number">
<ValidationProvider
name="number"
rules="required|min_value:1|max_value:100000"
v-slot="{ errors }"
>
<b-form-input
:state="errors.length == 0"
v-model="form.number"
type="text"
required
placeholder="Number"
name="number"
></b-form-input>
<b-form-invalid-feedback :state="errors.length == 0">{{errors.join('. ')}}</b-form-invalid-feedback>
</ValidationProvider>
</b-form-group>
<b-button type="submit" variant="primary">Generate</b-button>
</b-form>
</ValidationObserver> <br /> <h2>Emails</h2> <virtual-list :size="itemHeight" :remain="30">
<div v-for="(item, index) of list" :key="index" class="result-row">
<div class="index">{{index + 1}}</div>
<div>{{item}}</div>
</div>
</virtual-list>
</div>
</template><script>
const faker = require("faker");
import virtualList from "vue-virtual-scroll-list";export default {
name: "home",
data() {
return {
form: {},
list: [],
itemHeight: 30
};
},
components: { "virtual-list": virtualList },
methods: {
async onSubmit() {
const isValid = await this.$refs.observer.validate();
if (!isValid) {
return;
}
this.list = Array.from({ length: this.form.number }).map((l, i) => {
return faker.internet.email();
});
}
}
};
</script>
它的工作方式與極為相似Address.vue
侥猩,除了我們生成的是電子郵件而不是地址榔至。
接下來Name.vue
,在views
文件夾中創(chuàng)建一個(gè)文件并添加:
<template>
<div class="page">
<h1 class="text-center">Generate Names</h1>
<ValidationObserver ref="observer" v-slot="{ invalid }">
<b-form [@submit](http://twitter.com/submit).prevent="onSubmit" novalidate>
<b-form-group label="Number" label-for="number">
<ValidationProvider
name="number"
rules="required|min_value:1|max_value:100000"
v-slot="{ errors }"
>
<b-form-input
:state="errors.length == 0"
v-model="form.number"
type="text"
required
placeholder="Number"
name="number"
></b-form-input>
<b-form-invalid-feedback :state="errors.length == 0">{{errors.join('. ')}}</b-form-invalid-feedback>
</ValidationProvider>
</b-form-group>
<b-button type="submit" variant="primary">Generate</b-button>
</b-form>
</ValidationObserver> <br /> <h2>Names</h2> <virtual-list :size="itemHeight" :remain="30">
<div v-for="(item, index) of list" :key="index" class="result-row">
<div class="index">{{index + 1}}</div>
<div>{{item.firstName}} {{item.lastName}}</div>
</div>
</virtual-list>
</div>
</template><script>
const faker = require("faker");
import virtualList from "vue-virtual-scroll-list";export default {
name: "home",
data() {
return {
form: {},
list: [],
itemHeight: 30
};
},
components: { "virtual-list": virtualList },
methods: {
async onSubmit() {
const isValid = await this.$refs.observer.validate();
if (!isValid) {
return;
}
this.list = Array.from({ length: this.form.number }).map((l, i) => {
return {
firstName: faker.name.firstName(),
lastName: faker.name.lastName()
};
});
}
}
};
</script>
在用戶輸入所需的項(xiàng)目數(shù)后欺劳,我們會(huì)在此文件中生成偽造的名字和姓氏唧取。
然后在中App.vue
,將現(xiàn)有代碼替換為:
<template>
<div id="app">
<b-navbar toggleable="lg" type="dark" variant="info">
<b-navbar-brand to="/">Data Generator</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-item to="/" :active="path == '/'">Home</b-nav-item>
<b-nav-item to="/name" :active="path == '/name'">Name</b-nav-item>
<b-nav-item to="/address" :active="path == '/address'">Address</b-nav-item>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<router-view />
</div>
</template>
<script>
export default {
data() {
return {
path: this.$route && this.$route.path
};
},
watch: {
$route(route) {
this.path = route.path;
}
}
};
</script>
<style lang="scss">
.page {
padding: 20px;
}
.result-row {
display: flex;
height: calc(50vh / 10);
}
.index {
padding-right: 20px;
min-width: 100px;
}
</style>
添加帶有頁(yè)面鏈接的BootstrapVue導(dǎo)航欄划提。在頂部欄中枫弟,我們active
為鏈接設(shè)置屬性,以便突出顯示當(dāng)前頁(yè)面的鏈接鹏往。在本scripts
節(jié)中淡诗,我們將觀察$route
Vue Router提供的對(duì)象以獲取應(yīng)用程序的當(dāng)前路徑,并將其分配給該對(duì)象伊履,this.path
以便我們可以使用它來設(shè)置active
道具韩容。
接下來的main.js
,我們將現(xiàn)有代碼替換為:
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import BootstrapVue from "bootstrap-vue";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
import { ValidationProvider, extend, ValidationObserver } from "vee-validate";
import { required } from "vee-validate/dist/rules";
import { min_value } from "vee-validate/dist/rules";
import { max_value } from "vee-validate/dist/rules";
extend("required", required);
extend("min_value", min_value);
extend("max_value", max_value);
Vue.component("ValidationProvider", ValidationProvider);
Vue.component("ValidationObserver", ValidationObserver);
Vue.use(BootstrapVue);
Vue.config.productionTip = false;
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
我們?cè)诖颂幪砑恿讼惹拔募惺褂玫尿?yàn)證規(guī)則唐瀑,并包括了我們?cè)趹?yīng)用程序中使用的所有庫(kù)群凶。我們進(jìn)行了注冊(cè),ValidationProvider
并進(jìn)行ValidationObserver
了調(diào)用哄辣,Vue.component
以便可以在組件中使用它們请梢。Vee-Validate提供的驗(yàn)證規(guī)則包含在應(yīng)用程序中赠尾,以便模板可以通過extend
從Vee-Validate 進(jìn)行調(diào)用來使用它們。我們呼吁Vue.use(BootstrapVue)
在我們的應(yīng)用程序中使用BootstrapVue毅弧。
在router.js
我們將現(xiàn)有代碼替換為:
import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import Name from "./views/Name.vue";
import Address from "./views/Address.vue";
Vue.use(Router);
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "home",
component: Home
},
{
path: "/name",
name: "name",
component: Name
},
{
path: "/address",
name: "address",
component: Address
}
]
});
包含我們?cè)诼肪€中創(chuàng)建的頁(yè)面气嫁,以便用戶可以通過頂部欄中的鏈接或直接輸入U(xiǎn)RL來訪問它們。
接下來的index.html
够坐,我們將現(xiàn)有代碼替換為:
<!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" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title>Data Generator</title>
</head>
<body>
<noscript>
<strong
>We're sorry but vue-virtual-scroll-tutorial-app doesn't work properly
without JavaScript enabled. Please enable it to continue.</strong
>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
更改應(yīng)用程序的標(biāo)題寸宵。
最后,我們運(yùn)行npm run serve
以獲取以下屏幕: