开始于‎2022‎年‎3‎月‎4‎日

没看的page:

038_收集表单数据=>047自定义指令


初识vue

  1. 想让Vue工作,必须创建vue实例,并至少传入一个配置属性
  2. 容器中的代码依然符合HTML规范,只不过混入了一些特殊的vue语法
  3. 容器中的代码被称为【Vue模板】
  4. 容器和实例一定是一一对应
  5. 双花括号{{xxx}}插值语法)内xxxjs表达式,且xxx可以自动读取data中所有属性
  6. 真实开发中只有一个Vue实例,且会配合组件一起使用

模板语法

模板语法分为插值语法指令语法

  1. 插值语法用来解析标签体中的内容

  2. 指令语法用于解析标签(包括:标签属性、标签体内容、绑定事件)

    v-bind:href="xxx"可以简写为:href="xxx"

    xxx同样为js表达式,且可以直接读取到data中的所有属性

数据绑定

单向数据绑定:v-bind

v-bind单项数据绑定

双向数据绑定:v-model

v-model双向数据绑定

v-model只能应用在表单类元素(输入类元素)上

这类元素都有value值,因为v-model默认收集value值,所以v-model:value的简写形式是v-model

两种指令的简写:

简写

el与data的两种写法

el

  • 在new实例时就定义好el

  • 后续使用v.$mount('#root')再添加(更灵活)

    mount:挂载

data

  • 对象式:写成对象

  • 函数式:将data写成函数,且该函数需要返回对象

    data函数应该写成普通函数,而非箭头函数

    参见vue中箭头函数和普通函数

    写法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    const v=new Vue({
    //el:'#root',
    data(){
    console.log('@@@',this)
    return {
    name:'jack'
    }
    }
    //data:{
    // name:'HUST'
    //}
    })

由Vue管理的函数,不能写成箭头函数。一旦写成箭头函数,this指针就不再是Vue实例了。

MVVM模型

M:Model模型,对应data中的数据

V:View视图,模板

VM:ViewModel,Vue实例对象

MVVM

MVVM

因此在文档中,经常用vm(ViewModel的缩写)这个变量名来表示Vue实例。


data中的所有属性,最后都出现在了vm身上

vm身上所有属性,以及Vue原型上所有属性,在Vue模板中都可以直接使用

数据代理

Object.defineProperty方法

为对象添加属性,与后面的Vue.set()区分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let person={
name:'张三',
sex:'男'
}
Object.defineProperty(person,'age',{
value:18,
//enumerable:true
//控制属性是否可以枚举,默认值是false

//writable:true
//控制属性是否可以被修改,默认值是false

//configurable:true
//控制属性是否可以被删除,默认值是false
})
//为对象添加属性:Object.defineProperty方法
console.log(person)

通过这种方式添加的属性:不可枚举(即不能遍历),且无法修改值,且无法删除

除非修改上述属性


get()函数

1
2
3
4
5
6
7
8
9
10
11
let number=20
let person={
name:'张三',
sex:'男'
}
Object.defineProperty(person,'age',{
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get(){
return number
}
})

set()函数

1
2
3
4
5
6
7
8
9
10
11
let number=20
let person={
name:'张三',
sex:'男'
}
Object.defineProperty(person,'age',{
//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
set(value){
number=value
}
})

通过get()来帮age从number处取值,通过set()来将person.age设置的值赋给number

getter将number绑定给age,setter将age绑定给number

定义数据代理

数据代理:通过一个对象代理对另一个对象中属性的操作

见下例:

1
2
3
4
5
6
7
8
9
10
let obj={x:100}
let obj2={y:200}
Object.defineProperty(obj2,'extra',{
get(){
return obj.x
},
set(value){
obj.x=value
}
})

相当于给obj2添加了名为extra的属性,并将该属性绑定到obj.x

getter会导致extra的值从obj.x处获取

setter会导致修改extra的值时会同时修改obj.x的值

结果见下图:

数据代理

Vue中的数据代理

见下面的代码:

1
2
3
4
5
6
7
const vm=new Vue({
el:'#root',
data:{
name:'尚硅谷',
address:'洪福科技园'
}
})

这里vm中即有name和address两个值,可以通过vm.namevm.address直接访问,相当于getter

Vue实例中的data对象交给了vm,vm将data存在了自己的_data

如下图:

Vue中的数据代理

