template:

  1. /*
  2. main.js
  3. */
  4. Vue.config.productionTip = false //关闭提示
  5. Vue.filter('过滤器名',function(){}) //配置全局过滤器
  6. Vue.directive('自定义指令名',{}) //配置全局自定义指令名
  7. Vue.directive('自定义指令名',function(){}) //配置全局自定义指令名
  8. /*
  9. 组件中的script标签
  10. */
  11. export default{
  12. component:{
  13. School,
  14. }
  15. //数据根目录
  16. data(){
  17. return {}
  18. },
  19. //计算属性
  20. computed:{
  21. computed1(){ return 'xxx' },
  22. computed2:{
  23. get(){},
  24. set(){}
  25. }
  26. },
  27. //方法
  28. methods:{
  29. showInfo(){}
  30. },
  31. //局部过滤器
  32. filters:{
  33. filter1(){}
  34. },
  35. //局部自定义指令
  36. directives:{
  37. directive1(){}, //简写
  38. directive2:{
  39. bind(){},
  40. inserted(){},
  41. update(){}
  42. }
  43. },
  44. //接收传递的属性
  45. props:[],
  46. //混合
  47. mixins:[],
  48. }

5.容器与实例对应规则

容器和vue实例一一对应,一个实例对应多个容器则只操作第一个容器,多个实例对应一个容器则接受第一个容器
真实开发中只有一个vue实例,并且配合着组件一起使用

7.模板语法

两大类
1.插值语法:用于解析标签体内容
写法:{{xxx}},xxx是js表达式,读取data中所有属性

2.指令语法:用于解析标签(包括标签属性、标签体内容、绑定事件)
写法:v-bind:href=’xxx’ / :href=’xxx’
xxx是js表达式,读取data中所有属性

  1. <!-- 这里的url不再是字符串,而是js表达式,去实例的data中寻找变量--!>
  2. <a v-bind:href='url'/>
  3. <a :href='url'>

8.数据绑定

1.单向绑定(v-bind):数据只能从data流向页面
2.双向绑定(v-model):数据双向流动
双向绑定只能用在表单类元素上(带value属性的元素),且v-model绑定的是value值,所以v-model:value=’xxx’可以简写为v-model:’xxx’

9.el和data的两种写法

el的另外一种写法:vue实例的原型上的$mount方法绑定el

  1. /*
  2. main.js
  3. */
  4. new Vue({
  5. el:'#root', //vue实例掌管的容器
  6. data:{
  7. name:'...'
  8. } //对象式
  9. })
  10. const v = new Vue({
  11. data(){
  12. return{
  13. name:'xxx'
  14. }
  15. } //函数式
  16. })
  17. //v.__proto__.$mount('#root')
  18. v.$mount('#root') //同等与在vue配置对象设置el

data必须使用函数式,避免组件复用时变量存在引用关系,且只能写一般函数,函数内部this指向vue实例,说明是vue实例调用了data函数

10.MVVM

M:模型(Model):data中的数据
V:视图(View):模板代码
VM:视图模型(ViewModel):Vue实例 (其中有dom listeners和data bindings)
1.data中所有的属性,最后都出现在了vm身上(数据代理)
2.vm身上所有的属性及vue原型上所有属性,在Vue模板中都可以直接使用

11.Object.defineProperty()

方法接收三个属性:对象、属性、配置项

  1. Object.defineProperty(person,'age',{
  2. value:18,
  3. enumerable:true, //属性是否可以遍历,默认值false
  4. writable:true, //属性是否可以修改,默认值false
  5. configurable:true //属性是否可以删除,默认值false
  6. })

高级属性:getter、setter

  1. //需求:age的值取决于number变量,且number变量会改变,需要age不重新设置则随之改变
  2. Object.defineProperty(person,'age',{
  3. //当person的age属性被读取时,get函数(getter)就会被调用,且返回值就是age的值
  4. get(){
  5. //实现age读取number的值
  6. return number
  7. },
  8. //当person的age属性被修改时,set函数(setter)就会被调用,且会受到修改的具体值
  9. set(value){
  10. //实现age被修改时,会同时改变number
  11. number = value
  12. }
  13. })

12.数据代理(劫持):通过一个对象代理对另一个对象属性的操作

13.vue中的数据代理

1.Vue中的数据代理:通过vm对象来代理data对象中的属性的操作
2.Vue中数据代理的好处:更加方便地操作data中的数据
3.基本原理:
通过Object.defineProperty()把data对象中所有属性添加到vm上,为每一个添加到vm上的属性,都指定一个getter/setter,在getter/setter内部去操作data中对应的属性
image.png

14.事件处理

1.使用v-on:click=’xxx’或@click=’xxx’ 绑定事件,xxx是回调;
2.事件的回调需要配置在methods对象中,最终会直接复制到vm上;(data做数据代理,methods没有)
3.methods中配置的函数,是被Vue所管理的函数,一般函数this指向是vm或组件实例对象;
4.@click=’demo’ 和 @click=’demo($event)’ 效果一致,但后者可以传参

15.事件修饰符

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

16.键盘事件

@keyup @keydown两个事件监听键盘,一般使用@keyup
1.vue中常用的按键别名(事件修饰符):
回车 enter
删除 delete
退出 esc
空格 space
换行 tab (特殊,需要配合keydown使用)
上 up
下 down
左 left
右 right
2.vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
3.系统修饰键(用法特殊):ctrl、alt、shift、meta
配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
配合keydown使用:正常触发事件
4.Vue.config.keyCodes.自定义键名 = 键码,自定义按键别名

