Vue基础+vue2+vue3 大合集笔记

系列文章目录

  • 之前没跟对up主,vue基础没打好;跟着尚硅谷从头第二次学Vue,收获了很多并且记下来
  • 万字笔记,平常开发用的多的都在这了
  • 如果有出错的地方请多多指教!

文章目录

vue概述

vue是什么

  • 是一种web前端框架
  • 官方:vue是动态构建用户界面的渐进式框架
  • 作者:尤雨溪/鱿鱼须

vue的特点

  • 组件化:提高代码的复用,可以更好地维护
  • 声明式编码:**不用直接操作DOM,**提高开发效率
  • 虚拟DOM:当数据变化的时候,可以减少操作DOM,提高效率

Vue的引入(非Vue-cli的原生版)

  • 在官网下载vue的js
    在这里插入图片描述

  • 在html中用src的方式引入本地的vue.js
    在这里插入图片描述


第一个Vue代码

1.创建

  • 先创建一个Vue实例

  • Vue实例的构造需要配置对象

  • 往配置对象中填写,data,el等等都是配置对象的属性
    在这里插入图片描述

  • Vue实例需要和html中的容器产生关系:el:“id选择器”

  • 数据的绑定和引用:data中的数据可以通过{{}}在html中引用

  • 整体例子如下
    在这里插入图片描述

2. 注意事项

  • div和vue实例是一一对应的,一个div只能对应一个vue,即使是用css选择器选择到了多个div,也只接管第一个div
  • {{}}中填的是js表达式只要是能生成一个值,可以放在任何需要值得地方,就叫js表达式,比如
    1. 变量a
    2. a+b
    3. fun1() 等等等等都称为js表达式
  • data中数据改变了,页面中用到data中的地方也会改变

MVVM模型

  • M:model=>对应data中的数据
  • V:view => 模板
  • VM:ViewModel (视图模型) => vue实例对象
  • 人话:将数据和展示页面之间用vue搭建一个桥梁,vue来将数据绑定到视图层,同时监听视图层的变化,反映给数据
    在这里插入图片描述
    在这里插入图片描述

vue中的数据代理和数据劫持

1. Object.DefineProperty实现数据代理

(1) 介绍和应用场景

  • 涉及双向绑定的原理
  • 作用:可以往一个对象中添加属性,根据传参的配置对象,可以让这个属性和普通对象属性有些不同
  • 应用:当对象中的属性值来自对象外部的变量时,更改变量的值,对象中的值也想同步更改
    在这里插入图片描述
    这样的age,如果outerAge改为20,对象中age还是19
  • 如果想外部的改变可以同步到内部,就需要用到Object.DefineProperty

(2) 使用方法

  • Object.defineProperty(对象,要添加得键,{配置对象})
  • 配置对象的主要属性有:
    • value:18 //添加得属性得value

    • enumerable:true //是否可以被枚举 for in是否可以获取到 默认:false

    • writeable:true //value是否可以被修改 默认:false

    • configurable:true //是否可以被删除 默认:false

    • get(){} //当这个属性被获取的时候调用

    • set(){} //当这个属性被修改的时候调用

Object.defineProperty(对象,要添加得键,{配置对象})

let person={
	name:'szk'
}
Object.defineProperty(person,"age",{
	value:18 //添加得属性得value
	enumerable:true //是否可以被枚举 for in是否可以获取到 默认:false
	writeable:true //value是否可以被修改 默认:false
	configurable:true //是否可以被删除 默认:false

	get(){} //当这个属性被获取的时候调用
	set(){} //当这个属性被修改的时候调用
})

(3) 用这个使属性和外部数据绑定

  • get set在调用的时候可以来同步内外数据
    在这里插入图片描述

在这里插入图片描述

(4) 这样就实现了数据代理

  • 修改代理的(调用setter),就可以修改到真正的,就是数据代理
    在这里插入图片描述

2. data 和 _data

  • 看vm可以看到有一个属性叫做_data,它和vue实例中的data是同一个东西,一毛一样
    在这里插入图片描述

3. vue中的数据代理

  • vue将_data中的所有数据属性通过Object.defineProperty添加到vm实例上,并且提供了getter和setter方法
  • 于是通过vm直接获取数据的时候就调用getter,获取_data中的值,当修改的时候调用setter修改_data中的值
    在这里插入图片描述
  • 举个例子画个图
    在这里插入图片描述

那数据代理有什么用呢?

  • 既然vm上挂的属性就是_data中的数据代理,那么{{vm._data.name}}和{{name}}是等价的,{{vm_data.name='szk2'}}和{{name='szk2'}}也是等价的
  • 所以就是为了写代码的方便,在{{}}直接写数据,或者直接修改就能操作到_data中

4. vue中的数据劫持

  • 数据劫持就是将vue代码里我们写的data加工了一下,让每个属性有了getter和setter
  • 这就可以实现数据变了,改变页面
  • 先看看我们写的data和加工之后的data有什么区别
    在这里插入图片描述
  • 实际上vue通过监听者observer来监听data中的数据,这个getter和setter就是监听者里面的方法
  • getter就是监听者获取data中数据的,setter则是监听当数据发生变化的时候执行操作的
  • 当修改属性的时候,setter被调用,在setter方法中就会让订阅者执行重新解析模板的操作,从而改变了页面

5. 将两者结合总体流程

  • 结合起来看,当数据改变时,页面也跟着改变就是这个流程
    在这里插入图片描述

Vue.set方法

  • 用来向已经运行中的vm._data中添加属性—>就是在运行时添加响应式数据
  • 也可以用来更改响应式的数组数据
  • 如果直接添加属性,添加的属性是非响应式的,没有getter和setter
  • 用set方法添加的是响应式的

1. 往对象中添加属性

看看直接添加属性会怎样

  • 案例中给“学生留了位置”,但没有在data中定义数据给student,想之后再添加
    在这里插入图片描述
  • 之后在控制台添加一下试试
    在这里插入图片描述

