Vue —— 基础(四)(列表渲染)

简介: Vue —— 基础(四)(列表渲染)

一、列表渲染

1. v-for 指令:用于循环。
  1. 用于展示列表数据。
  2. 语法:v-for="(item, index) in xxx" :key="yyy"
  3. 可遍历:数组、对象、字符串(用得少)、指定次数(用得少)。

遍历数组

  1. p.id:遍历出所有人员的 id
  2. index:索引。
  <div id="root">
        <h3>人员列表(遍历数组)</h3>
        <ul>
            <li v-for="(p, index) in persons" :key="index">{{p.id}} - {{p.name}} - {{p.age}}</li>
        </ul>
    </div>
  const vm = new Vue({
        el: '#root',
        data: function () {
            return {
                persons: [
                    {id: 1, name: '张三', age: 18},
                    {id: 2, name: '李四', age: 19},
                    {id: 3, name: '王五', age: 20}
                ]
            }
        }
    })

7901109f56f44f4d8b7c9007fd1f8b12.png

遍历对象:注意遍历时的写法 (value, k) in xxx

  1. value:值。
  2. k:键。
  <div id="root">
        <h3>汽车信息(遍历对象)</h3>
        <ul>
            <li v-for="(value, k) in car" :key="k">{{k}} - {{value}}</li>
        </ul>
    </div>
  const vm = new Vue({
        el: '#root',
        data: function () {
            return {
                car:{
                    name: 'BMW',
                    price: '60w',
                    color: 'skyblue'
                }
            }
        }
    })

97b9e883b4cc4c0790d54c73fc1d06e4.png

遍历字符串(很少用)

  1. char:每个字符。
  2. index:索引。
  <div id="root">
        <h3>字符串信息(遍历字符串)</h3>
        <ul>
            <li v-for="(char, index) in str" :key="index">{{index}} - {{char}}</li>
        </ul>
    </div>
  const vm = new Vue({
        el: '#root',
        data: function () {
            return {
                str: 'hello'
            }
        }
    })

8ba8fd8793b14bce97ba16ddb9ca53a5.png

遍历指定次数(很少用)

  1. number:每一个数字。
  2. index:索引。
  <div id="root">
        <h3>遍历指定次数(很少用)</h3>
        <ul>
            <li v-for="(number, index) in 4" :key="index">{{index}} - {{number}}</li>
        </ul>
    </div>
  const vm = new Vue({
        el: '#root',
        data: function () {
            return {
            }
        }
    })

d6b855c76e1f43eeae9b85507e87b9ea.png

2. key 的原理
  1. key 的作用:
  1. key 是虚拟 DOM 对象的标识,当数据发生变化时,Vue 会根据【新数据】生成【新的虚拟DOM】。
  2. 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较。

对比规则:

旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key:

(1)若虚拟 DOM 中内容没变,直接使用之前的真实 DOM。

(2)若虚拟 DOM 中内容改变了,则生成新的真实 DOM,随后替换掉页面中之前的真实 DOM。

旧虚拟 DOM 中未找到与新虚拟 DOM 相同的 key:

(1)创建新的真实DOM,随后渲染到页面。

  1. 用 index 作为 key 可能会引发的问题。
  1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==>界面效果没问题,但效率低。
  2. 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。

开发中如何选择 key?

最好使用每条数据的唯一表示作为 key,比如 id、手机号、身份证号、学号等唯一值。

如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示, 使用 index 作为 key 是没有问题的。

实例:通过 id 唯一标识符,添加成员

  <div id="root">
        <h3>人员列表(遍历数组)</h3>
        <ul>
            <button @click.once="add">添加老刘</button>
            <li v-for="(p, index) in persons" :key="p.id">
                {{p.name}}--{{p.age}}
                <input type="text" :value=`${p.name}——${p.age}`>
            </li>
        </ul>
    </div>
  const vm = new Vue({
        el: '#root',
        data: function () {
            return {
                persons:[
                    {id: 1, name: '张三', age: 20},
                    {id: 2, name: '李四', age: 21},
                    {id: 3, name: '王五', age: 22},
                ]
            }
        },
        methods:{
            add(){
                const p = {id: 4, name: '老刘', age: 83}
                this.persons.unshift(p)
            }
        }
    })

cd3fed4c937e4cd2b7af4ba6bd7d2e85.png

3. 列表过滤