事件修饰符和按键别名都可以链式调用

19-20.计算属性

1.定义:要用的属性不存在,需要通过已有属性计算(包括vm外的数据,但是此时数据不能管理)
2.原理:底层借助了Object.defineProperty方法的getter和setter
3.get函数执行时机:
初次读取时执行一次
依赖数据发生改变时会被再次调用
4.优势:与methods实现相比,内部又缓存机制(复用),效率更高,调试方便
5.备注:
计算属性最终会出现在vm上,直接读取即可
如果计算属性要被修改,必须写setter,且setter修改依赖数据(从再次执行get得到计算属性,不能直接修改计算属性)

  1. //完整:
  2. new Vue({
  3. computed:{
  4. computed1:{
  5. get(){},
  6. set(){}
  7. }
  8. }
  9. })
  10. //只有getter的简写:
  11. new Vue({
  12. computed:{
  13. computed1(){}
  14. }
  15. })

22-24.监视属性

1.当被监视的属性变化时,handler回调函数自动调用
2.监视的两种写法:
new Vue时传入watch配置
通过vm.$watch方法监视
3.watch默认监视一层(优化性能),通过配置对象中设置deep:true开启深度监视监视多层数据结构
4.简写:配置对象中只有handler时,可以使用handler函数直接替代配置对象的位置。函数必须为一般函数。

  1. new Vue({
  2. watch:{
  3. isHot:{
  4. immediate:true, //初始化调用handler
  5. deep:true, //开启深度监视
  6. handler(newValue,oldValue){}
  7. }
  8. }
  9. })
  10. vm.$watch({
  11. handler(){}
  12. })

25.watch vs computed

1.computed更轻便,watch更灵活(异步任务等)
两个原则:
1.vue管理的函数最好写成普通函数,this指向是vm 或 组件实例对象
2.不被vue管理的函数最好写成箭头函数,更深层次的函数的this是vm 或 组件实例对象

26.class的绑定样式

1.字符串写法:样式类名不确定,需要动态指定
2.数组写法:要绑定的样式个数不确定,名字也不确定
3.对象写法:要绑定的样式个数确定,名字确定,但要动态决定用不用

  1. <div :class='mood' @click='changeMood'/>
  2. <div :class='classArr'/>
  3. <div :class='classObj'/>
  4. /*
  5. classArr = ['atguigu1','atguigu2']
  6. classObj = {
  7. atguigu1:false,
  8. atguigu2:true
  9. }
  10. */

27.style的绑定样式

两种方式:对象式、数组式
对象式:jsx的双括号,外层的括号改成引号
数组式:多个style对象放到一个数组里

28.条件渲染 v-show / v-if

v-show设置display:none进行隐藏,适用于切换频率高的场景
v-if挂载/卸载节点,还有v-else-if v-else,但是需要连续使用,不能中途插入其他节点
template(空节点)配合v-if

29-32.遍历渲染 v-for

v-for= ‘(a,b) in xxx’ 可遍历数组、对象、字符串和指定次数
需要使用:key指定key,没有指定key则自动指定index为key

列表过滤:使用computed重新计算属性实现过滤

33-37 数据监视原理 / 数据劫持

1.Vue会监视data中所有层次的数据
2.监测对象数据
通过setter实现监视,且要在new Vue时就传入要监测的数据
如需给后添加的属性做响应式,需要用到如下API
Vue.set(taget,propertyName/index,value) 或
vue.$set(taget,propertyName/index,value)
3.监测数组数据
通过包裹更改数组的方法实现,本质是:(1)调用原生api更改数组,(2)重新解析模板,进而更新页面
4.vue更新数组的方法
APIs:push() pop() unshift() shift() splice() sort() reverse()
Vue.set() vue.$set()
数组替换

注意:Vue.set()和vue.$set()不能给vm或vm的根数据对象(vm._data)添加属性
(后续可以用Vue.set做子传父的props?类似this.setState?)

响应式:数据变化带动页面变化
Vue的数据劫持:创建Vue实例的配置对象的data和vm的根数据对象并非直接赋值,而是经过加工后赋值,加工的过程称为数据劫持。vue的数据劫持过程模拟如下

  1. //模拟实例化Vue配置对象的数据
  2. let data = {
  3. name:'xxx',
  4. age:18
  5. }
  6. //第一步:数据劫持的模拟
  7. const obs = new Observer(data)
  8. //模拟实例化
  9. let vm = {}
  10. vm._data = data = obs //第二步:赋值给vm._data
  11. //构造函数模拟劫持
  12. function Observer(obj){
  13. const keys = Object.keys(obj)
  14. keys.forEach(k => {
  15. Object.defineProperty(this,k,{
  16. get(){
  17. return obj[k]
  18. },
  19. set(value){
  20. console.log('此处模拟解析模板,生成虚拟dom,对比算法')
  21. obj[k] = value
  22. }
  23. })
  24. })
  25. }

38.各种表单的v-model使用

1.text框:v-model收集的是value值,用户输入也是value值
2.radio框:v-model收集的是value值,需要给标签配置value值,且同组radio配置相同name
3.checkbox框:
没有配置value属性,那么收集的是checked值
配置了value属性:
v-model初始值是非数组,收集的还是checked值
v-model初始值是数组,收集的是value值的数组
4.v-model的三个修饰符:
lazy:失去焦点再收集数据,适用于textarea
number:输入字符串转为有效数字,适用于text=number
trim:输入首尾空格过滤

39.过滤器