使用set方法添加属性试试

  • Vue.set(要添加的到的对象,'添加的字段',‘添加的值’)
  • 或者vm.$set(要添加的到的对象,'添加的字段',‘添加的值’)
    在这里插入图片描述

注意点

  • set方法只能针对data中对象的属性的添加,而不能直接在data上添加
    在这里插入图片描述

2. 用set修改数组属性

  • Vue.set(要更改的数组对象,要修改的下标,‘修改的值’)
  • 响应式数组不能直接用下标进行修改,只能使用vue中封装的操作数组的几种方法
    在这里插入图片描述
  • 除此之外,使用set也可以做到
    在这里插入图片描述

插值语法

  • 被vue接管的div叫做模板,在之中会有相应的语法
  • 就是{{}},里面写的是js表达式
  • 标签体中使用插值语法
  • 之所以{{data}}里填data的东西可以显示,是因为{{}}中的是vue实例里面的东西
    在这里插入图片描述

指令语法

  • 都是v-xxx开头

(1) v-bind

  • v-bind用来绑定标签中的属性,简写是:
  • 语法: v-bind:要绑定的属性名='js表达式'
  • 比如,想绑定div中的herf属性,可以这样写
    在这里插入图片描述
  • v-bind 是单项数据绑定:data中的值改变可以影响页面,但页面的值改变了不会影响data

(2) v-model

  • 作用和v-bind类似
  • v-model 实现数据双向绑定:页面值改变了会影响data中的值
  • v-model只支持部分标签,一般应用在表单元素中
  • 默认收集的就是value,可以简写成 v-model = 'js表达式'
    在这里插入图片描述

在实际收集表单数据的时候需要注意几个问题

  • 对于radio这种单选框,一定要给其指定value,不然绑定的数据就是true/false而不是需要的值
  • 对于checkbox这种多选的,接收的时候要用数组接收,否则接收的也是true/false
  • button最终会触发form的submit,可以通过 @submit.prevent 来组织表单提交后刷新页面
  • 对于需要传值为数字的,可以使用后缀 v-model.number,这样收集到的就会是数字
    在这里插入图片描述

(3) v-on

  • 作用是:绑定事件 ,简写是@
  • 用来将事件(比如鼠标点击,得到焦点等等),与函数绑定在一起
  • vue2中的函数在配置对象中写在methods中
  • 例子需求:点击按钮后,alert一个信息
    在这里插入图片描述
    注意:
    1. 默认传一个event参数
    2. 如果传自己的参数,又想用到event,需要用$event 在传参表中声明,否则不会有event参数传入
    3. 没有参数可以省略()
    4. 简写是 @事件名=‘函数名’

事件修饰符

  • Vue中的事件修饰符:
    1. prevent :组织默认事件
    2. stop:组织事件冒泡
    3. once:事件只触发一次
    4. capture:使用时间的捕获模式
    5. self:只有event.target是当前操作的元素才触发事件
    6. passive:事件的默认行为立即执行,无需等待时间回调执行完毕
  • 使用方法:直接.出来就可以
    在这里插入图片描述

键盘事件

  • 使用方法@keyxxx='函数名' 比如:@keyup=‘handleKeyup’
  • 提供了几种常用键的快捷方法,直接.出来
    在这里插入图片描述
  • 例子:
    在这里插入图片描述

(4) v-text

  • 用来向其所在标签插入文字,而且会覆盖掉节点中的内容
  • 非常简单
    在这里插入图片描述

(5) v-html

  • 就是支持html解析的v-text
    在这里插入图片描述
  • v-html有安全性问题,动态渲染任意的html是很危险的,容易遭到黑客攻击,要慎用

(6) v-cloak

  • 解决网速过慢时,html结构出来了,但vue还没来,导致网站只显示一堆{{}}这样的结构
  • 加入v-cloak 配合css的属性选择器,就可以做到等模板全部渲染好之后才展示页面
  • 使用方法:在标签中加入v-cloak 只有属性没有值
    在这里插入图片描述

(7) v-once

  • v-once所在节点初始化渲染后就变成静态的了
  • 可以让初次动态渲染的东西一直停留在页面上
    在这里插入图片描述

(8) v-pre

  • vue跳过页面解析过程
    在这里插入图片描述
  • 给不需要使用到vue语法的地方加,可以提高效率,加快了编译

(9) 条件渲染

1. v-show

  • 可以显示/隐藏内容
  • v-show="布尔值表达式"
  • 表达式为true则显示,false为隐藏
  • show的隐藏是将元素隐藏了,但结构还在

2. v-if

  • 结构:
v-if:="布尔值表达式"

//后两者可选,可以不写
v-else-if:="布尔值表达式"
v-else:="布尔值表达式"
  • 作用也是显示/隐藏内容,和v-show的不同在于v-if实际渲染的时候如果是false是将整个元素结构都删除了,而show只是隐藏了
  • 注意:v-if 和 v-else-if 之间不能空有别的元素,必须是连贯的

(10) 列表渲染 v-for

  • 用来在模板中渲染可迭代对象
  • 注意:必须要执行key

1. 使用方法

  • 最好是迭代对象中有id属性,作为key,作为每次循环出来的“身份证号”
  • 如果没有的话,也可以让遍历产生的index作为key,在一些特殊情况下会出错,下文会讲
// 最好是迭代对象中有id属性,作为key,作为每次循环出来的“身份证号”
<div v-for='item in data中要迭代对象' :key='item.id'>

//用自己生成的index作为key的话这样写
<div v-for='(item,index) in data中要迭代的对象' :key='index'>

在这里插入图片描述

  • 注意:
    1. 数组对象遍历出一个个对象
    2. 对象中遍历出的是每一对键值对
    3. 如果要获取index的话,index一定是括号中的第二位 (value,index)
    4. 一定要写key,不然会降低效率,甚至会出错