实例:输入框输入信息,过滤出有其中关键字的人员信息。(计算属性实现)

  1. 在计算属性中 filPersons 是一个函数,返回出来过滤的结果。
  <div id="root">
        <h2>人员列表</h2>
        <input type="text" placeholder="请输入名字" v-model="keyWord">
        <ul>
            <li v-for="(p, index) in filPersons" :key="index">
                {{p.name}}--{{p.age}}--{{p.sex}}
            </li>
        </ul>   
    </div>
  const vm = new Vue({
        el:'#root',
        data:{
            keyWord:'',
            persons:[
                {id:'001',name:'马冬梅',age:18,sex:'女'},
                {id:'002',name:'周冬雨',age:19,sex:'女'},
                {id:'003',name:'周杰伦',age:20,sex:'男'},
                {id:'004',name:'温兆伦',age:21,sex:'男'},
            ],
        },
        computed:{
            filPersons(){
                return this.persons.filter(p => p.name.includes(this.keyWord.trim()))
                })
            }
        }
    })

(监听方法实现)

  1. 在监听方法中 filPersons 是一个数组,把过滤出来的信息放到数组里。
  <div id="root">
        <h3>人员列表(遍历数组)</h3>
        <input type="text" placeholder="请输入名字" v-model="keyWord">
        <ul>
            <li v-for="(p, index) in filPersons">
                {{p.name}} - {{p.age}} - {{p.sex}}
            </li>
        </ul>
    </div>
  const vm = new Vue({
        el: '#root',
        data: function () {
            return {
                keyWord: '',
                persons:[
                    {id:'001',name:'马冬梅',age:18,sex:'女'},
                    {id:'002',name:'周冬雨',age:19,sex:'女'},
                    {id:'003',name:'周杰伦',age:20,sex:'男'},
                    {id:'004',name:'温兆伦',age:21,sex:'男'},
                ],
                filPersons:[]
            }
        },
        watch:{
            keyWord:{
                immediate:true, //初次打开页面呈现内容
                handler(val){
                    this.filPersons = this.persons.filter(p => p.name.includes(val.trim()))
                }
            }
        }
    })

初始状态:

e680d96a2c7f43e08124c0b258d29e68.png

查询:

7f8f0e305944453e85ff036919cff527.png

4. 列表排序

对成员按年龄升序、年龄降序和原顺序排序。

  1. 先把过滤出来的信息放进数组。
  2. 利用三元表达式,对数组进行按需排序。
  3. 注意:添加点击事件的条件 'sortType = n' 不是 ===
  <div id="root">
        <h3>人员列表</h3>
        <input type="text" placeholder="请输入名字" v-model="keyWord">
        <button @click="sortType = 2">年龄升序</button>
        <button @click="sortType = 1">年龄降序</button>
        <button @click="sortType = 0">原顺序</button>
        <ul>
            <li v-for="(p, index) in filPersons" :key="p.id">
                {{p.name}} - {{p.age}} - {{p.sex}}
                <input type="text">
            </li>
        </ul>
    </div>
  const vm = new Vue({
        el: '#root',
        data: function () {
            return {
                keyWord: '',
                sortType: 0,
                persons:[
                    {id:'001',name:'马冬梅',age:18,sex:'女'},
                    {id:'002',name:'周冬雨',age:25,sex:'女'},
                    {id:'003',name:'周杰伦',age:45,sex:'男'},
                    {id:'004',name:'温兆伦',age:21,sex:'男'},
                ],
            }
        },
        computed:{
            filPersons(){
                const arr = this.persons.filter(p => p.name.includes(this.keyWord))
                if(this.sortType){
                    arr.sort((p1, p2) => {
                        return this.sortType === 2 ? p1.age - p2.age : p2.age - p1.age 
                    })
                }
                return arr
            }
        }
    })

年龄升序:

0460a8cf01c949d3a48c82adf002f491.png

年龄降序:

21f142edf0e9477b8d5c4c7311d38810.png

原顺序:6d167869946448eca4f0efdb459f2ce6.png


注意:如果 :key='index',即以索引为唯一值的话,就会出现以下情况。(所对应文本框内容不会跟随着前面顺序的变化而变化)

76d7cdbfb5f948d388874faa1c71b1b5.png

5. 列表更新(两种方法)

方法一:一个个改进来。