定义:对要显示的数据进行特定格式化再显示(适用于一些简单逻辑的处理)
语法:
1.注册过滤器:Vue.filter(name,callback) 或 new Vue({filters:{}})
2.使用过滤器 {{XXX | 过滤器名}} 或 v-bind:属性 = ‘xxx | 过滤器名’
备注:
1.过滤器也可以接收额外参数,多个过滤器也可以串联
2.并没有改变原本的数据,是产生新的对应的数据
20211114补充:fliter和computed都不能接收参数,如格式化(判断)需要用到结构中的数据(v-for中item)还是得用到methods。

40-41.v-text v-html

1.作用:v-html向指定节点中渲染包含html结构的内容,v-text则不包含结构
2.与插值语法的区别
v-html/v-text会替换掉节点的所有内容,插值语法则不会
v-html可以识别html结构
3.v-html有安全性问题
网站上动态渲染任意HTML是危险的,容易导致XSS攻击
一定要在可信的内容上使用v-html,不要在用户提交内容上使用

cookie:本质是字符串,格式是对象image.png

42.v-cloak

1.本质是一个特殊属性(没有值),Vue实例创建完毕并接管容器后会删掉v-cloak属性
2.使用css配合v-cloak可以解决网速慢页面展示出{{xxx}}的问题

43.v-once

1.v-once(没有值)所在节点在初次动态渲染后,就视为静态内容了
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
区别于事件修饰符.once : 只能触发一次事件

44.v-pre

跳过其所在节点的vue解析过程,加快编译速度,可用于没有指定语法和插值语法的节点

45-47.自定义指令

1.两种定义语法与配置对象的三个回调:

  1. //局部
  2. new Vue({
  3. directives:{
  4. directive1(){}, //bind和update时调用
  5. directive2:{
  6. bind(){}, //指令与元素成功绑定时调用
  7. inserted(){}, //指令所在元素被插入页面时调用
  8. update(){} //指令所在模板结构被重新解析时调用
  9. }
  10. }
  11. })

2.指令定义时不加v-,使用时要加v-;指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名

48.生命周期

环节1.初始化生命周期、监听事件、渲染方法,但数据代理还没开始
钩子1:beforeCreate
环节2.初始化:数据监测、数据代理
钩子2:created
(这里的create是指create数据监测、数据代理,这里的this是vm)

环节3.检查el(有则继续无则挂起)、template(有则template替换#root,无则使用#root);vue开始解析模板,生成虚拟DOM,页面还不能显示分析好的内容,而是显示原始内容
钩子3:beforeMount (此阶段对DOM的操作最终都被覆盖)
环节4.虚拟DOM转为真实DOM并把真实DOM存到vm.$el,
重要钩子4:mounted

遇到更新数据的情况
钩子5:beforeUpdate(数据与页面不同步)
环节:生成新虚拟dom,新旧虚拟DOM比较,完成页面更新,即model -> view的更新
钩子6:updated(数据与页面同步)

vm.$destory()用于销毁vm实例(但真实DOM还会保留)
重要钩子7:beforeDestory(此时vm的data、methods、指令都处于可用状态,但不再触发更新流程,只做收尾工作)
环节:vm实例卸载
钩子8:destoryed

钩子9:this.$nextTick-下次DOM渲染之后执行其中操作
钩子10:activated
钩子11:deactivated

53.模块、组件

模块定义:向外提供特定功能的js程序,是js文件。作用:复用js,简化js编写,提高js运行效率
组件定义:实现应用中局部功能代码和资源的集合。作用:复用编码,简化项目编码,提高运行效率

54-55.vue的组件

  1. /*
  2. 第一步:创建组件
  3. 1.el不要写:最终所有的组件都经过vm的管理,由vm中的el决定服务哪个容器
  4. 2.data必须写成函数:避免组件被复用时,数据存在引用关系(独立)
  5. const school = Vue.extend(options)可简写为const school = options
  6. */
  7. const school = Vue.extends({
  8. template:``,
  9. data(){
  10. return {}
  11. }
  12. })
  13. //第二步:局部注册组件
  14. new Vue({
  15. el:'#root',
  16. components:{
  17. school
  18. }
  19. })
  20. //第二步:全局注册组件
  21. Vue.component('school',school)
  22. //第三步:引用组件-以标签的形式放入#root中,如<school></school>

组件名:
一个单词:首字母大小写均可
两个单词:kebab-case CamelCase均可

57.VueComponent的构造函数

1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
2.我们只需写,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)
3.特别注意:每次调用Vue.extend 返回的都是一个全新的VueComponent
4.关于this指向:
(1)组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数,它们的this均是 VueComponent实例对象;
(2)new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数,它们的this均是 Vue实例对象

59.原型链继承

VueComponent.prototype.proto === Vue.prototype
组件实例对象沿着原型链可以找到VueComponent.prototype,进而找到Vue.prototype,再进而找Object.prototype,由此组件实例对象可以访问到Vue原型的属性和方法

组件实例对象是小型的vm,和vm相比,组件实例对象的配置对象不能写el,data必须写函数形式

61-63.脚手架

npm i -g @vue/cli //安装脚手架
vue create xxx //创建脚手架
render函数:
1.vue.js与vue.runtime.xxx.js的区别:
vue.js是完整版的Vue,包含:核心功能+模板解析器
vue.runtime.xxx.js是运行版的Vue,只包含:核心功能,没有模板解析器
通过import Vue from ‘Vue’引入的是vue.runtime.xxx.js,可以在vue的package.js中module属性查看引入的文件
2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容

65.Vue的ref属性

用作给元素或子组件注册引用信息,获取到元素的真实DOM元素或子组件的组件实例对象(虚拟DOM)
字符串的形式标识,通过this.$refs获取

