0
点赞
收藏
分享

微信扫一扫

【尚硅谷】Vue.js从入门到精通笔记(每日更新)

村里搬砖的月野兔 2022-03-12 阅读 120

目录

第1章:Vue核心

1-1.Vue简介

在这里插入图片描述

构建用户界面: 把拿到的数据通过某种办法变成用户可以看到的界面
渐进式: 渐即逐渐,进即递进,也就是说从一个轻量小巧的核心库逐渐递进到各式各样的Vue插件库

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1-2.Vue官网使用指南

在这里插入图片描述

API:就相当于Vue的字典,遇到不会的方法就可以去找API
Awesome:Vue 官方整理的比较好用的包

1-3.搭建Vue开发环境

在这里插入图片描述
关掉Vue控制台的提示:
1.安装Vue开发工具(安装开发工具的提示)
2.Vue.config.productionTip = false; 阻止 vue 在启东市生成生产提示

1-4.初识Vue

按shift强刷报错:
在这里插入图片描述
原因是没有找到页签图标,在根目录放一个页签图标就可以了

Hello小案例:

    <!-- 准备好一个容器 -->
    <div id="root">
        <!-- 差值:即插入值,用{{}}表示,可直接访问data数据 -->
        <h1>Hello,{{name}}</h1>
        <h1>我的年龄是:18</h1>
    </div>
    
    <script>
        // 创建Vue实例
        new Vue({
            // el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
            // 也可以是节点(document.getElementById('root')
            el: '#root',
            // data中用于存储数据,数据供el所指定的容器去使用,值暂时先写成一个对象(函数)
            data: {
                name: '尚硅谷',
                age: 18
            }
        });
    </script>

