在Vue應(yīng)用中添加虛擬滾動(dòng)

要在您的應(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.vueviews文件夾中創(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é)中淡诗,我們將觀察$routeVue 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以獲取以下屏幕:

翻譯自:https://medium.com/javascript-in-plain-english/how-to-add-virtual-scrolling-to-a-vue-app-19c21d55b3bc

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末咆霜,一起剝皮案震驚了整個(gè)濱河市邓馒,隨后出現(xiàn)的幾起案子嘶朱,更是在濱河造成了極大的恐慌蛾坯,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疏遏,死亡現(xiàn)場(chǎng)離奇詭異脉课,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)财异,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門倘零,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人戳寸,你說我怎么就攤上這事呈驶。” “怎么了疫鹊?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵袖瞻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我拆吆,道長(zhǎng)聋迎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任枣耀,我火速辦了婚禮霉晕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捞奕。我一直安慰自己牺堰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布颅围。 她就那樣靜靜地躺著伟葫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谷浅。 梳的紋絲不亂的頭發(fā)上扒俯,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天奶卓,我揣著相機(jī)與錄音,去河邊找鬼撼玄。 笑死夺姑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掌猛。 我是一名探鬼主播盏浙,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼荔茬!你這毒婦竟也來了废膘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤慕蔚,失蹤者是張志新(化名)和其女友劉穎丐黄,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孔飒,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡灌闺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坏瞄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桂对。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鸠匀,靈堂內(nèi)的尸體忽然破棺而出蕉斜,到底是詐尸還是另有隱情,我是刑警寧澤缀棍,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布宅此,位于F島的核電站,受9級(jí)特大地震影響睦柴,放射性物質(zhì)發(fā)生泄漏诽凌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一坦敌、第九天 我趴在偏房一處隱蔽的房頂上張望侣诵。 院中可真熱鬧,春花似錦狱窘、人聲如沸杜顺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)躬络。三九已至,卻和暖如春搭儒,著一層夾襖步出監(jiān)牢的瞬間穷当,已是汗流浹背提茁。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留馁菜,地道東北人茴扁。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像汪疮,于是被迫代替她去往敵國(guó)和親峭火。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • UI組件 element- 餓了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的組件庫(kù) m...
    柴東啊閱讀 15,848評(píng)論 2 140
  • UI組件 element- 餓了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的組件庫(kù) m...
    流觴小菜鳥閱讀 1,745評(píng)論 2 8
  • UI組件 element- 餓了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的組件庫(kù) m...
    王喂馬_閱讀 6,443評(píng)論 1 77
  • UI組件 element- 餓了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的組件庫(kù) m...
    你猜_3214閱讀 11,035評(píng)論 0 118
  • UI組件 element- 餓了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的組件庫(kù) m...
    小姜先森o0O閱讀 9,395評(píng)論 0 72