66.Vue的props属性

传递:标签内传递属性
接收:

  1. //1.简单接收
  2. props:['name']
  3. //2.限制类型
  4. props:{
  5. name:String,
  6. age:Number
  7. }
  8. //3.限制类型、必要性,指定默认值
  9. props:{
  10. name:{
  11. type:string
  12. require:true,
  13. default:'Tom' //必要性和默认值同时使用无意义
  14. }
  15. }

props是只读的(之前的react项目做得挺有问题的),vue底层会监测对props的修改(浅层监测,只监测引用),修改则警告。如业务需求,则应该复制props到data中再修改data(props的声明优先级高于data)
props也有数据劫持

67.mixin混合

功能:可以把多个组件共用的配置提取成一个混入对象
全局:Vue.mixin(xxx)
局部:通过配置项的mixins属性: mixins:[‘xxx’]

68.插件

功能:用于增强Vue
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据

  1. //定义插件:plugins.js
  2. export default {
  3. install(){
  4. //添加全局过滤器,添加全局指令,配置全局混入,添加实例方法等
  5. }
  6. }
  7. //使用:在main.js创建vm之前引用plugins.js
  8. Vue.use(plugins)

69.样式的scoped属性

限定样式为局部样式,仅应用于当前组件

npm view webpack versions //查看webpack的所有版本

78.webStorage

1.存储内容大小一般支持5MB(不同浏览器不同)
2.浏览器通过window.sessionStorage和window.localStorage属性实现本地存储机制
3.相关API:
xxxxStorage.setItem(‘key’,’value’)
xxxxStorage.getItem(‘key’)
xxxxStorage.removeItem(‘key’)
xxxxStorage.clear()
4.备注:
1.sessionStorage存储的内容会随着浏览器窗口关闭而消失

80-82.自定义事件