Vue中的数据代理图示:

数据代理


  • 总结:

    • Vue中数据代理:通过vm对象来代理data对象中属性的操作(读/写)

    • 好处:更加方便操作data中的数据

    • 基本原理:

      通过Object.defineProperty()把data对象中的所有属性添加到vm上

      为每一个添加到vm上的属性,都制定一个getter/setter

      在getter/setter内部去 读/写 data中对应的属性

事件处理

事件的基本处理

  1. 使用v-on:xxx@xxx都能绑定事件,其中xxx是事件名。在本节中使用v-on:click点击事件举例,v-on: 指令可以简写成 @
  2. 事件的==回调==需要配置在Vue实例的method对象中,最终会在vm上
  3. methods中配置的函数,不要用箭头函数,要用普通函数,否则this就不是vm了
  4. methods中配置的函数,都是被Vue管理的函数,this指向的是vm或组件实例对象
  5. @click="demo"@click="demo($event)"效果一致,但带个括号可以在括号里传参数

事件修饰符

写法:<a href="https:www.baidu.com" @click.prevent="showInfo">点我看蟹黄堡秘方</a>

Vue中的事件修饰符:

  1. prevent:阻止默认事件 (常用)
  2. stop:阻止事件冒泡 (常用)
  3. once:事件只触发一次 (常用)
  4. capture:使用事件的捕获模式
  5. self:只有event . target是当前操作的元素是才触发事件
  6. passive:事件的默认行为立即执行,无需等待事件回调执行完毕

修饰符是可以连着写的:@click.prevent.stop="showInfo"

键盘事件

keyup是按键弹起的时候触发,keydown是按键按下的时候触发

Tab特殊,要配合keydown使用

通过这种形式触发:

1
2
3
4
5
6
<input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo">
methods:{
showInfo(e){
console.log(e.target.value)
}
}
键盘事件

按键修饰也是可以连着写的:@keyup.ctrl.y="showInfo"


计算属性