总结:

  1. 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;
  2. root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;
  3. root容器里的代码被称为【Vue模板】;
  4. Vue实例和容器是一一对应的;
  5. 真实开发中只有一个Vue实例,并且会配合着组件一起使用;
  6. {{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性
  7. 一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新

注意区分:JS表达式和JS代码(语句):

  1. 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
    (1)a
    (2)a+b
    (3)demo(1)
    (4)x === y ‘a’ : ‘b’

  2. js代码(语句)
    (1)if(){}
    (2)for(){}

1-5.模板语法

概念: 容器里面的代码就是模板语法

模板语法分为两大类:

  1. 差值语法:
    功能:用于解析标签体内容。
    写法:{{xxx}},xxx是js表达式且可以直接读取到data中的所有属性。
  2. 指令语法:
    功能:用于解析标签(包括:标签属性、标签体内容、绑定事件。。。)
    备注:Vue中有很多的指令,且形式都是:v-。
    举例:v-bind:hred="xxx" 或 简写为 :href="xxx",xxx同样要写js表达式且可以直接读取到data中的所有属性。

错误示例:

<a href="url"></a>   <!-- 此时的url只是一个字符串 -->
<a href={{url}}></a> <!-- 差值写在属性的写法已经被Vue弃用 -->
<a :href="url"></a>  <!-- 正确用法 -->

1-6.数据绑定

Vue中有2种数据绑定的方式:

  1. 单向绑定(v-bind):数据只能从data流向页面。
  2. 双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
    备注:
    1.双向绑定一般都应用在表单元素上(如:input、select等)
    2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。

演示:

<!-- 单向数据绑定 !-->
<input type="text" :value="name">
<!-- 双向数据绑定 !-->
<input type="text" v-model="name">

错误示例:
以下代码是错误的,因为v-model只能应用在表单类元素(输入类元素)上

<h2 v-model:x="name">hello</h2> 

1-7.el和data的两种写法

  1. el有2种写法:
    (1)new Vue时候el属性;
    (2)先创建Vue实例,随后再通过vm.$mount(’#root’)指定el的值

  2. data有2种写法:
    (1)对象式
    (2)函数式
    如何选择?目前哪种写法都可以,以后学到组件时,data必须使用函数式,否则会报错

  3. 一个重要的原则:
    只要是Vue所管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了,而是window

    const v = new Vue({
        // el: '#root', //el第一种写法
        // data: { //data第一种写法
        //     name: '尚硅谷' 
        // },
        data() { //data第二种写法
            return {
                name: '尚硅谷'
            }
        }
    })
    
    v.$mount('#root') //el第二种写法
    

1-8.MVVM模型

在这里插入图片描述

MVVM模型:

  1. M:模型(Model):data中的数据
  2. V:视图(View):Vue模板
  3. VM:视图模型(ViewModel):Vue实例对象(绑定数据,dom监听)

观察发现:

  1. data中所有的属性,最后都出现在了vm身上
  2. vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接访问

1-9.数据代理

1-9-1.回顾Object.defineProperty方法

作用: 给对象定义属性,并对该属性进行一些高级的设置
参数: 1. 需要添加属性的对象
2. 添加属性名称
3. 配置项(配置属性值或一些其它的参数)
注意: 定义的属性是浅紫色的,说明它是不可枚举(遍历)的

常用配置属性

作用

value

设置属性值

enumerable

控制属性是否可以枚举,默认值为false

writable

控制属性是否可以被修改,默认值为false

configurable

控制属性是否可以被删除,默认值为false

get函数

当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值

set函数

当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值

怎样让一个变量和一个对象的值关联起来?

let number = 18;
let person = {
        name: '张三',
        sex: '男'
    }
Object.defineProperty(person, 'age', {
    get: function() {
        return number;
    }
})

为什么无法直接修改person.age的值,怎么修改?

let number = 18;
let person = {
        name: '张三',
        sex: '男'
    }
Object.defineProperty(person, 'age', {
    get: function() {
        return number;
    },
    set: function(value) {
    number = value;
	}
})

方法一:因为age是不可写的,可以设置writable属性或直接修改与age关联的number
方法二:通过set函数把修改的值赋值给number

知识拓展:
Object.keys
作用:这个方法可以把传入对象所有属性的属性名提取出来变成数组
参数:对象

1-9-2.何为数据代理

定义: 通过一个对象代理对另一个对象中属性的操作(读/写)

// 通过obj2访问并且修改obj的x
let obj = {x: 100}
let obj2 = {y: 200}
Object.defineProperty(obj2, 'x', {
    get() {
        return obj.x;
    },
    set(value) {
        obj2.x = value;
    }
})

1-9-3.Vue中的数据代理

  1. Vue中的数据代理:
    通过 vm对象 代理 vm._data对象(就是你配置的data对象) 中的属性操作(读/写)
  2. Vue中数据代理的好处:
    更加方便的操作data中的数据
  3. 基本原理:
    通过Object.defineProperty把data对象中所有属性都添加到vm上,并为其指定一个getter/setter,在getter/setter内部去操作(读/写)data中对应的属性。

在这里插入图片描述

备注:vm._data展开后你会发现它和data并不一致,这是因为Vue底层做了数据劫持而非数据代理,其目的就是为实现响应式的操作,后面会讲到。
在这里插入图片描述

1-10.事件处理

1-10-1.事件的基本使用

  1. 使用 v-on:xxx@xxx 绑定事件,其中xxx是事件名;

  2. 事件的回调需要配置在methods对象中,最终会再vm上;

  3. methods中配置的函数,不要用箭头函数!否则this就不是vm了而是window;

  4. methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象;

  5. @click="demo"@click="demo($event)" 效果一致,前者默认参数就是事件对象,后者要用$event才能生成事件对象,并且可以传多个参数;

    <button @click=“demo”>点我提示信息

    <button @click=“showInfo(66)”>点我提示信息

    <button @click=“showInfo(66,$event)”>点我提示信息

备注:method上面的方法最终也会出现在vm上面,但它并没有作数据代理,因为没有必要,函数一旦定义好就直接拿来用,不会再改。

1-10-2.事件修饰符

事件修饰符

描述

prevent

阻止默认事件(常用)

stop

阻止事件冒泡(常用)

once

事件只触发一次(常用)

capture

使用事件的捕获模式

self

只有event.target是当前操作的元素时才触发事件

passive

先执行默认行为,后执行回调函数

示例:
1.阻止默认事件

<a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a> <!-- 加了阻止了链接跳转 -->

2.阻止事件冒泡

<div class="demo1" @click="showInfo">
	<button @click.stop="showInfo">点我提示信息</button> <!-- 没加会触发外层事件,加了则不会 -->
</div>

3.事件只触发一次

<button @click.once="showInfo">点我提示信息</button> <!-- 第一次点会触发事件,第二次点则不会 -->

4.使用事件的捕获模式(事件流 分为 捕获冒泡
在这里插入图片描述

<div class="box1" @click.capture="showMsg(1)">
    div1
    <div class="box2" @click="showMsg(2)">  <!-- 没加输出1,2,加了输出2,1 -->
        div2
    </div>
</div>

5.只有event.target是当前操作的元素时才触发事件

<div class="demo1" @click.self="showInfo">
	<!-- 点击button,div和button的事件源都是button -->
	<!-- 没加会触发div的事件,没加则不会,因为self要求事件源是本身 -->
    <button @click="showInfo">点我提示信息</button>
</div>

6.事件的默认行为立即执行,无需等待事件回调执行完毕

<ul @wheel.passive="demo" class="list"> <!--加了先滚动后回调,没加先回调后滚动-->
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>

为什么滚动了鼠标,滚动条却不往下走?
因为wheel事件会先触发滚动事件,然后会去执行回调回调执行完了才会执行默认行为,而passive就是为了解决这种问题,它会先执行默认行为,然后再走回调(scrool同效)

好处:可以一定程度上进行优化,常用在移动端的项目(手机、平板),但用的比较少。

1-10-3.键盘事件

1.Vue中常用的按键别名:

回车 => enter
删除 => delete(捕获“删除(delete)”和“退格(BackSpace)”键)
退出 => esc
空格 => space
换行 => tab(特殊,必须配合 keydown 去使用)
上 => up
下 => down
左 => left
右 => right

2.Vue未提供别名的案件,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)

<input type="text" placeholder="按下回车提示输入" @keyup.caps-lock="showInfo">

3.系统修饰键(用法特殊):ctrl、alt、shift、meta
(1)配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其它键,事件才被触发。(此时的e.key值是其它键,而不是系统修饰键)
(2)配合keydown使用:正常触发事件。

4.也可以使用keyCode去指定具体的按键(不推荐,因为不同的键盘编码可能会不统一,尽量用键名)

<input type="text" placeholder="按下回车提示输入" @keyup.13="showInfo">

5.Vue.config.keyCodes.自定义别名 = 键码,可以去指定按键别名

<!-- Vue.config.keyCodes.huiche = 13; -->
<input type="text" placeholder="按下回车提示输入" @keyup.huiche="showInfo">

1-10-4.事件总结

修饰符小技巧:事件修饰符可以连着写

<!-- 阻止默认事件和冒泡 -->
<div class="demo1" @click="showInfo">
	<a href="http://www.atguigu.com" @click.stop.prevent="showInfo">点我提示信息</a>
</div>


<!-- 按 ctrl + y 才触发(系统修饰符 + 键名) -->
<input type="text" placeholder="按下回车提示输入" @keyup.ctrl.y="showInfo">

1-11.计算属性与监视

1-11-1.姓名案例

差值语法实现:

<div id="root">
	姓:<input type="text" v-model="firstName">
	名:<input type="text" v-model="lastName">
	姓名:<span>{{firstName.slice(0,3)}}-{{lastName}}</span>
</div>

<script>
    const vm = new Vue({
        el: '#root',
        data: { firstName: '张', lastName: '三' }
    })
</script>

methods实现:

<div id="root">
    姓:<input type="text" v-model="firstName">
    名:<input type="text" v-model="lastName"> 
    姓名:<span>{{fullName()}}</span>
    <button @click="fullName">点我</button>
</div>

<script>
    const vm = new Vue({
        el: '#root',
        data: { firstName: '张', lastName: '三' },
        methods: {
            fullName() { return this.firstName + '-' + this.lastName } // this指向vm
        }
    })
</script>

computed实现:

<div id="root">
    姓:<input type="text" v-model="firstName">  
    名:<input type="text" v-model="lastName"> 
    姓名:<span>{{fullName}}</span>
</div>

<script>
    const vm = new Vue({
        el: '#root',
        data: { firstName: '张', lastName: '三' },
        computed: {
            fullName: {
                get() {
                    // 此处的this是vm
                    return this.firstName + '-' + this.lastName
                }
            }
        }
    })
</script>

1-11-2.计算属性

对于Vue来说,data里的配置项就是属性 。

而计算属性,就是拿着写完的属性去加工计算,生成一个全新的属性。

计算属性直接被挂载到vm上,直接读取使用即可(_data里面没有计算属性)。

const vm = new Vue({
    el: '#root',
    data: {
        firstName: '张',
        lastName: '三'
    },
    computed: {
        fullName: {
            get() {
             	// 此处的this是vm
                return this.firstName + '-' + this.lastName;
            }
        }
    }
})

get有什么作用?
当有人读取fullName时,get就会被调用,且返回值就作为fullName的值。
(底层就是用Object.defineProperty的getter/setter实现的)

get什么时候被调用?

1.初次读取时会执行一次(往后就会取缓存里的数据)
2.所依赖的数据发生变化时会被再次调用(所以不用担心修改了值还会从缓存里获取)

<!-- Vue模板里有4个fullName,为什么get只被调用了一次? 
	 因为Vue底层为computed做了一个缓存机制,重复的计算属性会到缓存里面获取 -->
<div id="root">
	<span>{{fullName}}</span>
	<span>{{fullName}}</span>
	<span>{{fullName}}</span>
	<span>{{fullName}}</span>
</div>

<script>
    const vm = new Vue({
        el: '#root',
        data: {
            firstName: '张',
            lastName: '三'
        },
        computed: {
            fullName: {
                get() {
                	console.log('get被调用了'); // 只输出了一次 “get被调用了”
                    return this.firstName + '-' + this.lastName
                }
            }
        }
    })
</script>

set什么时候被调用?
当fullName被修改时。

如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生变化。

<!-- 当fullName被修改时页面并没有发生变化,原因是set并没有改到firstName和lastName,它只做了输出。
	 所以要想页面也发生变化,那就得给set做一个加工,让它修改到firstName和lastName。 -->
<script>
    const vm = new Vue({
        el: '#root',
        data: {
            firstName: '张',
            lastName: '三'
        },
        computed: {
            fullName: {
                get() {
                	console.log('get被调用了'); // 只输出了一次 “get被调用了”
                    return this.firstName + '-' + this.lastName
                },
                set(value) {
					console.log('set', value);
					// 格式:张-三
					const arr = value.split('-');
					this.firstName = arr[0];
					this.lastName = arr[1];
				}
            }
        }
    })
</script>

computed对比methods:
computed有缓存机制(复用),效率更高、调试方便(devtools上会有一个computed的分类)。
methods函数出现几次就调用几次,效率比较低。

计算属性的简写:
一般来说计算属性是不修改的,更多是读取出来展示。

并不是什么时候都能用简写,只有考虑读取,不考虑修改的时候才能用简写形式。

const vm = new Vue({
    el: '#root',
    data: {
        firstName: '张',
        lastName: '三'
    },
    computed: {
        fullName() {
            console.log('get被调用了');
            return this.firstName + '-' + this.lastName
        }
    }
})

1-11-3.天气案例

<div id="root">
    <h2>今天天气很{{info}}</h2>
    <!-- <button @click="isHot = !isHot">切换天气</button> -->
    <button @click="changeWeather">切换天气</button>
</div>
<script>
    Vue.config.productionTip = false;

    new Vue({
        el: '#root',
        data: {
            isHot: true
        },
        computed: {
            info() {
                return this.isHot ? '炎热' : '凉爽';
            }
        },
        methods: {
            changeWeather() {
                this.isHot = !this.isHot
            }
        },
    })
</script>

1-11-4.监视属性

监视属性watch:
1.当被监视的属性变化时,回调函数自动调用,进行相关操作;
2.监视的属性必须存在,才能进行监视!!(除了data属性,computed属性也能监视)
3.监视的两种写法:
(1)new Vue时传入watch配置;
(2)通过vm.$watch监视;
(明确要监视哪些属性的时候用第一个。创建实例的时候不知道要监视谁,后续根据用户的一些行为然后才知道要监视哪个属性就用第二个)

watch配置属性:

属性

描述

immediate (立即的)

初始化时让handlder调用一下

handler(newVal, oldVal)

当监视的属性发生改变的时候调用,参数可以拿到改变前后的值

deep

深度监听,可以监测多层级数据的改变

// 写法一
const vm = new Vue({
    el: '#root',
    data: {
        isHot: true
    },
    computed: {
    methods: {
    watch: {
        isHot: {
            immediate: true,
            handler(newValue, oldValue) {
                console.log('isHot被修改了', newValue, oldValue);
            }
        }
    }
})

// 方法二
vm.$watch('isHot', { // 注意这里监视的属性要写字符串,配置对象的写法和上一种完全一致
    immediate: true,
    handler(newValue, oldValue) {
        console.log('isHot被修改了', newValue, oldValue);
    }
})

深度监视:
1.Vue中的watch默认不监测对象内部值的变化(监测一层)
2.配置deep:true可以监测对象内部值变化(监测多层)

备注:
(1)Vue默认是可以监视到多层级数据的改变的(修改number.a页面发生改变可以看出)。但是watch属性默认是不可以的,要想可以就得打开深度监视(为了效率)。
(2)使用watch时根据数据的具体结果,决定是否采用深度监视。

const vm = new Vue({
    el: '#root',
    data: {
        isHot: true,
        numbers: {
            a: 1,
            b: 1
        }
    },
    computed: {
    methods: {
    watch: {
        isHot: {
        // 监视多级结构中某个属性的变化————加上引号(原始写法)   
        // 'numbers.a': {
        //     handler() {
        //         console.log('a被改变了');
        //     }
        // }
        // 监视多级结构中所有属性的变化————开启深度模式
        'numbers': {
            deep: true,
            handler() {
                console.log('numbers被改变了');
            }
        }
    }
})

监视属性的简写:
当配置项只有handler的时候才可以简写。

const vm = new Vue({
    el: '#root',
    data: {
        isHot: true
    },
    computed: {
        info() {
            return this.isHot ? '炎热' : '凉爽';
        }
    },
    methods: {
        changeWeather() {
            this.isHot = !this.isHot
        }
    },
    watch: {
        // 正常写法:
        /* isHot: {
            // immediate: true,
            // deep:true,
            handler(newValue, oldValue) {
                console.log('isHot被修改了', newValue, oldValue);
            }
        }, */
        // 简写:
        isHot(newValue, oldValue) {
            console.log('isHot被修改了', newValue, oldValue);
        }
    }
});

// 正常写法:
vm.$watch('isHot', {
    // immediate: true,
    // deep:true,
    handler(newValue, oldValue) {
        console.log('isHot被修改了', newValue, oldValue);
    }
});

// 简写:
vm.$watch('isHot', function(newValue, oldValue) {
    console.log('isHot被修改了', newValue, oldValue);
});

watch对比computed:
1.computed能完成的功能,watch都能完成。
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。

两个重要的小原则:
1.所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数、Promise的回调函数等),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。

还是拿上一个天气案例作对比:

const vm = new Vue({
    el: '#root',
    data: {
        firstName: '张',
        lastName: '三',
        fullName: '张-三'
    },
    watch: {
        firstName(val) {
            this.fullName = val + '-' + this.lastName;
        },
        lastName(val) {
            this.fullName = this.firstName + '-' + val;
        }
    }
})

上面代码是命令式且重复的。将他们与计算属性的版本进行比较:

const vm = new Vue({
    el: '#root',
    data: {
        firstName: '张',
        lastName: '三'
    },
    computed: {
        fullName() {
            return this.firstName + '-' + this.lastName
        }

好得多了,不是吗?

延迟一秒钟后再响应:

const vm = new Vue({
    el: '#root',
    data: {
        firstName: '张',
        lastName: '三',
        fullName: '张-三'
    },
    watch: {
        firstName(val) {
            // 注意这里用普通函数自带this 默认指向window,箭头函数没有this 会往上继承
            setTimeout(() => {
                this.fullName = val + '-' + this.lastName;
            }, 1000)
        },
        lastName(val) {
            setTimeout(() => {
                this.fullName = this.firstName + '-' + val;
            }, 1000)
        }
    }
})

watch轻松完成。

const vm = new Vue({
    el: '#root',
    data: {
        firstName: '张',
        lastName: '三'
    },
    computed: {
        fullName() {
        	// fullName值等于空,因为fullName没有返回值,返回值给了定时器的回调
        	setTimeout(() => {
    			return this.firstName + '-' + this.lastName;
			}, 1000)
        }

相比较之下,computed却无法实现,因为它无法执行异步任务。

1-12.class与style绑定

class样式:
写法:class="xxx" xxx可以是字符串、对象、数组。
字符串写法适用于:类名不确定,要动态获取。
对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。

style样式:
:style="{fontSize: xxx}"其中xxx是动态值。(注意样式名得是小驼峰)
:style="[a,b]"其中a、b是样式对象。

<div id="root">
    <!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
    <div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/>
    <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
    <div class="basic" :class="classArr">{{name}}</div> <br/>
    <!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
    <div class="basic" :class="classObj">{{name}}</div> <br/>
    
    <!-- 绑定style样式--对象写法 -->
    <div class="basic" :style="styleObj">{{name}}</div> <br/>
    <!-- 绑定style样式--数组写法 -->
    <div class="basic" :style="styleArr">{{name}}</div>
</div>

<script>
    const vm = new Vue({
        el: '#root',
        data: {
            name: '尚硅谷',
            mood: 'normal',
            classArr: ['atguigu1', 'atguigu2', 'atguigu3'],
            classObj: {
                atguigu1: false,
                atguigu2: false
            },
            styleObj: {
                fontSize: '40px',
                color: 'red'
            },
            styleObj2: {
                backgroundColor: 'orange'
            },
            styleArr: [{
                fontSize: '40px',
                color: 'red'
            }, {
                backgroundColor: 'gray'
            }]

        },
        methods: {
            changeMood() {
                const arr = ['normal', 'happy', 'sad'];
                const index = Math.floor(Math.random() * 3);
                this.mood = arr[index];

            }
        },
    })
</script>

1-13.条件渲染

  1. v-if
    写法:
    (1)v-if=“表达式”
    (2)v-else-if=“表达式”
    (3)v-else=“表达式”

    适用于:切换频率较低的场景。
    特点:不展示的DOM元素直接被移除。
    注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。

  2. v-show
    写法:v-show=“表达式”
    适用于:切换频率较高的场景。
    特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉

  3. 备注: 使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。

    当前的n是{{n}}

1-14.列表渲染

1-14-1.基本列表

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

<div id="root">
	<!-- 遍历数组 -->
	<h2>人员列表(遍历数组)</h2>
	<ul>
		<li v-for="(p,index) of persons" :key="index">
			{{p.name}}-{{p.age}}
		</li>
	</ul>
	<!-- 遍历对象 -->
	<h2>汽车信息(遍历对象)</h2>
	<ul>
		<li v-for="(value,k) of car" :key="k">
			{{k}}-{{value}}
		</li>
	</ul>
	<!-- 遍历字符串 -->
	<h2>测试遍历字符串(用得少)</h2>
	<ul>
		<li v-for="(char,index) of str" :key="index">
			{{char}}-{{index}}
		</li>
	</ul>
	
	<!-- 遍历指定次数 -->
	<h2>测试遍历指定次数(用得少)</h2>
	<ul>
		<li v-for="(number,index) of 5" :key="index">
			{{index}}-{{number}}
		</li>
	</ul>
</div>

<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			persons:[
				{id:'001',name:'张三',age:18},
				{id:'002',name:'李四',age:19},
				{id:'003',name:'王五',age:20}
			],
			car:{
				name:'奥迪A8',
				price:'70万',
				color:'黑色'
			},
			str:'hello'
		}
	})
</script>

1-14-2.key的原理

面试题:react、vue中的key有什么作用?(key的内部原理)

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

2.对比规则:
(1)旧虚拟DOM中找到了与新虚拟DOM相同的key:
① 若虚拟DOM中内容没变, 直接使用之前的真实DOM!
② 若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2)旧虚拟DOM中未找到与新虚拟DOM相同的key,创建新的真实DOM,随后渲染到到页面。

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

4.开发中如何选择key:
(1)最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
(2)如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
使用index作为key是没有问题的。

示例:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

<div id="root">
	<!-- 遍历数组 -->
	<h2>人员列表(遍历数组)</h2>
	<button @click.once="add">添加一个老刘</button>
	<ul>
		<li v-for="(p,index) of persons" :key="index"> <!-- 这里不要用index哈 -->
			{{p.name}}-{{p.age}}
			<input type="text">
		</li>
	</ul>
</div>

<script type="text/javascript">
	new Vue({
		el:'#root',
		data:{
			persons:[
				{id:'001',name:'张三',age:18},
				{id:'002',name:'李四',age:19},
				{id:'003',name:'王五',age:20}
			]
		},
		methods: {
			add(){
				const p = {id:'004',name:'老刘',age:40}
				this.persons.unshift(p)
			}
		},
	})
</script>

1-14-3.列表过滤

当computed和watch都能实现的时候,优先使用computed

<div id="root">
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <ul>
        <li v-for="(p,index) of filPersons" :key="index">
            {{p.name}}-{{p.age}}-{{p.sex}}
        </li>
    </ul>
</div>

<script type="text/javascript">
    // watch实现:
    /* 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: '男'
            }],
            filPersons: []
        },
        watch: {
            keyWord: {
                immediate: true,
                handler(val) {
                    this.filPersons = this.persons.filter((p) => {
                        return p.name.indexOf(val) !== -1;
                    })
                }
            }
        }
    }) */

    // computed实现:
    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) => {
                    return p.name.indexOf(this.keyWord) !== -1;
                })

            }
        }
    })
</script>

1-14-4.列表排序

这个案例充分体现了computed功能的强大,只要有任何一个属性发生了变化,整个计算属性都会重新办进行计算。

<div id="root">
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <button @click="sortType = 1">年龄升序</button>
    <button @click="sortType = 2">年龄降序</button>
    <button @click="sortType = 0">原顺序</button>
    <ul>
        <li v-for="(p,index) of filPersons" :key="index">
            {{p.name}}-{{p.age}}-{{p.sex}}
        </li>
    </ul>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false

    // computed实现:
    const vm = new Vue({
        el: '#root',
        data: {
            keyWord: '',
            persons: [{
                id: '001',
                name: '马冬梅',
                age: 30,
                sex: '女'
            }, {
                id: '002',
                name: '周冬雨',
                age: 31,
                sex: '女'
            }, {
                id: '003',
                name: '周杰伦',
                age: 18,
                sex: '男'
            }, {
                id: '004',
                name: '温兆伦',
                age: 21,
                sex: '男'
            }],
            sortType: 0 //0原顺序   @click="sortType = 0"1降序  2升序
        },
        computed: {
            filPersons() {
                const arr = this.persons.filter((p) => {
                    return p.name.indexOf(this.keyWord) !== -1;
                });
                // 判断一下是否需要排序
                if (this.sortType) {
                    arr.sort((p1, p2) => {
                        return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age
                    })
                }
                return arr;
            }
        }
    })
</script>

知识拓展:
sort(a,b)数组方法,a-b升序,b-a降序,更改原数组。

1-14-5.更新时的一个问题

1-14-6.Vue检测数据改变的原理

1-14-7.模拟一个数据监测

1-14-8.Vue.set的使用

1-14-9.Vue监测数据改变的原理_数组

1-14-10.总结Vue数据监测

1-15.收集表单数据

1-16.Vue实例声明周期

1-17.过度&动画

1-18.过滤器

1-19.内置指令与自定义指令

1-20.自定义插件

第2章:Vue组件化编程

第3章:使用Vue脚手架

第4章 :Vue中的ajax

第5章:Vuex

第6章:Vue-router

第7章:Vue UI组件库

举报

相关推荐

0 条评论