1.一种组件间通信的方式,适用于:子组件===>父组件
2.使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)
3.绑定自定义事件:
第一种方式:在父组件中,
第二种方式:在父组件中,给组件上ref,在mounted钩子里 this.$refs.xxx.$on(‘atguigu’,this.test)
若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法
4.触发自定义事件 this.$emit(‘atguigu’,数据)
数据可以传多个,接收可以以 …arg的形式接收为数组
5.解绑自定义事件 this.$off(‘atguigu’)
6.组件上也可以绑定事件默认是绑定自定义事件,如绑定原生DOM事件需要.native修饰符
7.注意:通过this.$ref.xxx.$on(‘atguigu’,回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出现问题。
谁绑定的事件,谁提供回调。绑定给谁的,谁调用

应用:用于替代父传子的函数,原先需要调用函数的地方改为触发自定义事件

84-85.全局事件总线

1.一种组件间通信的方式,适用于任意组件间通信。
原理:
存在一个变量,所有组件实例对象都能对其操作(绑定事件及触发事件),其自身也有$on $emit $off等方法。
当需要跨组件通信时,接收者对其绑定自定义事件,发送者触发其自定义事件,则能通过其进行通信。
2.安装全局事件总线

  1. new Vue({
  2. ...
  3. beforeCreate(){
  4. Vue.prototype.$bus = this //安装全局事件总线
  5. }
  6. })
  7. /*
  8. 条件1:所有组件实例和Vue实例都能调用 ===> 将其定义在Vue原型
  9. 条件2:其能调用$on $emit $off等在Vue原型的方法 ===> 让其成为组件实例或Vue实例(此处为Vue实例)
  10. */

3.使用事件总线
1.接收数据 在mounted钩子中,this.$bus.$on(‘xxx’,()=>{})
2.提供数据 this.$bus.$emit(‘xxx’,data)
4.最好在接收数据(绑定事件)的组件中,用beforeDestory钩子中,用$off去解绑当前组件所用到的事件

90.$nextTick

语法:this.$nextTick(回调函数)
作用:在下一次DOM更新结束后执行其指定的回调
场景:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。(因为Vue会将整个回调函数的语句都执行完再进行模板的重新渲染)
例如:新出现的input框获取焦点:this.$refs.inputTiltie.focus()

91-95.Vue封装的过度与动画

1.作用:再插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名
2.写法
1.准备好样式:三方库、动画、过渡

  1. /*
  2. 三方库:npm i animate.css --save
  3. 只需在template设置name和进场离场过程样式即可
  4. */
  5. <template>
  6. <transition
  7. name='animate_animated animate_bounce'
  8. enter-active-class='xx'
  9. leave-active-class='xx'
  10. >
  11. <h1 v-show='isShow'>xxx</h1>
  12. </transition>
  13. </template>
  14. /*
  15. 动画
  16. */
  17. <style>
  18. .name-enter-active{
  19. animation:atguigu 1s
  20. }
  21. .name-leave-active{
  22. animation:atguigu 1s reverse
  23. }
  24. @keyframe atguigu{
  25. from{
  26. transform:translateX(-100%)
  27. }
  28. to{
  29. transform:translateX(0)
  30. }
  31. }
  32. </style>
  33. /*
  34. 过渡
  35. */
  36. <style>
  37. .name-enter-active,.name-leave-active{
  38. animation:1s
  39. }
  40. .name-enter,.name-leave-to{
  41. transform:translateX(-100%)
  42. }
  43. .name-leave,.name-enter-to{
  44. transform:translateX(0)
  45. }
  46. </style>

元素进入/离开的样式:
v-enter/leave:进入/离开的起点,只有短暂的一帧生效
v-enter/leave to:进入/离开的终点,过程持续生效
v-enter/leave-active:进入/离开的过程,一般用来指定时间
v-enter-to:进入的终点
2.使用transition包裹过渡元素并配置name

  1. <transition>
  2. <h1 v-show='isShow'>xxx</h1>
  3. </transition>

3.若有多个元素则应该使用transition-group标签,且每个元素配置key属性

appear属性表示初次渲染执行进场动画

96-97.配置代理

方法一:在vue.config.js中添加如下配置:

  1. devServer:{
  2. proxy:"http://localhost:5000"
  3. }

优点:配置简单,请求资源时直接发给前端(8080)即可
缺点:不能配置多个代理,不能灵活控制请求是否走代理
工作方式:优先匹配前端资源,前端不存在则转发请求给服务器

方法二:

  1. devServer:{
  2. '/atguigu':{
  3. target:'http://localhost:5000',
  4. pathRewrite:{'^/atguigu':''},
  5. ws:true, //websocket
  6. changeOrigin:true //用于控制请求头中的host值
  7. }
  8. }

优点:可以配置多个代理,且可以灵活的控制请求是否走代理
缺点:配置略微繁琐,请求资源时必须加前缀

React是在package.json中配置代理

101.vue-resource

vue1.0使用的一个用于发送ajax请求的插件库,现在不推荐使用,推荐使用axios

  1. import vueResource from 'vue-resource'
  2. Vue.use(vueResource)
  3. //由此Vue实例和组件实例多了一个$http属性,通过$http.get() $http.post()发送请求

102-104.插槽

1.作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信方式,适用于父组件===>子组件,使得组件的复用更灵活
2.分类:默认插槽、具名插槽、作用域插槽
3.使用方式
1.默认插槽:

  1. //父组件:
  2. <Category>
  3. <div>html结构</div>
  4. </Category>
  5. //子组件:
  6. <template>
  7. <slot>插槽默认内容</slot>
  8. </template>

2.具名插槽:具有名字的插槽

  1. //父组件,template包裹多个结构一并传入,或分别传入,分别传入用v-slot:xxx
  2. <Category>
  3. <template v-slot:footer>
  4. <div>html结构</div>
  5. </template>
  6. </Category>
  7. //子组件
  8. <template>
  9. <slot name='footer'>插槽默认内容</slot>
  10. </template>

3.作用域插槽:数组在组件自身,但根据数据生成的结构在父组件中

  1. //父组件:Vue3把scope='footer'替换成v-slot='footer',接收到一个对象
  2. <Category>
  3. <template slot-scope='anywords'>
  4. <div>html结构</div>
  5. </template>
  6. </Category>
  7. //子组件 把data中的games往父组件中自己的起始标签和结束标签中传
  8. <template>
  9. <slot :games='games'>插槽默认内容</slot>
  10. </template>

105-116.vuex

1.搭建环境

  1. //创建store/index.js
  2. import Vue from 'vue'
  3. import Vuex from 'vuex'
  4. const actions = {
  5. incrementOdd(context,value){ //context是精简版的stroe,内含dispatch,commit,state等
  6. if(context.state.sum % 2){
  7. context.commit('INCREMENT',value)
  8. }
  9. }
  10. }
  11. const mutations = {
  12. INCREMENT(state,value){
  13. state.sum += value
  14. }
  15. }
  16. const state = {
  17. sum:0
  18. }
  19. const getters = {
  20. bigSum(state){
  21. return state.sum*10
  22. }
  23. }
  24. export default Vuex.Store({actions,mutations,state,getters})
  25. //main.js中配置store
  26. import store from './store'
  27. new Vue({
  28. el:'#root',
  29. ....
  30. store,
  31. })

2.组件中读取vuex中的数据:this.$store.state.xxx / $store.state.xxx
3.组件中修改vuex中的数据:this.$store.dispatch(‘action方法名’,value) / this.$store.commit(‘mutation方法名’,value)
4.当state中的数据需要经过加工后再使用,可以使用getters加工,读取时向getters读取:this.$store.getters.xxx / $store.getters.xxx

5.四个map的方法
1.mapState
2.mapGetters
3.mapActions
4.mapMutations

  1. /*
  2. mapState / mapGetters 方法:映射state和getters中的数据,方便读取数据
  3. 生成一个对象,里面对应每个值为mappedState/mappedGetters函数
  4. mapActions / mapMutations 方法:生成和actions/mutations沟通的dispatch/commit方法
  5. ...mapActions({increment:'JIA'})
  6. 生成
  7. increment(value){
  8. this.$store.dispatch('JIA',value)
  9. }
  10. 此时注意value,需要绑定事件时传入value,否则value是event
  11. */
  12. import { mapState, mapGetters, mapActions, mapMutations } = 'vuex'
  13. computed:{
  14. //对象式写法,从state的sum中读取属性到computed的he
  15. ...mapState({he:'sum',xuexiao:'school',xueke:'subject'})
  16. //数组式写法,当state和computed属性同名
  17. ...mapState(['sum','school','subject'])
  18. ...mapGetters({dahe:'bigSum'})
  19. ...mapGetters(['bigSum'])
  20. }
  21. methods:{
  22. //同样有对象写法和数组写法
  23. ...mapActions({})
  24. ...mapActions([])
  25. ...mapMutations({})
  26. ...mapMutations([])
  27. }

6.模块化vuex

  1. /*
  2. store/index.js
  3. */
  4. const personOptions = {
  5. namespaced:true,
  6. actions = {},
  7. mutations = {},
  8. state = {},
  9. getters = {}
  10. }
  11. export default Vuex.Store({
  12. modules:{
  13. personAbout:personOptions
  14. }
  15. })
  16. /*
  17. 组件:四个map方法,方法新增第一个参数:vuex模块化的名字
  18. */
  19. import { mapState, mapGetters, mapActions, mapMutations } = 'vuex'
  20. computed:{
  21. ...mapState('personAbout',[])
  22. ...mapGetters('personAbout',['bigSum'])
  23. }
  24. methods:{
  25. ...mapActions('personAbout',{})
  26. ...mapMutations('personAbout',{})
  27. }
  28. /*
  29. 组件普通写法:getter写成'personAbout/personList',其他均多一级即可
  30. */

117-133.路由

路由器router监视路径。路由是一组映射关系,key为路径,value为function(后端)或component(前端)
基本使用

  1. /*
  2. 安装vue-router插件
  3. 编写router/index.js 用于配置路由关系
  4. */
  5. import VueRouter from 'vue-router'
  6. import...
  7. export default new VueRouter({
  8. //mode:'history', //默认hash模式
  9. routes:[
  10. {
  11. path:'/home',
  12. component:Home
  13. },
  14. {
  15. path:'/about',
  16. component:About,
  17. children:[
  18. {
  19. path:'news', //二级路由path不写斜杠
  20. component:News
  21. }
  22. ]
  23. },
  24. ]
  25. })
  26. /*
  27. main.js
  28. */
  29. import VueRouter from 'vue-router'
  30. import router from './router'
  31. Vue.use(VueRouter)
  32. new Vue({
  33. ...,
  34. router,
  35. })
  36. /*
  37. React中的Link组件,在Vue中是<router-link>,to属性需要把多级路径写全,可添加replace属性:表示历史记录replace
  38. React中的Route组件,在Vue中是<router-view>,且不需要额外配置关系
  39. */
  40. <router-link class='' active-class='' to='/home'/>
  41. <router-view>
  42. /* vue3 */
  43. //router.js
  44. import { createRouter } from 'vue-router'
  45. const routes = [
  46. {},{}
  47. ]
  48. const router = createRouter({routes})
  49. export default router
  50. //main.js
  51. import router from './router'
  52. createApp(App).use(router).mount(#app)

注意:
1.被切走的组件实际是卸载了
2.每个组件实例都有自己的$route属性,存储着自己的路由信息,且有共同的$router属性

传参1:query传参:跳转的参数在实例的$route.query属性中

  1. //跳转路由并携带query参数,to的字符串写法
  2. <router-link :to='`/home/message/detail?id=${m.id}&title=${m.title}`'/>
  3. //跳转路由并携带query参数,to的对象写法
  4. <router-link
  5. :to="{
  6. path:'/home/message/detail',
  7. query:{
  8. id:m.id,
  9. title:m.title
  10. }
  11. }"
  12. />

路由命名:to的对象写法path可以使用name替代,但需要事先在router/index.js配置name。

传参2:params传参:跳转的参数在实例的$route.params属性中

  1. /*
  2. 在router/index.js配置路径时需要声明接收params参数
  3. */
  4. {
  5. name:'xiangqing',
  6. path:'detail/:id/:title', //使用占位符接收params参数
  7. component:Detail
  8. }
  9. /*
  10. 传参跳转
  11. to的对象式写法不能用path,必须用name
  12. */
  13. <route-link :to='`/home/message/detail/${m.id}/${m.title}`'/>
  14. <route-link
  15. :to="{
  16. name:'xiangqing',
  17. params:{
  18. id:m.id,
  19. title:m.title
  20. }
  21. }"
  22. />