2. 为什么要用key

  • vue在虚拟DOM时对于更新了的内容会进行对比算法,key这时就会被作为对比的依据
  • 如果使用index作为key时,如果插入数据的顺序破坏了原本的index(此处就是往头的地方插入了数据),则新数据会拥有旧数据的index
  • vue会去对比新旧DOM中有相同key的地方,有新的内容就会代替掉,一样的地方就会复用
  • 此处虽然input中内容其实不同,但在DOM中vue认为他们是一样的
  • 最终导致新插入的数据的input中的值其实是老数据中index为0的input中的值
    在这里插入图片描述
  • 而如果每个key都是唯一的话,就不会进行上述的对比算法,只有新旧DOM中都有key为同一个值时才会对比
  • 这样就避免了上述的错误
  • 具体可以看B站尚硅谷这一篇讲解很详细

3.列表过滤

  • 为了在前端实现模糊查询
    在这里插入图片描述
  • 实现逻辑:对输入的值进行双向绑定----->在计算属性中通过数组的filter函数过滤出符合关键字的数组对象——>渲染过滤过的数组对象
    在这里插入图片描述

自定义指令

  • 指令如v-bind 那些vue内置的叫内置指令,自定义指令就是自己定义的v-xx的指令
  • 在自定义指令中,需要亲自操作dom元素

1. 直接写函数的简单写法

  • 指令可以想象成跟计算属性类似的东西,可以写成一个函数
  • 指令的名字在使用时需要加上v-指令名字,比如定义了一个叫big的指令,在标签中使用时就要用v-big=‘’
  • 步骤:
    1. 在directives中写函数,参数第一个element是dom所在元素,第二个参数binding是和这个dom绑定了的一个对象
    2. 在标签中使用v-刚才写的函数名='value',这个value就是会放到bingding对象中的value的值
  • 例子需求:写一个big指令,可以让标签里的数组扩大十倍
    在这里插入图片描述
  • 来看看这个bingding的对象:关注里面的value值,这个值第一次的时候就是v-big=‘n’ 绑定的n,但后面这个值和data中就没关系了
    在这里插入图片描述

2. 写成一个对象的形式

  • 类似于生命周期函数的写法
  • 自定义组件生效在vue中流程是这样的:
    在这里插入图片描述
  • 这三个时期对应对象中的三个函数bind,inserted,update
  • 之所以要在不同生命周期写是因为:有些对dom元素的操作,必须是在dom渲染到页面上才奏效的,如dom.focus,如果用上一点中说的函数法,就无法控制在那个阶段指定,一些具体细节就无法调整
    在这里插入图片描述

3. 命名注意

  • 不要用驼峰命名法,最终他都会转成小写,使用-对多单词进行分割
  • 比如:bigNumber 就写成big-number,在定义函数的时候就写成 big_number(){}

4.全局配置

  • 刚才的写法是在组件中局部的,作用域在组件内,如果想全局调用,就是用
  • Vue.directives("自定义操作名",在局部里写的完整函数or对象)
    在这里插入图片描述

计算属性

  • 拿已有的属性进行加工和运算,得到一个全新的属性
  • 储存在配置对象里面的computed
  • 底层原理还是用的Object.definedProperty,计算属性得出的属性也会被挂在在vm

1. 使用

computed:{
	要计算的属性:{
		get(){
				return 计算出的内容
		}

		//但一般set用的少,因为一般是根据data中数据计算出属性,而不是改变属性来改变data中的值
		set(value){
				this.属性0=value
		}
	}
}

实例:

在这里插入图片描述

2. get的调用时机

  • 初次读取计算属性的时候
  • 之后会把这个计算的属性进行缓存,如果所依赖的数据没有发生变化,则一直是使用这个缓存====>如果用的是函数就得重复调用多次,使用计算属性节省了很多资源开销
  • 所依赖的数据发生变化时,又会调用get

3.简便写法

  • 一般只用到get,而不用set,可以把计算属性简写成像个函数的形式
    在这里插入图片描述

监听函数

  • 用来监视属性的修改,做出反应

1. 用法

watch:{
        要监视的属性名:{
            handler(oldVal,newVal){
                        要进行的操作
            }
         }
	}

在这里插入图片描述

2. 监听多级属性的时候

  • 当要监听的属性位于对象中时,写法有点区别,要用字符串表示属性在这里插入图片描述

3. 深度监听

  • vue中的watch默认不监听对象内部属性的改变
  • 通过deep:true属性可以让其监听到对象内部
  • 数据结构简单的时候可以不开启,因为开启会消耗资源
  • 需求例子:监听person对象,person中的name改变时进行操作
    在这里插入图片描述

4. 简写

在这里插入图片描述

5. 计算属性和监听属性的使用场合

  • 计算属性能完成的,监听属性都能完成
  • 计算属性对于只用来在模板显示一个值,而不需要对这个值进行后续操作,用计算属性一般会简单
  • 如果对更新的值需要有进一步操作,如一些异步操作时,则只能使用监听属性
  • 原因是计算属性只能依赖return 的返回值,而监听函数可以有更多操作

绑定class

  • 使用v-on可以绑定class样式
  • v-on:class='data中数据'

1. 绑定字符串

在这里插入图片描述

2. 绑定对象

如果绑定的是对象,对象的键名为class动态变化的值,value为布尔值,为true就添加到class,false不添加

在这里插入图片描述

绑定style

  • v-on绑定一个style对象
  • 在对象中写css样式,但是要注意使用驼峰命名,比如:background-color : red 在对象中要写成backgroundColor:‘red’
    在这里插入图片描述

生命周期函数

  • 在vue渲染页面的特殊时间点调用的函数,就叫做生命周期函数
  • 要实现的功能一到某个阶段时就得开始调用,就需要使用生命周期函数
  • 比如:我想让页面一展现就开始某种特效,如果使用methods,可能需要有个事件触发才能执行,而使用了生命周期函数就可以在挂载时就执行,不需要用一个click之类的事件进行触发
  • 生命周期函数中的this,指的是vm (Vue实例对象)

