Vue.js列表渲染&关于列表元素的key&列表过滤与排序


索引

  • 一、关于key
    • 反例
    • 正例
  • 二、列表过滤(监视器VS.计算属性)
    • 监视器实现
    • 计算属性实现
  • 三、列表排序

饮水思源:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=30&spm_id_from=pageDriver

一、关于key

反例

一个反例,用index作为key出bug

DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>title>
  <script src="JS/vue.js">script>
head>

<body>
  <div id="root">
    <h1>{{header}}h1>
    <ul>
      

      <li v-for="(article, index) in articles" :key="index">
        {{article.title}} --- index = {{index}}
        <input type="text">
      li>
    ul>

    <button id="btnAdd">添加一篇文章button>
  div>

  <script>
    const articles = [
      {
        id: 1,
        title: '这个是文章1'
      },
      {
        id: 2,
        title: '这个是文章2'
      },
      {
        id: 3,
        title: '这个是文章3'
      },
    ]

    const vm = new Vue({
      el: "#root",
      data: {
        header: "key 的原理探究 --- 一个出错的例子",
        articles: articles,
      },
    })

    let i = 4;
    document.querySelector("#btnAdd").addEventListener("click", () => {
      articles.unshift({
        id: i,
        title: `这个是文章${i++}`,
      })
    })
  script>
body>

正例

修改一下,一个正确的例子,用唯一的id作key:

DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>title>
  <script src="JS/vue.js">script>
head>

<body>
  <div id="root">
    <h1>{{header}}h1>
    <ul>
      <li v-for="(article, index) in articles" :key="article.id">
        {{article.title}} --- index = {{index}}
        <input type="text">
      li>
    ul>

    <button id="btnAdd">添加一篇文章button>
  div>

  <script>
    const articles = [
      {
        id: 1,
        title: '这个是文章1'
      },
      {
        id: 2,
        title: '这个是文章2'
      },
      {
        id: 3,
        title: '这个是文章3'
      },
    ]

    const vm = new Vue({
      el: "#root",
      data: {
        header: "key 的原理探究 --- 一个正确的例子",
        articles: articles,
      },
    })

    let i = 4;
    document.querySelector("#btnAdd").addEventListener("click", () => {
      articles.unshift({
        id: i,
        title: `这个是文章${i++}`,
      })
    })
  script>
body>
html>

二、列表过滤(监视器VS.计算属性)

效果:

监视器实现

DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>title>
  <script src="JS/vue.js">script>
head>

<body>
  <div id="root">
    <input type="text" placeholder="请输入文章标题" v-model="keyWord">
    <ul v-show="!searchMode">
      <li v-for="(x, index) in allArticles" :key="x.id">
        #{{index}}# 标题:{{x.title}} 创建时间:{{x.create_time}}
      li>
    ul>
    <ul v-show="searchMode">
      <li v-for="(x, index) in filArticles" :key="x.id">
        #{{index}}# 标题:{{x.title}} 创建时间:{{x.create_time}}
      li>      
    ul>
  div>

  <script>
    const articles = [
      {
        id: 1,
        title: '文章123',
        create_time: '2022-01-22',
      },
      {
        id: 2,
        title: '文章345',
        create_time: '2022-01-27',
      },
      {
        id: 3,
        title: '文章567',
        create_time: '2022-01-11',
      },
      {
        id: 4,
        title: '文章6789',
        create_time: '2022-01-05',
      },
    ]

    const vm = new Vue({
      el: "#root",
      data: {
        allArticles: articles,
        keyWord: "",
        searchMode: false,
        filArticles: [],
      },
      watch: {
        keyWord(newVal) {
          if (newVal === "") {
            this.searchMode = false;
          } else {
            this.searchMode = true;
            this.filArticles = this.allArticles.filter(x => {
              return x.title.indexOf(newVal) !== -1;
            })
          }
        },
      }
    })
  script>
body>
html>

计算属性实现

DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>title>
  <script src="JS/vue.js">script>
head>

<body>
  <div id="root">
    <input type="text" placeholder="请输入文章标题" v-model="keyWord">
    <ul v-show="!searchMode">
      <li v-for="(x, index) in allArticles" :key="x.id">
        #{{index}}# 标题:{{x.title}} 创建时间:{{x.create_time}}
      li>
    ul>
    <ul v-show="searchMode">
      <li v-for="(x, index) in filArticles" :key="x.id">
        #{{index}}# 标题:{{x.title}} 创建时间:{{x.create_time}}
      li>      
    ul>
  div>

  <script>
    const articles = [
      {
        id: 1,
        title: '文章123',
        create_time: '2022-01-22',
      },
      {
        id: 2,
        title: '文章345',
        create_time: '2022-01-27',
      },
      {
        id: 3,
        title: '文章567',
        create_time: '2022-01-11',
      },
      {
        id: 4,
        title: '文章6789',
        create_time: '2022-01-05',
      },
    ]

    const vm = new Vue({
      el: "#root",
      data: {
        allArticles: articles,
        keyWord: "",
      },
      computed: {
        searchMode() {
          return this.keyWord !== "";
        },
        filArticles() {
          return this.allArticles.filter(x => {
              return x.title.indexOf(this.keyWord) !== -1;
          })
        }
      }
    })
  script>
body>
html>
计算属性实现.js

三、列表排序

效果:

实现:

DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>title>
  <script src="JS/vue.js">script>
head>

<body>
  <div id="root">
    <input type="text" placeholder="请输入文章标题" v-model="keyWord">
    <button v-on:click="sortByTime">按时间排序button>
    <button v-on:click="sortByDefault">原顺序button>
    <ul>
      <li v-for="(article, index) in filArticles" :key="article.id">
        #{{index}}# {{article.title}} 创建时间{{article.create_time}}
      li>
    ul>
  div>

  <script>
    const allArticles = [
      {
        id: 1,
        title: '章123',
        create_time: '2022-01-22',
      },
      {
        id: 2,
        title: '文章345',
        create_time: '2022-01-27',
      },
      {
        id: 3,
        title: '章567',
        create_time: '2022-01-11',
      },
      {
        id: 4,
        title: '文章6789',
        create_time: '2022-01-05',
      },
      {
        id: 5,
        title: '文章6789',
        create_time: '2022-01-01',
      },
    ]

    const vm = new Vue({
      el: "#root",
      data: {
        keyWord: "",
        sortType: 0, // 0 原顺序 1 按时间排序
      },
      computed: {
        filArticles() {
          let tmpArr = allArticles.filter(article => {
            return article.title.indexOf(this.keyWord) !== -1;
          })

          if (this.sortType) {
            tmpArr.sort((a, b) => {
              return a.create_time > b.create_time ? 1 : -1
            })
          }

          return tmpArr
        }
      },
      methods: {
        sortByTime() {
          this.sortType = 1;
        },
        sortByDefault() {
          this.sortType = 0;
        },
      },
    })
  script>
body>
html>