注意:如果用以下写法写,不奏效

  this.person[0] = {id:'001', name:'马老师', age:50,sex:'男'}
  <div id="root">
        <h3>人员列表</h3>
        <input type="text" placeholder="请输入名字" v-model="keyWord">
        <button @click="updatedMei">更新马冬梅信息</button>
        <ul>
            <li v-for="(p, index) in filPersons" :key="index">
                {{p.name}} - {{p.age}} - {{p.sex}}
            </li>
        </ul>
    </div>
  const vm = new Vue({
        el: '#root',
        data: function () {
            return {
                keyWord: '',
                sortType: 0,
                persons:[
                    {id:'001',name:'马冬梅',age:18,sex:'女'},
                    {id:'002',name:'周冬雨',age:25,sex:'女'},
                    {id:'003',name:'周杰伦',age:45,sex:'男'},
                    {id:'004',name:'温兆伦',age:21,sex:'男'},
                ],
            }
        },
        methods:{
            updatedMei(){
                this.persons[0].name = '马老师',
                this.persons[0].age = 50,
                this.persons[0].sex = '男'
            }
        },
        computed:{
            filPersons(){
                return this.persons.filter(p => p.name.includes(this.keyWord))
            }
        }
    })

点击更新马冬梅信息

1489bd9fe9f44a03bbdb0b0a1387caca.png

方法二:使用 splice() 方法,删除添加。

  updateMei(){
        this.persons.splice(0,1,{id:'001',name:'马老师',age:50,sex:'男'})
    }
6. Vue.set 的使用

Vue.set():向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = 'hi' )

Vue.set( target, propertyName/index, value )

  1. target:要更改的数据源(可以是对象或者数组)
  2. key:要更改的具体数据
  3. value :重新赋的值
  4. 注意:对象不能是 Vue 实例,或者 Vue 实例的根数据对象。
  <div id="root">
        <h1>学生信息</h1>
        <button @click="addSex">添加一个性别属性,默认值男</button>
        <h2>姓名:{{student.name}}</h2>
        <h2 v-if="student.sex">性别:{{student.sex}}</h2>
        <h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
    </div>
  const vm = new Vue({
        el: '#root',
        data: function () {
            return {
                student: {
                    name: 'tom',
                    age: {
                        rAge: 40,
                        sAge: 29,
                    },
                }
            }
        },
        methods: {
            addSex() {
                Vue.set(this.student,'sex','男')
                // this.$set(this.student, 'sex', '男')
            }
        }
    })

2fd72c4eb36d4e748dbfb110535c25f8.png

543ffbbdd79641cea0a6e995baaa121a.png

7. 总结 vue 监听数据的原理
  1. vue会监视 data 中所有层次的数据。
  2. 如何检测对象中的数据?
  3. 通过 setter 实现监视,且要在 new Vue 时就传入要检测的数据。


对象中后追加的属性,Vue默认不做响应式处理。

如需给后添加的属性做响应式,请使用如下API:

(1)Vue.set(target.propertyName/index.value) 或

(2)vm.$set(target.propertyName/index.value)

  1. 如何检测数组中的数据?

通过包裹数组更新元素的方法实现,本质就是做了两件事:

  1. 调用原生对应的方法对数组进行更新。
  2. 重新解析模板,进而更新页面。

在 Vue 修改数组中的某些元素一定要用如下方法:

使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()

Vue.set() 或 vm.$set()

特别注意:Vue.set() 和 vm.$set 不能给vm 或 vm的根数据对象 添加属性!!

8. 总结练习
  <div id="root">
        <h3>学生信息</h3><br/>
        <button @click="student.age++">年龄+1岁</button><br/>
        <button @click="addSex">添加性别属性,默认值:男</button><br/>
        <button @click="changeSex">修改性别</button><br/>
        <button @click.once="addStudent">在列表首位添加一个名字</button><br/>
        <button @click="updateFirstName">修改第一个朋友的名字为:张三</button><br/>
        <button @click.once="addHobby">添加一个爱好</button><br/>
        <button @click="updateFirstHobby">修改第一个爱好为:开车</button><br/>
        <button @click.once="deleteFirstHobby">过滤掉爱好中的抽烟</button><br/>
        <h3>姓名:{{student.name}}</h3>
        <h3>年龄:{{student.age}}</h3>
        <h3 v-if="student.sex">性别:{{student.sex}}</h3>
        <h3>朋友们</h3>
        <ul>
            <li v-for="(friend) of student.friends" :key="friend.name">
                {{friend.name}} - {{friend.age}}
            </li>
        </ul>
        <h3>爱好</h3>
        <ul>
            <li v-for="(hobby) of student.hobbies" :key="hobby">
                {{hobby}}
            </li>
        </ul>
    </div>
  const vm = new Vue({
        el: '#root',
        data: function () {
            return {
                student:{
                    name: 'tom',
                    age: 20,
                    sex: '',
                    friends: [
                        {name: 'jerry', age: 18},
                        {name: 'tony', age: 20}
                    ],
                    hobbies: ['抽烟','喝酒','烫头']
                    }
            }
        },
        methods: {
            addSex(){
                Vue.set(this.student,'sex','男')
            },
            changeSex(){
                this.student.sex = '未知'
            },
            addStudent(){
                this.student.friends.unshift({name: 'mike', age: 22})
            },
            updateFirstName(){
                this.student.friends.splice(0, 1 , {name: '张三', age: 18})
            },
            addHobby(){
                this.student.hobbies.push('学习')
            },
            updateFirstHobby(){
                this.student.hobbies.splice(0, 1, '开车')
            },
            deleteFirstHobby(){
                this.student.hobbies.shift()
            }
        }
    })