1. beforeCreate

  • 这个生命时期有初始化的vue实例,但是但没开始数据代理
  • 这意味着这个阶段拿不到vm中的data和method

2. created

  • 这个生命周期完成了数据代理,可以拿到vm中的data和method

3. beforeMounted

  • 这个生命时期是vue已经生成了虚拟DOM,但还没放到页面上成为真实DOM
  • 这个阶段对DOM的操作,最终渲染出来都不奏效
  • 网页显示的是未经编译的DOM结构

4. mounted

  • 页面展现的是经过vue编译的DOM,就没有{{}}这些东西了
  • 这个是vue完成模板的解析,初次把真实DOM放入页面后(挂在完毕),调用mounted
  • 初次就是相对于之后数据更改后重新渲染模板时,就不算初次了,不会调用mounted
  • 一般定时器,网络请求,订阅消息等可以在这个阶段执行

5. beforeUpdate

  • 这个生命时期是当数据更新时,数据已经更新了,但页面还是旧的,新数据没有放到页面上去

6. updated

  • 更新数据完毕时,页面和数据都是新的

7. beforeDestroy

  • 想销毁vm实例就调用vm.$destroy(),vm就会被销毁,但销毁之前还有beforeDestroy
  • 可以理解成濒死状态,这个时期一般可以关闭定时器,取消订阅消息等首尾操作
  • 但是这里修改的数据,已经不会更新了

8. destroyed

  • vm已经被销毁了
  • 自组件全部无效,监听器,自定义事件也无效了
    在这里插入图片描述

9. 常用的生命周期函数

  • mounted:发送ajax请求,启动定时器,绑定自定义事件,订阅消息(初始化)
  • beforeDestroy:清除定时器,解绑自定义事件,取消订阅消息等(收尾工作)

10. vue3中生命周期会有所区别

  • 在setup函数中使用生命周期函数
  • 名字有所区别
  • 调用时需要按需引入
    在这里插入图片描述
    在这里插入图片描述

自定义事件

  • 可以用于子组件给父组件传参

1. 第一种使用方法

父组件中:

  • 在子组件的标签中v-on:自定义事件名=‘绑定的函数’
    在这里插入图片描述
  • 意思是触发这个事件的时候,就会调用handleClick函数

子组件中

使用this.$emit('自定义事件名',参数1,参数2....)
在这里插入图片描述

  • 意思就是点击之后,就触发这个自定义事件,传值为123,相当于是个回调函数,返回123可以被父组件中接收

触发流程

在这里插入图片描述


2. 第二种使用方式

  • 首先在子组件标签上写上ref
  • this/$refs.就可以取到子组件的实例对象
  • 通过on('自定义事件名称',this.要调用的方法,参数)也可以声明自定义事件
  • 这样做的好处:这样做就灵活很多,可以在不同的生命周期函数中调用

在这里插入图片描述

  • 注意点:在这种写法中,如果在参数中直接在里面写普通函数的回调,里面的this并不是父组件的实例对象,而是子组件的实例对象
    在这里插入图片描述
  • 如果回调写的是箭头函数,箭头函数没有自己的this,向外寻找this,这里找到的就是mounted的this,就是父组件的实例对象,就有name属性
    在这里插入图片描述
  • 总之on方法里的回调中的this一定要是父组件的实例对象才有用
  • 绑定的本质是把这个自定义事件用on方法添加到子组件的实例对象上
    在这里插入图片描述

3. 解绑事件

this.$off(),这里this是父组件的实例对象
在这里插入图片描述

4. 如果同时也想使用原生事件

  • 一旦给子组件标签定义了自定义事件,那原生的事件如@click就会失效,全部被当成自定义组件
  • 这时还想其触发,就@click.native就可以触发原生的事件
    在这里插入图片描述

全局事件总线

  • 用于任何组件之间的通信
  • 不是新的api,而是程序员们利用自定义事件玩出来的一种可以实现任何组件通信的方式

1. 思想

  • 自定义事件只能实现父子组件之间的通信,那对于兄弟组件怎么办呢?
  • 那就让大家都有一个都能使用的工具人,中转一下
  • 那个大家都能访问的工具人,就是全局事件总线的精髓所在
    在这里插入图片描述
  • 这样来看,工具人需要满足一些条件:
    1. 工具人要被所有的组件都可以看到
    2. 工具人身上可以添加自定义事件

2. 谁来当工具人

  • 先来想想这个工具人应该在哪才能被大家都看得到
  • 之前提到过,Vue上配的东西之所以能实现全局配置,就是因为Vue实例和VueComponent实例顺着原型链都会最终找到Vue的原型对象
  • 因此在VueComponent中找不到的方法和属性会顺着原型链找到Vue的原型对象上去
  • 那所以这个Vue原型对象Vue.prototype就是大家都可以看到的地方

  • 位置找到了,那谁来当呢
  • 讲自定义组件的时候提到,绑定事件的本质就是往子组件的实例对象上用on函数添加了自定义事件
  • 那说明这个工具人,肯定长得像个Vue实例或者VueComponent实例
  • 而我们一定要做的就是创建Vue实例对象,就让Vue实例对象来当工具人

3. 实现

(1)确定工具人

  • 所以工具人位置在Vue.prototype上,这个人就是个vm,直接来吧
    在这里插入图片描述
  • bus有总线的意思,其实叫什么名字都可以,这样工具人就找好了,以后就叫他bus

(2)接收端

  • 发送端需要给bus使用$on函数添加一个事件,包含一个回调函数用来接收数据
    在这里插入图片描述

(3)触发端

  • 触发端就要触发$bus中绑定的事件,可以传参
    在这里插入图片描述
    在这里插入图片描述
  • 在组件1中成功获得’黄金之风’
  • 此时再来看这张图

在这里插入图片描述


消息发布与订阅

  • 消息的发布与订阅也能实现组件间自由通信,但是需要借助外部的js库
npm i pubsub-js