传参的使用:
1.在模板中直接$route.query/params使用,没有响应式(也不需要),但刷新会丢失;
2.传到data里,会多了响应式(vue3可以解决)

以props的形式接收路由传参:在router/index.js配置props属性
方法一:值为对象,该对象中所有的key-value都会以props的形式传给Detail组件(写死)
props:{a:1,b:’hello’}
方法二:值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件
方法三:props为函数,return一个对象,对象中的属性会以props分别传给组件,且函数接收$route

編程式路由:方法均在VueRouter的原型上,this.$router是VueRouter的实例。push/replace均传入配置对象,即route-link中to的对象式写法的对象
this.$router.push()
this.$router.replace()
this.$router.back()
this.$router.forward()
this.$router.go(n) //跳转n步

缓存路由组件:让不展示的路由保持挂载,不被销毁

  1. <keep-alive :include='["News"]'> //News是组件名,即实例中配置对象的name属性。写一个直接写字符串
  2. <router-view />
  3. </keep-alive>

两个生命周期钩子:用于捕获路由组件的激活状态
activated:路由组件被激活时触发
deactivated:路由组件失活时触发

路由守卫:全局守卫、独享守卫、组件内守卫
beforeEach全局前置路由守卫——初始化的时候,每次路由切换之前被调用,用于检验权限
afterEach全局前置路由守卫——初始化的时候,每次路由切换之后被调用,用于跳转后修改标题
beforeEnter独享路由守卫:在单个route的配置对象中设置,只有前置
beforeRouteEnter组件内守卫进入前,写在组件实例的配置根目录
beforeRouteLeave组件内守卫离开前,写在组件实例的配置根目录

  1. /*
  2. router/index.js
  3. */
  4. import VueRouter from 'vue-router'
  5. const router = new VueRouter({
  6. routes:[
  7. {
  8. ...
  9. beforeEnter:(to,from,next)=>{}, //独享路由守卫,只有前置
  10. }
  11. ]
  12. })
  13. //全局前置路由守卫
  14. router.beforeEach((to,from,next)=>{
  15. //to/from是vueRouter实例,next函数表示通行
  16. })
  17. //全局后置路由守卫
  18. router.afterEach((to,from)=>{})
  19. export default router
  20. /*
  21. 组件内路由:组件实例
  22. */
  23. <script>
  24. export default {
  25. beforeRouteEnter(to,from,next){},
  26. beforeRouteLeave(to,from,next){}
  27. }
  28. </script>