初始页面

958851058a7e4eb7b352c7414cdfbfc9.png

点击所有按钮后页面:

5da42e5187784add9ac5c1a1740a2696.png


二、收集表单数据

  1. <input type="text">

v-model 收集的是 value 值,用户输入的就是 value 值。

<input type="radio">

v-model 收集的是 value 值,且要给标签配置 value 值。


<input type="checkbox">

没有配置 input 的 value 属性,那么收集的就是 checked (勾选 or 未勾选,是布尔值)

配置input的value属性:

(1)v-model 的初始值是非数组,那么收集的就是 chenked (勾选 or 未勾选,是布尔值)

(2)v-model 的初始值是数组,那么收集的就是 value 组成数组。

  1. 备注:v-model的三个修饰符:
  1. lazy:失去焦点再收集数据。
  2. number:输入字符串转为有效的数字。
  3. trim:输入首尾空格过滤。

实例:把表单的数据收集起来,并且以 JSON 的形式打印输出。

  <div id="root">
        <form @submit.prevent="demo">
            账号:<input type="text" v-model.trim="userInfo.account"><br /><br />
            密码:<input type="text" v-model="userInfo.password"><br /><br />
            年龄:<input type="number" v-model.number="userInfo.age"><br /><br />
            性别:
            男:<input type="radio" name="sex" v-model="userInfo.sex" value="male">
            女:<input type="radio" name="sex" v-model="userInfo.sex" value="female"><br /><br />
            爱好:
            学习<input type="checkbox" v-model="userInfo.hobby" value="学习">
            打游戏<input type="checkbox" v-model="userInfo.hobby" value="打游戏">
            吃饭<input type="checkbox" v-model="userInfo.hobby" value="吃饭">
            <br /><br />
            所属校区
            <select v-model="userInfo.city">
                <option value="">请选择校区</option>
                <option value="北京">北京</option>
                <option value="上海">上海</option>
                <option value="深圳">深圳</option>
                <option value="青岛">青岛</option>
            </select><br /><br />
            其他信息:
            <textarea v-model.lazy="userInfo.other"></textarea><br /><br />
            <input type="checkbox" v-model="userInfo.agree">
            阅读并接受 <a href="javascript:;">《用户协议》</a>
            <button>提交</button>
        </form>
    </div>
  const vm = new Vue({
        el: '#root',
        data: {
            userInfo: {
                account: '',
                password: '',
                age: '',
                sex: 'female',
                hobby: [],
                city: '北京',
                other: '',
                agree: ''
            }
        },
        methods: {
            demo() {
                console.log(JSON.stringify(this.userInfo))
            }
        }
    })

8f84900dd9244d5099ddca9120bdc4f5.png

积跬步至千里,积小流成江海

相关文章
|
9天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
9天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
9天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
8天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
8天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
|
JavaScript 测试技术 容器
Vue2+VueRouter2+webpack 构建项目
1). 安装Node环境和npm包管理工具 检测版本 node -v npm -v 图1.png 2). 安装vue-cli(vue脚手架) npm install -g vue-cli --registry=https://registry.
1052 0
|
9天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
10天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
10天前
|
存储 JavaScript
Vue 组件间如何通信
Vue组件间通信是指在Vue应用中,不同组件之间传递数据和事件的方法。常用的方式有:props、自定义事件、$emit、$attrs、$refs、provide/inject、Vuex等。掌握这些方法可以实现父子组件、兄弟组件及跨级组件间的高效通信。
|
15天前
|
JavaScript
Vue基础知识总结 4:vue组件化开发
Vue基础知识总结 4:vue组件化开发