1. 发布者

  • 发布者发送,publish
  • pubsub.publish('事件名称',传的参数)
    在这里插入图片描述

2. 接收者

  • 接收者订阅
  • pubsub.subscribe('订阅的事件名称',绑定的回调函数)
  • 注意绑定的回调函数接收的形参第一个参数是这个事件的名称,第二个才是真正传来的参数
    在这里插入图片描述

3. 总结流程

在这里插入图片描述


data的两种写法

1. 对象式写法

  • data后跟对象的形式
const vm=new Vue({
	data:{
		person:'szk'
	}
})

2. 函数式写法

  • data 是一个函数,return的返回值才是页面中拿得到的数据
  • 注意:这个函数不能是箭头函数,箭头函数没有自己的this,箭头函数的this是window,而普通函数的this是调用者Vue
const vm = new Vue({
	data:function(){
		return {
			person:"szk"
		}
	}
})

可以简写成

const vm = new Vue({
	data(){
		return {
			person:"szk"
		}
	}
})

$nextTick

  • 前提知识:在一个函数中有多次data中值的修改,vue会走完整个函数才重新渲染页面,而不是遇到一个数据修改就重新渲染一次
  • $nextTick使用场景:当一个函数中某些操作希望vue不要走完整个函数就重新渲染页面时使用

1. 使用方法

this.$nextTick(function)

2. 看个案例就明白了

  • 需求:需要在点击按钮的时候,让input框出现,同时获取焦点

  • 如果不使用这个
    在这里插入图片描述

  • 使用后
    在这里插入图片描述


Vue集成第三方动画库animate.css

  • vue中的动画系统可以让你花更多精力关注dom本身,而少关注因为动画带来的各种class问题
  • 这里拿animate.css举例子,animate.css官网

1. 安装animate.css,并且在需要的地方引入

npm install animate.css

import 'animate.css'

2. 写一段会让dom元素出现和消失的代码

  • 这里就是点击按钮,h1就会出现
    在这里插入图片描述

3. 给单元素加上动画

  • 格式
<transition
    appear
    name="要绑定的class名"
    enter-active-class="进入时动画名"
    leave-active-class="离开时动画名"
    >
        <h1 v-show="isShow">hello</h1>
        这个是需要变换的元素
 </transition>

例子
在这里插入图片描述

4. 给多元素加动画

  • transition标签中只能放一个dom元素
  • 如果想一组元素都有动画,需要用到transition-group标签
  • 注意:每个元素都需要有个key属性,作为其唯一标识
    在这里插入图片描述

组件

  • 组件:局部功能代码和资源的集合——在vue中组件一般就是html,css,js的集合

1. 为什么要组件化编程

  • 传统的前端,依赖关系混乱,代码复用性差

在这里插入图片描述
图片来自尚硅谷

  • 而用了组件化后

在这里插入图片描述

  • 实现代码的良好复用,简化编码,提高效率

2. 先在一个HTML中创建组件(非单文件组件)

  • 虽然之后在vue-cli中我们实际都写单文件组件(一个.vue文件就是一个单独的组件)
  • 先学习非单文件组件,对于理解vue中组件的编写更好

1. 创建组件

  • 格式
const comp1=Vue.extend({ //传入一个配置对象
	// 组件中一定不能写 el:
	
	// 这个是最后在vue开发者工具里显示的名字
	name:"student"
	
	//template中写的是这个组件的模板
	template:`
		<div> {{name}}-----{{age}} </div>
	`,

	//data跟Vue实例中的很像,但注意一定要写成函数的形式
	data(){
		return{
			name:"szk",
			age:90
		}
	},
	methods:{},
	// ....vue实例中能写的基本都能写
})
  • 有几个注意点:
    1. 组件中一定不能写el:"",这个只有在vue实例中才能写
    2. data中不能写成对象的形式,要写成函数+返回值的形式 ,如果不这样的话,最终挂载到实例上,各个组件的data就会混乱,相互可以修改对方组件中的数据,如果用的是函数+返回值的方式,data中的值是调用函数返回的,而不是从data对象中获取的,就不会出现这个问题

2. 注册组件

  • 之后在vue实例上注册组件,当然组件之间可以实现嵌套,就是在组件中可以注册组件,让其称为子组件
  • 格式:
const vm=new Vue({
	components:{
		// key就是 要在模板(html)中使用这个组件的标签名,comp1就是上面一点钟创建的组件对象
		student: comp1
		people: comp2
	}
})

3. 使用组件

  • 在模板(html)中使用刚才创建的组件
<div id="root">
        <div>

			这里就是刚才在实例中注册的components的名字,用标签的形式使用
            <student></student>
            <people></people>
        </div>
</div>

4.完整案例

在这里插入图片描述


3. 关于component的一些深入理解

(1)Vue.extend到底干了什么

返回一个新的VueComponent构造函数

  • 将源码中一些先不去了解的地方删掉后,可以看到
  • Vue.extend调用了一个方法,生成一个VueComponent构造函数并返回
  • 由此得出结论,Vue.extend方法返回一个VueComponent构造函数,而且每次调用产生的VueComponent是全新的
    在这里插入图片描述

(2)组件里的this是什么

和vue实例长得差不多的VueComponent实例对象

  • 当标签在渲染的时候就通过上文中的VueComponent构造函数实例化出来VueComponent对象
  • 看看component中的this是什么
    在这里插入图片描述

4. 来写单文件组件 .vue文件

  • vscode推荐安装vetur插件,为.vue文件提供提示
  • .vue文件分为三部分,template,script,style
  • 格式:
<template>
<!--写html模板  -->
</template>


<script>
// 写js或ts代码
</script>


<style scoped>
/* 写样式css或less等 */
</style>

组件的创建

  • 将上述的student组件写到单文件组件中就是这样的
    在这里插入图片描述
  • 注意点:script中需要把这个组件模块化暴露出去,推荐使用export default{} 默认暴露