133.node!!

138.vite

  1. npm init vite-app <project-name>
  2. cd <project-name>
  3. npm install
  4. npm run dev

139.工程结构

vue3的main.js,对比p9

  1. //不再引入vue构造函数,而是createApp工厂函数。(构造函数new调用,工厂函数不用)
  2. import { createApp } from 'vue'
  3. import App from './App.vue'
  4. //创建应用实例对象——app(类似于之前Vue2中的vm,单app比vm更“轻”)
  5. const app = createApp(App)
  6. app.mount('#app')
  7. /*
  8. vue2的写法
  9. */
  10. new Vue({
  11. render: h => h(App)
  12. }).mount('#app')

141.setup

vue3的一个新配置,值为一个函数。函数内部写compositionAPI(组合API)以及数据、方法等。
setup函数的返回值:
1.对象,对象中的属性、方法都可以在模板中直接使用
2.渲染函数,自定义渲染内容,渲染内容覆盖模板 (jsx?)
注意尽量不要与vue2混用,也不能是async函数

常用的组合API:

142-143.引用对象

引用实现(RefImpl)的实例,用来定义一个响应式的数据(固定的数据直接写?)

  1. import { ref } from 'vue'
  2. const xxx = ref(initValue)
  3. xxx.value = ''

创建一个包含响应式数据的引用对象(reference对象),操作数据不能直接操作,需要通过value属性操作,但模板中读取则直接读取xxx
ref函数可以接收基本类型和对象对象,对于基本类型,响应式的实现基于Object.defineProperty()的get/set;对于对象类型,则基于reactive函数(RefImpl的value是一个Proxy实例)

144.reactive函数

作用:定义一个对象类型的响应式数据(基本类型用ref函数)
语法:const 代理对象= reactive(被代理对象) 接收一个对象(数组),返回一个代理器对象(proxy对象)
reactive定义的响应式数据是深层次的,内部基于ES6的Proxy实现,通过代理对象操作源对象内部数据都是响应式的

147.ref/reactive对比

定义数据:ref用于定义基本类型数据,reactive用于定义引用类型数据
原理:ref通过Oject.defineProperty()的get和set实现响应式(数据劫持),reactive通过Proxy实现响应式(数据劫持),并通过Reflect操作源对象内部的数据
使用角度:ref操作数据需要.value,模板读取不需要;reactive均不需要

145.Vue2响应式

存在问题:
1.新增、删除属性界面不更新。解决:通过this.$set/$delete Vue.set/delete对响应式数据做修改
2.直接通过下标修改数组,界面不会更新。解决:数组7个api,this.$set

146-147.Vue3响应式

通过Proxy(代理):拦截对象中任意属性的变化,包括:属性值的读写,属性的添加、删除等
通过Reflect对象(反射):对源对象的属性进行操作

  1. /*
  2. 模拟proxy实现响应式
  3. */
  4. new Proxy(data,{
  5. //读取属性值触发
  6. get(target,propName){
  7. //进行响应式操作
  8. return Reflect.get(target,propName)
  9. },
  10. //修改属性值,或新增属性触发
  11. set(target,propName,value){
  12. //进行响应式操作
  13. Reflect.set(target,propName,value)
  14. },
  15. //删除属性触发
  16. deleteProperty(target,propName){
  17. //进行响应式操作
  18. Reflect.deleteProperty(target,propName)
  19. }
  20. })

149.setup的两个注意点

setup执行的时机,在beforeCreate之前执行,this是undefined
setup的参数:
props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性(在setup外用props生命)
context:上下文对象
attrs:值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性,相当于this.$attrs
slots:收到的插槽内容,相当于this.$slot
emit:分发自定义事件的函数,相当于this.$emit(可能需要emits声明接收自定义事件)

150.计算属性

引入computed函数,setup内部调用computed函数,参数为函数(简写)或对象(完整写法),computed函数返回计算属性的值。

151-153.监视

引入watch函数,setup内部调用watch函数。参数为三个,第一个是监视的目标;第二个是触发监听的回调(回调默认接收newValue、oldValue),第三个(选配)为配置对象。

情况一:监听ref所定义的一个响应式数据
情况二:监听ref所定义的多个响应式数据,则第一个参数改为数组,数组内每个元素为监听的目标
情况三:监听reactive所定义的一个响应式数据,此时无法获得正确的oldValue,且强制开启deep监听
情况四:监听reactive所定义的响应式数据中的某个属性,则第一个参数改为回调,回调返回某个属性
情况五:监听reactive所定义的响应式数据中的某些属性,则第一个参数改为数组,数组内每个元素为回调,回调返回某个属性
情况六:监听reactive所定义的响应式数据中的某个引用型数据,此时配置对象的深度监听有效,但无法获得正确的oldValue

监听的目标是RefImpl / Proxy对象(而不是值),所以ref定义的基本类型数据是监听变量本身(RefImpl对象),而定义的引用类型数据是变量的value属性(Proxy对象)。

154.新增:watchEffect函数