姓名案例:(3种写法)

  1. 插值语法

    v-model:value是双向数据绑定,简写为v-model

  2. methods

    数据(Model)驱动视图(View):数据变化的时候视图中也会随之变化,修改模板的时候都会引起容器的重新解析,会导致在容器中的函数调用重新执行(在插值语法中写方法)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
          姓名:<span>{{fullname()}}</span>
    //调用fullname这个methods需要带括号`()`
    ...
    methods:{
    fullname(){
    console.log('@')
    return this.surname+'-'+this.name;
    //注意上面的this.name而非name
    }
    }
  3. 计算属性

    普通属性是data中的属性,类似键值对

    计算属性写在computed

    get()的调用时机:1、初次读取fullname时;2、所依赖的数据发生变化时

    这正是类似的例子里计算属性相较于methods的优势:只会在必要时调用,会有缓存

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const vm=new Vue({
    el:'#root',
    data:{
    name:'三',
    surname:'张'
    },
    computed:{
    fullname:{
    get(){
    return this.surname+'-'+this.name
    },
    set(value){
    const arr=value.split('-')
    this.surname=arr[0]
    this.name=arr[1]
    }
    }
    }

计算属性

  1. 定义:要用的属性不存在,要通过已有属性计算得来。

  2. 原理:底层借助了objcet.defineproperty方法提供的getter和setter

  3. get函数什么时候执行?

    1. 初次读取时会执行一次。
    2. 当依赖的数据发生改变时会被再次调用。
  4. 优势:与methods实现相比, 内部有缓存机制(复用),效率更高,调试方便。

  5. 备注:

    1. 计算属性最终会出现在vm上,直接读取使用即可。
    2. 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
  6. 简写:

    当不需要修改计算属性的value时(即不需要setter时)可以将计算属性简写成方法的形式,这个函数就是原来的get()函数

    计算属性简写

监视属性

使用旧知识写天气案例:

小小的天气案例,用到了计算属性computed,用到了方法methods

可以把不用将点击事件click绑定至changeWeather方法,而是直接在click后面引号中写上简单的isHot=!isHot


使用监视属性写天气案例:

watch监视两种方法

watch的简写与计算属性computed类似:

(在不使用watch中的immediate、deep属性时可以采用简写)

watch的简写


监视属性总结:

  1. 当被监视的属性变化时,回调函数自动调用,进行函数内的操作

    回调函数是指handler()

  2. 监视的属性(计算属性也可以监视)必须存在,才能进行监视

    监视属性不存在时不会报错

  3. 监视的两种写法:

    1. new Vue时传入watch配置
    2. 通过vm.$watch监视

深度监视

监视多级结构中某个属性的变化

对象中的key是个字符串,简写形式可以不带''单引号,但像下面的例子中要监视numbers.a时就得加单引号,不然会带.

1
2
3
4
5
6
7
//监视多级结构中某个属性的变化
'numbers.a':{
// immediate:true,//初始化时调用handler
handler(newValue,oldValue){
console.log('a被修改了',oldValue,newValue)
}
}

监视多级结构中所有属性的变化

整个对象在监视时相当于监视复杂结构的地址,尽管其内容发生改变,只要地址不变,监视就不会给出变动

如果开启deep属性:deep:true,则可以做到监控一整个结构的所有属性


深度监视总结:

  1. Vue中的watch默认不监视对象内部值的改变(只监视一层)
  2. 配置deep:true可以检测对象内部值的改变(可以监视每一层)

另外:

  1. Vue自身可以检测对象内部值的改变,但其提供的watch默认不可以
  2. 使用watch时根据数据对象的具体结构,决定是否采用深度监视

回顾:Vue管理的函数

methods中的函数

计算属性中的get()、set(),以及计算属性简写时的函数(直接是属性名做函数)

监视属性中的handler(),以及监视属性简写时的函数(直接是属性名做函数)


上述姓名案例和天气案例通过计算属性监视属性都可以实现

具体差别见代码

基础实现用计算属性较为简单,但一些复杂需求还是要使用监视属性,例如姓名案例中修改姓名后延迟1s后再使全名修改

计算属性中不能开启异步任务去维护数据,但监视属性watch可以

要注意的是:

Vue管理的函数都要使用普通函数

计时器要使用箭头函数,见下例:

计算属性和监视属性比较


computed和watch之间的区别:

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

==两个重要的小原则==:

  1. 被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象
  2. 所有不被Vue管理的函数(定时器的回调函数、ajax的回调函数、Promise的回调函数等),最好写成箭头函数,这样this指向的才是vm 或 组件实例对象
  3. 上述俩原则目标统一:确保this指向的是vm 或 组件实例对象

绑定样式

:class:stylev-bind:classv-bind:style的简写

绑定样式总结

记得样式属性写在对象里时例如font-size要写成fontSize,且40px两边要加引号,如下所示:

style对象

绑定class样式

  • 字符串写法:适用于——样式名不确定,需要动态指定的情况

  • 数组写法:适用于——要绑定的样式名称不确定,个数也不确定

    将数组中的样式全都绑定,通过增删数组,来控制绑定哪些样式

  • 对象写法:适用于——要绑定的样式名字和个数都确定,但要动态决定用不用

绑定class样式

绑定style样式

也分为对象写法和数组写法

要分清楚哪里带引号,哪里不带引号

条件渲染

  • 通过v-show="a"实现,a是Vue管理的变量,可以动态修改,值为trueorfalse

  • 通过v-if="b"实现,v-if在将其隐藏的时候会彻底删除

所以隐藏/显示频率高的时候用v-show,减少开销

同理还有v-else-ifv-else,与v-if是一组判断

  • 可以用template将在不影响结构的前提下将多个标签包裹,但只能配合v-if
  • 使用v-if的时候元素可能获取不到(元素可能直接被删掉了),但v-show一定能获取到元素

列表渲染

基本列表

利用v-for

一般用v-for来遍历数组、对象,偶尔遍历字符串、次数


v-for指令:

  1. 用于展示列表数据
  2. 语法:v-for="(item,index) in xxx" :key="yyy" 每个元素key唯一
  3. 可遍历:数组、对象、字符串、次数

key的原理

如果以Vue自动给出的index作为key会出问题,解释见下图:

遍历列表时key的作用

==面试==:关于key的作用总结如下:

key内部原理

列表过滤

推荐用计算属性实现,但监视属性也能实现

一个使用name作为keyword进行关键词模糊筛选的例子

使用到了js中数组的filter方法 【JavaScript Array filter() 方法

内部返回值使用js中字符串的indexOf方法 【JavaScript indexOf() 方法】,若indexOf()返回-1,表示父串中无子串,否则返回子串在父串中的下标

  • 监视实现:

    监视实现

  • (推荐)计算属性实现:

    计算属性实现

列表排序

计算属性的强大之处:计算filPersons所用到的变量中有一个发生改变,都会引起filPersons的重新计算

js中数组的sort方法 【JavaScript Array sort() 方法

列表排序

Vue监测数据改变的原理

利用set()方法,但set()方法只能应用于对象,不能修改数组

因为Vue.set()没有对数组进行监测,增加setter()getter()

数组名、对象 才是响应式的,其改变会触发视图更新

能修改数组并引发视图更新的方法:push()pop()shift()unshift()splice()sort()reverse()

注意,split()方法不能修改数组,只能返回筛选后的结果

Vue对数组的监测实际上是通过包装数组身上上述常用能够修改数组的方法实现的,以便监测其变化,进而触发视图更新


总结

Vue数据监测总结


038_收集表单数据=>047自定义指令


生命周期

引出生命周期

  1. 生命周期又名生命周期回调函数、声明周期函数、生命周期钩子
  2. 是什么:是Vue在关键时刻帮我们调用的一些特殊名称的函数
  3. 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
  4. 生命周期函数中的this指向的是vm或组件实例对象

生命周期流程

声明周期示意图:

Vue生命周期

挂载流程-更新流程-销毁流程


讲了8个-4对生命周期钩子

beforeCreate()-created()

beforeMount()-mounted()

beforeUpdate()-updated()

beforeDestory()-destoryed()

详见上面的生命周期流程示意图


比较重要的是mounted()beforeDestory()

  • mounted()中做初始化的事情

    发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】

  • beforeDestory()中做收尾善后的事情

    清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】

关于销毁Vue实例:

  1. 销毁后借助Vue开发者工具看不到任何信息
  2. 销毁后自定义时间会失效,但原生DOM事件依然有效
  3. 一般不会在beforeDestory()操作数据,因为数据即便被改变,也不会再触发更新流程了

小Tips:在生命周期函数mounted()中创建的定时器,想在methods中将其关闭,创建时可以创建成this.timer=setInterval()的 形式,这样创建在this中,就相当于创建在vm上,methods中也能使用方法将其关闭

组件

对于组件的理解

非单文件组件:一个文件中包含有n个组件,写在.html文件里

单文件组件:一个文件中只包含有1个组件,写在.vue文件中,一个文件就是一个组件


  • Vue中使用组件的三大步骤:

    1. 定义组件(创建组件)

    2. 注册组件

    3. 使用组件(写组件标签)

  • 如何定义一个组件:

    1. 使用Vue.extend(options)创建,其中optinosnew Vue(options)时传入的那个options几乎一样,但区别如下:

      1. el不要写:最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器
      2. data必须写成函数:避免组件被复用时,数据存在引用关系

      另外:使用template可以配置组件结构

      const school = Vue.extend(options)可以简写为const school = opntions

    2. 如何注册组件:

      1. 局部注册:靠new Vue的时候传入components选项
      2. 全局注册:靠Vue.components('组件名',组件)
    3. 编写组件标签:

      <school></school>


【关于VueComponent

  1. school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的

  2. 我们只需要写<school></school><school/>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)

    每写一次标签就调用一次相应的构造函数

  3. 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent

  4. 关于this指向:

    1. 组件配置中:

      data函数、methods中的函数、watch中的函数、computed中的函数

      它们的this均为【VueComponent实例对象】

    2. new Vue()配置中:

      data函数、methods中的函数、watch中的函数、computed中的函数

      它们的this均为【Vue实例对象】

  5. VueComponent的实例对象,以后简称vc,也可称之为 组件实例对象

    Vue的实例对象简称vm


分析Vue与VueComponents的关系

实例的隐式原型属性,永远指向自己缔造者的原型对象

Vue与VueComponents的关系示意图:

Vue与VueComponents的关系

VueComponent.prototype.__proto__ === Vue.prototype

上面这个式子是上图中黄色的虚线的含义

这样做的原因是:让组件实例对象(vc)可以访问到Vue原型上的属性、方法

Vue单文件组件

export分别暴露,统一暴露,默认暴露,下图中是最常使用的默认暴露方法

单文件组件例子

写组件的快捷键:**<v**,结构、交互、样式的模板可以立刻写出

Vue脚手架

安装

分析脚手架结构

路由