组件的引用

  • 由老大哥app组件统领一切组件
    在这里插入图片描述

组件的命名

  • 一个单词:全小写或首字母大写
    1. school.vue
    2. School.vue
  • 多个单词:用-连接,或者大驼峰
    1. my-school.vue
    2. MySchool.vue

插槽slot

  • 使用场景在组件中,有一些地方需要单独定制,在使用这个组件标签的时候再决定定制的地方怎么写
  • 就是用来写组件中的局部

1. 使用

  • 需求案例:在组件school中,大体结构相同,但有两个地方使用的不一样的东西

在组件中设置插槽

<slot name='slot的名字'> </slot>

在这里插入图片描述

在使用组件的地方往插槽放东西

  • 最好将需要插入的元素用template标签包起来,这样做而不是用div包起来是因为最终vue会脱去template标签,就可以少出现一层莫名其妙的div结构
<子组件标签>
	<template slot='插槽名字'>

	</template>
</子组件标签>

在这里插入图片描述

2. 总结

  • 插槽就是在使用子组件标签时,对子组件中内容可以更自定义化地定制
    在这里插入图片描述

组件中定义一个插槽

Vue是如何实现全局配置的

  • 涉及到原型和原型链的内容
  • 其实就是组件实例的原型对象VueComponent 的原型对象是Vue的原型对象实现的
  • 只要满足上面的关系,VueComponent实例中找不到的方法和属性会顺着原型链找到Vue的原型对象
  • 因此只要只要进行Vue.filter 这样的操作,在Vue原型对象上加属性,就可以同时应用到组件上,实现全局配置

Vue-cli 中Vue到底是怎么跑起来的

  • 首先要对vue中组件有了解
  • 整个过程简化为这张图
    在这里插入图片描述

ref属性

  • 对于普通标签来说,就等于是vue中的id
  • 对于组件标签来说,ref可以取到的是组件对象,而id选择器取到的还是这个dom元素

1. 使用

  • 直接在标签上加上 ref="给他取的名字",取的时候就用 this.$refs.这个名字
  • 会挂在在组件/vm上作为属性
    在这里插入图片描述
  • 在普通标签中,拿到的跟id选择器拿到的是一样的
    在这里插入图片描述

  • 而对于子组件标签中,ref拿到的是组件对象,id拿到的是DOM元素
  • 在这里插入图片描述

props:往组件中传参

  • 父组件可以向子组件传参
  • 对于使用的模板相同,但是渲染的数据不同,且数据由父组件决定时,使用props传参
  • 分为三种方式

1.第一种方式接收

  • 父组件中在标签中用:+传参名称='传参内容'的方式传参
  • 子组件中定义props属性接收参数
  • 接受的参数和data中的一样会被挂载到组件对象上,可以直接用{{}}插值语法调用
  • 第一种方式是简单声明,参数名放在一个数组中
    在这里插入图片描述

2. 第二种方式接收

  • props中接收是一个对象,里面就是参数名: 参数的数据类型
  • 可以用来约束接收参数的数据类型,不符合控制台报错
    在这里插入图片描述

3. 第三种方式接收

  • 一个参数名是一个对象
    在这里插入图片描述

4. 注意点

  • 父组件传参的时候传入字符串必须是:参数名='',使用v-on动态绑定的形式,这样引号中会被当成是js表达式,否则数字传过去也是字符串
  • 当传参是个非组件属性的字符串时,则不能加 :,因为:参数名=''的冒号中会被当成表达式,如果填字符串就代表数据的引用,如果data或者computed中没这个属性就会报错
  • 如果传参是从data或computed等挂在在了组件属性上的数据,那就用
  • props传进去之后,不建议修改
  • props的优先级高于data,如果props中的值和data中同名,渲染props中的

mixin

  • 对于各个组件的公共js部分可以抽取出来写在mixins 中

1.使用方法

  1. 先创建一个mixin.js用来写抽出来的部分
  2. 在mixin.js中需要export导出,可以默认导出也可以分别导出,例子这里用默认导出
    在这里插入图片描述
  3. 在需要使用的组件中导入这个js,使用属性mixins:[]
    在这里插入图片描述
  4. 之后这个组件中就会拥有这个方法和属性
    在这里插入图片描述
  5. 注意:所有的mixins中的内容只能来自一个mixin.js文件,不能是多个js文件里都引入作为mixins;[]中内容

2. 全局引入mixin

  • 全局引入mixin,所有的组件,包括App组件,都可以调用mixin中的方法和数据
    在这里插入图片描述

之后就是Vue3部分//

Vue3 两种创建方式

1. vue-cli方式

  • 先全局安装/更新vue-cli
  • -g全局安装
  • vue create 项目名称
# 先全局安装/更新vue-cli
npm install -g @vue/cli

# vue create 项目名称创建项目
vue create myPro1

2. vite创建(启动贼快)

npm init vue@latest
cd myPro2
npm install
npm run dev

sass安装

npm install sass-loader@^10 sass -D

Vue3使用Vuex

  • 在Vue中实现集中式数据管理插件
  • 相比全局事件总线的优势: 当组件很多的时候,全局事件总线写起来贼麻烦
  • 什么时候需要用:多个组件依赖同一个状态

1. 运行流程图

  • 组件调用action(dispatch):客户给服务员提需求—————> action调用mutations(commit):服务员让厨师做菜————>mutations修改state中数据值(厨师做好了菜)————>客户拿到菜(拿到state中的值)
    在这里插入图片描述

1. 安装和引入

  • 版本:vue2 只能用vuex3 npm i vuex@3
  • vuex4只能在vue3中使用 npm i vuex
  • 在store文件夹中写一个index.js,之后vuex的具体内容写在里面
  • index模板:
import { createStore } from "vuex";
export default createStore({
  state:{},
  getters:{},
  mutations:{},
  actions:{},
  modules: {},
});
  • 在main.js中引入
    在这里插入图片描述