watchEffect函数传入两个参数:回调、配置对象
watchEffect和computed的比较:
两者都能自动追踪需要监听的变量
computed注重的计算结果,所以回调函数必须有返回值,而watchEffect更注重过程,所以不用写返回值。而且watchEffect很像React的useEffect

155.生命钩子

beforeDestory ===》beforeUnmount
Destoryed ===》unmounted
通过配置项的形式写生命钩子:写在setup外面。
通过组合式API形式的生命周期钩子:从vue解构引入,写在setup里面:
没有了beforeCreate / created 对应API钩子
beforeMount /mounted / beforeUpdate / updated / beforeUnmount / unmounted 改成组合式API形式的生命钩子:都在前面加上on
同时使用两个形式,组合式API的调用早一些

156.hook

组合API:API指ref、reactive、计算属性与监视、生命周期等。组合是指允许在hook对其进行组合
hook:一个函数,把setup函数中舒勇的compositionAPI进行封装
自定义hook优势:复用代码,让setup逻辑更清楚易懂

157.toRef / toRefs

作用:创建一个ref对象,其value值指向另外一个对象中的某个属性
语法:const name = toRef(person,'name')
应用:要将响应式对象中的某个属性单独提供给外部使用,此时直接传递会丢失响应式,新建ref会丢失映射关系,toRef相当于建立新变量和原变量的映射关系且新变量是响应式的。
拓展:toRefs与toRef功能一致,但可以批量创建多个ref对象(只创建一层),语法:toRefs(person) 函数返回一个对象,里面每组key-value是原对象的属性和ObjectRefImpl

其他组合API:

158.shallowReactive与shallowRef

shallowReactive只处理对象最外层属性的响应式(浅响应式)
shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理
应用场景:
shallowReative:对象数据结构比较深,但只变化外层属性
shallowRef:后续不会改变对象数据的属性,而是直接替换新的对象

159.readonly与shallowReadonly

readonly:让一个响应式数据变为只读的(深只读)
shallowReadonly:让一个响应式数据变为只读的(浅只读)
应用场景:不希望数据被修改
与非响应式区别:非响应式是能够修改但不会重新渲染页面,对比toRaw和markRaw

160.toRaw与markRaw

toRaw函数接收一个reactivce生成的响应式数据,返回对应的普通对象。对普通对象进行任何操作都不会引起页面更新
markRaw函数接收一个数据,返回永不会被生成响应式的数据(即使后续交由reactive也不会被生成响应式)。
应用场景:数据源不可变时,避免生成响应式可以提高性能。

161.customRef

自定义ref,允许自己创建一个容器(代替ref包裹数据),容器内调用customRef实现响应式的逻辑。
customRef是一个函数,内部接收一个函数,内部函数接收track、trigger,返回一个对象,对象包含getter/setter。track函数用于getter通知追踪value,trigger函数用于setter通知实例重新解析模板

  1. function myRef(value){
  2. return customRef((track,trigger)=>{
  3. return {
  4. get(){
  5. track() //通知get追踪value
  6. return value
  7. },
  8. set(newValue){
  9. value = newValue
  10. trigger() //通知重新解析模板
  11. }
  12. }
  13. })
  14. }

162.provide与inject

用于祖先与后代的通信方式,祖先发布,后代订阅。provide和inject都是函数,provide接收两个变量:标识、数据,inject接收一个参数:标识,返回数据。

163.判断响应式数据

isRef:检查一个值是否为一个ref对象
isReative:检查一个对象是否是由reactive创建的响应式代理
isReadonly:检查一个对象是否是由readonly创建的只读代理
isProxy:检查一个对象是否是由reactive或readonly方法创建的代理

164.组合式API的优点

vue2的配置式API缺点:相同功能的data、methods、computed、watch需要分配写在配置API里,改动一个功能需要改动多个地方。
组合式API允许把一个功能的相关代码抽离成单独的函数(hook),甚至是文件,在setup中进行组合。

166.teleport

teleport标签内的结构可以传送到页面的任何地方,属性to=’’,可以填入标签名及css选择器

167.suspense

  1. import { lazy, Suspense } from 'react'
  2. import Loading from './Loading'
  3. /*
  4. 异步组件
  5. */
  6. const Login = lazy(() => import('./Pages/login'))
  7. const Admin = lazy(() => import('./Pages/admin'))
  8. /*
  9. 在 render 里
  10. */
  11. render() {
  12. return (
  13. <Suspense fallback={<Loading/>}>
  14. <Switch>
  15. <Route path='/login' component={Login} />
  16. <Route path='/' component={Admin} />
  17. </Switch>
  18. </Suspense>
  19. )
  20. }
  1. /*
  2. v-slot:default代表默认的内容
  3. v-slot:fallback代表备用的内容
  4. */
  5. <template>
  6. <Suspense>
  7. <template v-slot:default>
  8. <Child/>
  9. </template>
  10. <template v-slot:fallback>
  11. 加载中...
  12. </template>
  13. </Suspense>
  14. </template>
  15. <script>
  16. import { defineAsyncComponent } from 'vue'
  17. const Child = defineAsyncComponent(() => import('./Child'))
  18. </script>

异步引入的子组件(Child组件)的setup函数可以是async函数,返回值可以是Promise

168.全局API的转移

1.从Vue身上转到app组件身上了,同样写在main.js里
Vue.prototype.xxx ===> app.config.globalProperties
2.移除keyCode作为v-on的修饰符,兼容性。
3.移除v-on.native vue3父组件对子组件绑定自定义事件,子组件需要在配置api中使用emits进行声明,不声明则默认是原生事件

  1. export default {
  2. emits:['close']
  3. }

4.移除过滤器,使用computed代替