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

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

相关文章
|
3天前
|
JavaScript
Vue中如何设置在执行删除等危险操作时给用户提示(二次确认后执行对应的操作)
这篇文章介绍了在Vue项目中如何实现执行删除等危险操作时的二次确认机制,使用Element UI的`el-popconfirm`组件来弹出确认框,确保用户在二次确认后才会执行删除操作。
Vue中如何设置在执行删除等危险操作时给用户提示(二次确认后执行对应的操作)
|
3天前
|
JavaScript
如何创建一个Vue项目(手把手教你)
这篇文章是一篇手把手教读者如何创建Vue项目的教程,包括使用管理员身份打开命令行窗口、找到存放项目的位置、通过vue-cli初始化项目、填写项目信息、进入项目目录、启动项目等步骤,并提供了一些常见第三方库的引入方法。
如何创建一个Vue项目(手把手教你)
|
3天前
|
JavaScript
如何在Vue页面中引入img下的图片作为背景图。../的使用
这篇文章介绍了在Vue页面中如何引入`img`目录下的图片作为背景图,提供了两种使用相对路径的方法。第一种是使用`../assets/img/`作为路径引入图片,第二种是使用`../../assets/img/`作为路径。文章还展示了使用这些方法的代码实现和效果展示,并鼓励读者学无止境。
如何在Vue页面中引入img下的图片作为背景图。../的使用
|
3天前
|
JavaScript
如何查看Vue使用的版本
这篇文章介绍了如何在项目中查看Vue及其相关库的版本信息,比如element-ui和element-china-area-data。要查看Vue的版本,需要查看项目中的`package.json`文件,在`dependencies`部分可以找到Vue的版本号。如果需要查询不同版本的兼容性,可以访问相应的官方文档或资源网站。
|
3天前
|
存储 JavaScript 前端开发
Vue中如何通过三元运算符来展示不同的操作
这篇文章讲述了在Vue中如何使用三元运算符结合v-if指令来根据订单的不同状态展示不同的操作按钮,例如在待发货状态显示退款按钮,在待付款或完成状态显示删除按钮。
|
3天前
|
前端开发
StringBoot+Vue实现游客或用户未登录系统前、可以浏览商品等信息、但是不能购买商品或者加入购物车等操作。登录系统显示用户的登录名(源码+讲解)
这篇文章介绍了使用StringBoot+Vue实现用户登录状态判断的方法,包括前端加载用户信息和后端设置session的源码示例。
|
3天前
|
JavaScript 编译器
成功解决:Module build failed: Error: Vue packages version mismatch
这篇文章记录了解决Vue项目中遇到的"Module build failed: Error: Vue packages version mismatch"错误的步骤,原因是项目中Vue依赖的版本不一致,解决方法是删除`node_modules`后重新安装指定版本的Vue和`vue-template-compiler`,确保版本匹配,最终成功运行项目。
成功解决:Module build failed: Error: Vue packages version mismatch
|
3天前
|
JavaScript
在Vue中使用Avue、配置过程以及实际应用
这篇文章介绍了作者在Vue项目中集成Avue组件库的完整过程,包括安装、配置和实际应用,展示了如何利用Avue实现动态表单和数据展示的功能。
在Vue中使用Avue、配置过程以及实际应用
|
4天前
|
JavaScript
Vue devDependencies 与 dependencies 能别
Vue devDependencies 与 dependencies 能别
10 3
|
3天前
|
JavaScript
如何通过点击商品的信息(图片或者文字)跳转到更加详细的商品信息介绍(前后端分离之Vue实现)
该博客文章介绍了如何在Vue 2框架下实现前后端分离的商品信息展示和详情页跳转,包括排序筛选、详情展示、加入购物车和分享功能。
如何通过点击商品的信息(图片或者文字)跳转到更加详细的商品信息介绍(前后端分离之Vue实现)