2.state

  • 是vuex中的数据存储地方,可以类比为数据库
  • 里面的数据是全局可以访问到的

store端

在这里插入图片描述


组件中使用:

  1. 从vuex中引入useStore
  2. 使用useStore返回一个store实例
  3. 通过store.state. 获取
    在这里插入图片描述

3.mutations

store端

  • 相当于后端的DAO层,只能写同步方法,用来直接与state中的数据进行交互,最好不涉及业务逻辑
  • 是个对象,里面可以写很多方法
    在这里插入图片描述
  • 被调用的方式有两种:
    1. 被action调用:需要经过一定的业务逻辑,再操作state中数据
    2. 被组件直接调用:没什么业务逻辑,直接操作state
      在这里插入图片描述
  • 被actions调用
  • 需要经过一定的业务逻辑,再操作state中数据
  • action中函数的上下文参数context就有commit('mutations中要被调用的方法名',参数)
    在这里插入图片描述

组件端

  • commit('mutations中要被调用的方法名',参数)
    在这里插入图片描述

4. actions

  • 在actions中可以执行异步操作,操作state的业务逻辑可以写在这里
  • 有两个参数,(contaxt上下文参数,传的参数)
  • 上下文参数中就有commit,可以通过这个调用mutations中的方法

store端

在这里插入图片描述

组件端

  • 组件端使用store.dispatch('actions中的方法名',传参)调用
    在这里插入图片描述

5. modules

  • 将vuex中也进行组件化,每个组件都包含属于自己的state,mutations,actions,getters

store端

在这里插入图片描述

组件端

在这里插入图片描述

注意:使用这种方法调用一定要在每个模块vuex中加入namespaced:true

在这里插入图片描述


vue3使用路由router

  • vue-router是一个插件库,用来实现单页面应用:整个应用只有一个完整的的页面,点击导航连接页面不刷新,只会局部刷新,数据通过ajax请求获取

1. 安装和基础配置

npm i vue-router
  • 新建一个router文件夹,里面写一个index.js
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/test01',
    name: 'test01',
    component: ()=>import ('../views/router/TestRouter01.vue') //这里填的就是组件的路径
  },

]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router
  • 之后再main.js中引入这个js,并且use
    在这里插入图片描述

2. 配置各组件的路由

在这里插入图片描述


3. 在组件中的使用

1. 函数式使用route

  • 注意这里是导入的useRouter 而不是useRoute ,router是路由器,掌管push,back,forward这些路由器操作,而route是路由信息相关操作

在这里插入图片描述

2. 标签式使用路由

 <router-link to='路径'>跳转</router-link> 
 

// to后用对象形式写
 <router-link :to="{
    name:'test01',
    params:{
        name:'dio',
        age:101
    }
  }">跳转</router-link>

4. 嵌套路由

  • 当多个路由都属于同一个路由之下,就像父子一样,就要用到嵌套路由
    在这里插入图片描述
  • 在路由的配置中,在children属性中又可以配置数组对象,每个对象由path和component组成,称为子路由
  • 注意在子路由中的path不用加/
    在这里插入图片描述

5. 路由传参

query形式的传参

  • 直接在需要跳转的地方声明就可以,路由配置不用改

  • 方式一:直接在url中拼接,用?分隔url和传参,之后写成键值对形式,不同参数之间用&连接,这种写法不能写:to 直接写to,后面当成字符串
    在这里插入图片描述

  • 方式二:用:to='',后面当成js表达式解析,path是路径,query中写一个对象里面是传的参数
    在这里插入图片描述

  • 需要接收的时候

    1. import { useRoute } from 'vue-router'
    2. const route=useRoute() 将route实例化
    3. console.log(route.query)就可以看到传来的query的值
      在这里插入图片描述

params传参

  • restful风格传参,路由需要修改,需要跳转的地方也要修改

  • 方式一:将需要传的参数直接用/拼接在url中
    在这里插入图片描述
    方式二:如果写成对象形式,一定记得,不能用path,必须用路由的name
    在这里插入图片描述

  • 在路由的地方,需要做出标识,用/:参数名称的方式标注
    在这里插入图片描述

  • 在组件中使用和query类似
    在这里插入图片描述

6. 缓存组件

  • 路由切换的时候,不需要的组件是被销毁的,里面的用户输入的数据如果再次加载的时候就没了
  • 使用<keep-alive include='要缓存的组件名'> 就可以对组件进行缓存,不会销毁,再次加载的时候用户输入的东西还在
  • 缓存多个的时候用数组包裹
    在这里插入图片描述

7. 路由守卫

  • 不是所有导航项都可以点,满足条件才能触发路由,可以理解成前端的鉴权
  • 分为全局前置路由守卫和后置路由守卫,分别在切换路由之前和切换路由之后调用

前置路由守卫

router.beforeEach((to,from,next)=>{
	next() //next函数用来放行,否则统统拦截
})

后置路由守卫

router.afterEach((to,from)=>{
	
})

独享路由守卫

  • 某个路由独有的路由守卫,只有前置没有后置
const routes=[{
	path:'/personal',
	name:'personal',
	components: Personal,
	beforeEnter((to,from,next)=>{
		//判断逻辑
	})
}]

组件中的路由守卫

  • 在vue2中有beforeRouteEnter,beforeRouteLeave,beforeRouteUpdate
  • 在vue3中在setup中则变为onBeforeRouteUpdate,onBeforeRouteLeave 由于setup作用时,路由已经生效了,因此没有了onBeforeRouteEnter
    在这里插入图片描述

setup

1. 什么是setup

  • set up是Vue3 推荐使用的组合式API
  • 在Vue3中,尽量都采用组合式API写法,虽然可以在Vue3写vue2的代码,但最好不要一个组件中两种写法混用
  • set up 本质就是个函数

2. 如何使用

  • setup 就是个函数,里面可以有数据,各种函数,生命周期函数
  • 既然是函数,就要有返回值,setup的返回值就是要暴露给模板中的东西,可以是数据,可以是方法
  • return 出去的东西在模板中就可以用插值语法{{}}取到了
<script>
export default {
	name:"comp1",
	setup(){
		let a=0 //曾经data的定义,全部放在setup中
		
		function fun1(){ //methods中的函数,也丢在setup中
			console.log(a) //由于是定义在setup这个函数中,定义的数据可以直接使用,不需要this
		}
		watch(){ //监听函数等等都可以在里面写
		return { //既然是函数,就要有返回值,返回值就是要暴露给模板中的东西,可以是数据,可以是方法
			a, 
			fun1
			}
		}
	}
}

</script>

setup中的两个参数

  • setup中可以接收两个参数,分别是porps和context

props

  • 用来接收父组件传来的参数
  • 步骤:
    1. 在父组件中传参
    2. 在子组件中用porps属性声明接收的对象
    3. setup中的(props)参数可以接收参数,在setup中就可以使用了
      在这里插入图片描述

context上下文对象

  • context中最重要的是里面的emit方法,对应vue2中的$emit
  • emit的使用方法:
    1. 父组件中定义自定义事件
    2. 子组件中用context.emit('事件名',传的参数)
    3. 最好也声明一下emits:[‘事件名’]
      在这里插入图片描述

ref和reactive

  • ref函数用来定义一个响应式数据
  • reactive函数用来定义一个对象类型的响应式数据,但不能定义基本类型

1. 使用

  • 首先将要使用的ref和reactice引入
  • 之后就用函数调用的方式把源数据放进去
  • 可以看到ref将源数据变成了一个RefImpl对象,本质通过Object,defineProperty实现响应式
  • 而reactive将源数据变成了一个Proxy对象,本质通过Proxy实现响应式
  • 在这里插入图片描述

2. 两者区别和使用场景

  • ref可以用来定义基本类型或者对象类型的响应式数据,定义对象的响应式时其实是求助了Proxy
  • reactive只能定义对象类型的响应式数据

  • ref返回的是RefImpl对象,需要通过.value的方式才能取到里面的值
  • reactive直接.属性名就可以获取属性

  • 对于对象形式的使用reactive更方便,因为不用每个都.value
  • 一般可以把数据封装成对象形式,用reactive更加方便

Vue3中计算属性

  • 和vue2中类似,但是可以写在setup中

1. 用法

  • 只用通过计算属性将现有的值计算后导出,而不用在计算属性中操作别的数据时,使用简易写法,一般不在computed中修改数据,简易写法一般够用
const 属性名=computed(()=>{
	return 计算出来的属性
})

Vue3中的监听函数watch

  • 和vue2中类似,但有很多小细节

1. 用法

  • 监视一个数据
watch(要监听的数据,(newValue,oldValue)=>{
	console.log('xxx的数据被修改了')
},{immediate:true,deep:true})
  • 监视多个数据,写一个数组
watch([要监听的数据1,数据2...](newValue,oldValue)=>{
	console.log('xxx的数据被修改了')
},{immediate:true,deep:true})
  • 监视对象中的某个属性时
watch(()=>对象.属性,(newValue,oldValue)=>{
	console.log('xxx的数据被修改了')
},{immediate:true,deep:true})

在这里插入图片描述

2. 注意点

  • 监视的数据必须是响应式的,即为ref()或者reactive()包裹的数据
  • 监测ref处理的数据,不需要.value
  • 当监视的是reactive处理的整个对象时,oldVal无法获取
  • 当监视的当监视的是reactive处理的整个对象时,强制deep:true 深度监视,对象内部属性被修改也能监视到
  • 但如果监视的是对象中的某个对象时,deep:true 深度监视才能监视的到
    在这里插入图片描述

watchEffect

  • 作用:自动监听回调函数里面用到的响应式数据的改变
  • 和watch的区别:不用指出监视是什么属性,回调中用到什么属性就监视什么属性
  • 与computed的有点相似,但有点区别:watchEffect更注重过程(回调函数体),而计算属性注重返回值

1. 用法

const person=reactive({
	name:'jojo'
})
watchEffect(()=>{
	let name=person.name
	//这里用到了响应式数据person,因此就会监视person.name
	console.log(‘回调执行’)
})

在这里插入图片描述


自定义hook函数

  • 类似于vue2重点mixin,将setup中使用的组合式API进行封装,可以供其他组件中使用
  • 本质是个函数,供其他组件引入后调用,获得其返回值

1. 使用

  • 首先创建一个js文件,将其导出
    在这里插入图片描述
  • 使用端:引入这个函数,之后就可以使用了
    在这里插入图片描述

2. 优势

  • 实现了代码的高复用
  • hook中可以包含任何的组合式api,``将组合式api进行了封装
  • 使用端不用关注hook函数中是如何实现的,只关注其提供的功能(返回的参数),可以让setup中逻辑更清晰易懂

toRef和toRefs

  • 作用:将数据变成响应式数据
  • 当对象中的属性想写成一个个的响应式数据的时候,toRef可以大大提高效率

toRef用法

toRef(对象名,要单独变成响应式数据的属性名)

setup() {
        const person=reactive({
            name:'jojo',
            age:90,
            hobby:{
                violin:'twoSetViolin',
                pho:'saul'
            }
        })
        return {
            name:toRef(person,'name'),
            hobby:toRef(person,'hobby')
        }
    }

toRefs的用法

  • 上文中如果一个对象有100个属性,那还是得写一百行才能把一个个属性都变成响应式,toRefs就是来解决这一点,配合拓展运算符可以一次性将所有属性都变成响应式
  • ...toRefs(对象)
    在这里插入图片描述

provide&inject

  • 实现父组件和子孙组件之间很方便的通信
  • 在父组件provide,需要的地方inject注入即可

1. 使用

祖宗组件中provide(要传的数据名,要传的数据)

setup(){
	const person={name:'jojo',age:90}
	provide('personData',person)
}

子孙组件中inject('数据名')

const person2=inject('personData')

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值