Vue2

初识Vue2.0

  1. 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象
  2. vue容器里的代码依然符合html规范,其中混入一些vue语法例如mustache语法的双花括号,mustache语法里面要写js表达式,且里面会自动读取到data中的所有属性。
  3. vue容器里的代码被称为Vue模板

new Vue时传入一个配置对象,值有比如:el用于指定当前vue实例;data用于储存数据
Vue实例和容器是一一对应的,真是开发中只有一个Vue实例,并且会配合着组件一起使用

Vue模板语法

vue模板语法有两大类。

  1. 插值语法(mustache语法):写法 {{xxx}},xxx里写的是js表达式,且可以直接督导data中的所有属性。
  2. 指令语法:写法例如 v-bind:href="xxx",可以简写成 :href="xxx",xxx里写的也是js表达式,可以直接读取到data中的所有属性。
  • 插值语法通常用于标签体内容(#text的内容),指令语法可用于标签属性,标签体内容,绑定事件等

数据绑定

  1. 单向数据绑定,例如v-bind绑定表单input的value值 ,单向指data中的值绑定到视图中,但视图中修改不会影响到data

  1. 双向数据绑定,v-model,通常用于输入类元素上例如表单的input,通常用于绑定input的value值。v-model默认收集的就是value值,所以v-model:value 可以简写为 v-model,新版vue已不支持v-model:value写法,直接写v-model即可

绑定属性修饰符

v-bind 还可以用于传值,此外给组件传值还有一个 sync 属性,例如 :money.sync="money" (冒号后面的跟引号里面的一定要一样),代表父组件给子组件传递 props:['money'],并且给子组件绑定一个自定义事件名叫(update:money),事件的回调是子组件 $emit('update:qian',huidiao) 里的第二个参数huidiao。


data(){
    return{ money:10000 }
}
//子组件内:
$emit('update:money',money-100)
props:['money']

利用属性修饰符sync可以实现子组件修改父组件传过来的props(修改props)

el与data的两种写法

el的两种写法

  1. new Vue时候配置el属性。
  2. 先创建Vue实例vm,随后再通过vm.$mount('#root')指定el的值。
    vue3里已不支持第一种写法,用的是第二种的改进版

data的两种写法

  1. 对象式
  2. 函数式
    学习阶段可以用第一种写法,但只要涉及到组件,data就必须使用函数式。

重要原则

由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this指向就不再是Vue实例

MVVM模型

model-view-viewmodel

  • vue2文档中说因为设计时受mvvm启发,所以vue实例通常用vm来命名。但vue3已移除这句话,用
    Counter。
  • vm:
const vm = new Vue()

data中的所有属性,最后都会出现在了vm身上,vm身上所有属性以及vue原型上的所有属性,再vue模板中都可以直接使用

Vue数据代理

回顾Object.defineProperty

参数一:给谁添加属性
参数二:添加属性的属性名
参数三:配置项,是一个对象,其中包括value。
此方法定义的属性默认是不可枚举/遍历的,可在配置项里修改enumerable:true开启遍历。
定于的属性默认是不可以被修改的,可在配置项修改 writable:true 开启修改
定义的属性默认是不可以被删除的,可在配置项修改 configurable:true 开启删除。
配置项get函数(getter)当有人读取参数二的属性时,getter就会被调用,且返回值就是这个属性的值
配置项set函数(setter)当有人修改参数二的属性时,setter就会被调用,且会收到给setter传参的值

let person = {
    name:'Ming',
    sex:'male'
}
let number = 18
Object.defineProperty(person,'age',{
    get(){return number}
    set(value){number = value//此时修改person的age就会修改number}
})

数据代理

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

vue中的数据代理

vm._data 里面的内容,就是配置对象里面的data,只不过内部做了一些数据劫持,使之可以实现响应式更新视图。内部的传值用的就是Object.defineProperty这个api

Vue事件处理

给元素绑定事件,用 v-on:***="***" 指令,或者简写形式 @***="***" 例如


然后再vue实例里面的 methods 里面写上方法就可以了,最终会在vm身上,想要获取事件对象只需要在写函数的时候传入一个参数

const Counter = {
    methods:{
        show(event){
            console.log(event)
        }
    }
}
Vue.createApp(Counter).mount('#app')

如果在给元素绑定事件的时候想要传入一个参数怎么办?想要传入一个参数并且获得事件对象,就需要一个$event做占位符,$event占位符和传的参数的位置没有要求,只需要在写函数的时候对应拿取就行



基本使用注意点:

  1. 使用 v-on:xxx 或 @xxx 可以绑定事件,其中xxx是事件名
  2. 事件的回调需要配置在methods对象中,vue会处理其绑到vm上
  3. methods中配置的函数,不要用箭头函数,否则this指向的就不是vm
  4. methos中配置的函数,都是被vue所管理的函数,this的指向是vm或组件实例对象
  5. @click="demo" 和 @click="demo($event)" 的效果一致,但后者可以传参

事件修饰符

点我跳转

像如上代码,如果想要a标签点击触发show事件,但不想进行a标签默认的跳转行为。可以使用 e.preventDeafault() 来阻止。
但是,vue里面有事件修饰符,用于在事件触发时候添加一些其他动作。
例如 prevent 修饰符,用法写在v-on指令后面用点接起来就可以。事件修饰符可以链式书写

点我跳转
vue时间修饰符 意义
prevent 阻止默认事件(常用)
stop 阻止事件冒泡(常用)
once 事件只触发一次(常用)
capture 使用事件的捕获模式
self 只有event.target是当前操作的元素时才触发事件
passive 事件的默认行为立即执行,无需等待事件回调执行完毕

键盘事件

在原生js里,通常用e.keycode判断哪个键按下了。
vue里可以给使事件后面添加别名后缀方式使用。例如 @keyup.enter

vue常用案件别名 按键
回车 enter
删除 delete(删除和退格同时捕获)
退出 esc
空格 space
换行 tab(特殊:必须配合keydown使用)
up
down
left
right
  • vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-cace短横线命名法。例如 @keydown.caps-lock

  • 类似tab的系统用法特殊的修饰键:ctrl、alt、shift、meta

    1. 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。可以链式书写 @keyup.ctrl.y
    2. 配合keydown使用:正常出发事件
  • 也可以使用keycode去指定具体的按键(mdn文档提示未来可能弃用)

  • Vue.config.keyCodes.自定义按键名 = 键码,可以去定制按键

Vue计算属性 computed

computed里面写的属性的值基本上都是一个对象。通常称为计算属性。
计算属性里面通常写get()和set()属性,类似Object.defineProperty()一样使用

const Counter = {
    data() {
        return {
            firstName: '张',
            lastName: '三'
        }
    },
    computed: {
        fullName: {
            get() {
                return this.firstName + this.lastName
            }
        }
    }
}
app = Vue.createApp(Counter).mount('#app')
  • get什么时候调用?
    1. 初次读取该值时
    2. 所依赖的数据发生变化时
  • set什么时候调用?
    当该值被修改时

计算属性小结

  1. 定义:要用的属性不存在,当可以通过已有属性计算得来
  2. 原理:底层借助了Object.defineProperty()的getter和setter
  3. 优势:与methods实现相比,内部有缓存机制,效率更高,调试方便
  4. 备注:计算属性最终会出现在vm上,直接读取使用即可。
    如果计算属性要被修改,那必须写set函数去相应修改,且set中要引起所依赖的数据改动。例如上面的案例
    computed: {
        fullName: {
            get() {
                return this.firstName + this.lastName
            }
            set(value){
                let v = value
                this.firstName = v[0]
                this.lastName = v[1]
            }
        }
    }

计算属性简写

通常,用到计算属性基本上是只用到getter的,如果只用到getter,那么可以使用简写形式

    computed: {
        fullName() {
                return this.firstName + this.lastName
            }
        }
    }

虽然看起来像个方法,但他实际上是个属性,使用的时候不要使用调用符号。
至此,我们学到的vue上的东西有:data数据、methods方法、computed计算属性。数据和计算属性都是直接读即可读到

监视属性变化watch

  • 配置属性watch可以监视vue实例里一个值的变化,可以是普通data值,也可以是计算属性值。监听的值发生变化就执行handler。
  • watch的属性作为键,值是一个对象形式的配置对象,里面有基础配置属性handler函数,该函数自动接收两个参数,一个是新值一个是旧值。
  • handler什么时候调用?当监视的那个键的值发生变化的时候
const Counter = {
    data() {
        return {
            isHot:true
        }
    },
    watch:{
        isHot:{
            handler(newValue,oldValue){
                console.log('isHot被修改了')
            }
        }
    }
}
app = Vue.createApp(Counter).mount('#app')
  • 还有其他配置项,immediate:false,该配置项用于是否开启 初始化时让handler调用一下。
  • 监视的属性必须存在才能被监视
  • 监视的两种写法:
    1. 创建vue实例时候传入watch配置
    2. 通过vue实例的watch('isHot',{})` ,参数一是监视那个值,参数2是配置项

深度监视

监视多级结构中所有属性的变化,使用配置项 deep:true

  • vue中的watch默认不监测对象内部值的改变(一层)(当监测的值是对象时)
  • 配置 deep:true 可以监测对象内部值改变(多层)(当监测的值是对象时)
    其他知识点:
    1. vue自身可以监测到对象内部值的改变,但vue提供的watch默认不可以
    2. 使用watch时根据数据的具体结构,来决定是否开启deep配置项。像上面提到的当监测的值是对象时

监视的简写

当不需要其他配置项只需要handler函数的时候,可以使用简写

const Counter = {
    data() {
        return {
            isHot:true
        }
    },
    watch:{
        isHot(newValue,oldValue){
                console.log('isHot被修改了')
        }
    }
}
app = Vue.createApp(Counter).mount('#app')

watch和computed区别

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

绑定class样式

  1. 字符串写法:适用于:样式的类名不确定,需要动态指定
  1. 数组写法,适用于:要绑定的样式个数不确定、名字也不确定。因为可以使用数组的方法删除或添加
  1. 对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用

绑定style样式

注意:使用style绑定样式,key值要用小驼峰写法

  1. 对象写法
  1. 数组写法
    :style="[a,b]"其中a、b是样式对象

scoped样式

多个组件写style样式,如果不携带scoped属性,那么会全部由app.vue组合到一起,如果命名冲突后面的就会覆盖前面的


作用:让样式只在局部组件中生效,防止冲突。一般不会在app组件使用

条件渲染 v-show和v-if

v-show的原理是display:none,接的值是一个布尔值,也可以是一个表达式。v-show="3===1"
v-if的原理是把整个元素节点移除掉,dom节点资源开销币v-show大
v-else-if的原理与普通if else一样,v-if判断成功后,v-else-if就不判断了
v-else就是v-if和v-else-if都不成立的时候,v-else就生效
v-else和v-if和v-else-if需要成组使用,也就是使用这三个命令的节点需要连在一起,否则只有v-if生效,然后后续的报错
其他知识点:template标签和v-if搭配使用,template元素在渲染的时候会脱掉这个标签

循环渲染/列表渲染 v-for

类似原生的 for-in 循环,可用于遍历可迭代对象和对象,还可以遍历指定次数。
语法:v-for="(item,index) in xxx" :key="yyy",当只需要遍历值不需要索引的时候可以只写一个参数

  • //v-for循环对象时有三个参数,item,key和index

key有什么作用

  1. 虚拟DOM中key的作用
    key是虚拟DOM对象的标识!!!当数据发生变化时,Vur会根据新数据生成新的虚拟DOM!!!
    随后Vue进行新虚拟DOM与旧虚拟DOM的差异比较,也就是根据diff算法去进行页面渲染。
  2. 如果不写key,则Vue默认根据index来对key进行赋值。如果用index作为key会引发一下问题
    1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新,影响效率
    2. 如果结构中还包含输入类DOM,会产生错误DOM更新进而影响界面。
  3. 所以,开发中使用每条数据的唯一标识作为key,如id、手机号、身份证号等唯一值。

Vue2监测数据改变的原理

Vue.set() 和 vm.set() 用于修改堆数据(数组、对象等)里的数据 参数一:要修改(添加)进的目标 参数二:要修改的属性key 参数三:要修改的值value 除了set 还有 $delete,参数是一样的

原理总结:

  1. vue会监视data中所有层次的数据
  2. 如何监测对象中的数据?通过setter实现监视,且要在new Vue时旧传入要监测的数据。
    1. 对象中后追加的属性,Vue默认不做响应式处理
    2. 如需给后添加的属性做响应式,请使用如下API: Vue.set(TARGET,PropertyName/INDEX,VALUE)vm.$set(TARGET,PropertyName/INDEX,VALUE)
  3. 如何监测数组中的数据?
    1. 通过包裹数组更新元素的方法(vue重写的常用原生数组方法):push、pop、shift、unshift、splice、sort、reverse。本质是调用原生对应的方法对数组进行更新后重新解析模板,调用reactiveSetter等进行界面更新。
    2. 使用 Vue.set(TARGET,PropertyName/INDEX,VALUE)vm.$set(TARGET,PropertyName/INDEX,VALUE)
  4. 特别注意:Vue3已移除那两个api,Vue.set() 和 vm.$set() 不能给 vm 或 vm 的根数据对象添加属性

收集表单数据

vue页面收集表单数据,通常使用v-model指令,以及给form表单用v-on绑定事件并阻止默认跳转提交

  1. ,则v-model手机的是value值,用户输入的就是value值
  2. ,则v-model收集的是value值,且要给标签配置value属性
    1. 没有配置input的value属性,那么收集的就是checked的布尔值
    2. 配置input的value属性:
      • v-model的初始值是非数组,那么收集的就是checked的布尔值(不推荐这样用)
      • v-model的初始值是数组,那么收集的就是value组成的数组

v-model的三个修饰符

修饰符 作用
number 输入字符串转为有效的数字
lazy 失去焦点再收集数据
trim 输入首尾空格过滤

Vue2过滤器filters

现在的时间是:{{time | timeFomater}}

现在的时间是:{{time | timeFomater()}}

  • vue会把,需要过滤器处理的那个参数,当作函数的参数传入过滤器函数里。
  • 如果像第二个h1那样写,传入小括号的第一个参数依然是需要过滤器处理的那个参数,第二个则是自定义传的参数.
  • filters过滤器可以进行多层过滤

    现在的时间是:{{time | timeFomater() | myslice}}

  • 过滤器可以搭配v-bind使用,但不能搭配v-model 现在的时间是:

全局过滤器 Vue.filter

Vue.filter('mySlice',function(value){return value.slice(0,4)})

Vue其他内置指令

整理之前学的指令

指令 说明
v-bind 单项绑定解析表达式,可简写为 :xxx
v-model 双向数据绑定
v-for 遍历数组、对象、字符串
v-on 绑定事件监听,可简写为@xxx
v-show 条件渲染是否展示
v-if v-else-if v-else 条件渲染

v-text

类似innerText,v-text里的内容会覆盖标签内所有内容,且不会编译里面的标签括号

v-html

类似innerHtml,可以解析结构。所以v-html对比v-text有安全性问题。一定要在可信的内容上使用v-html,永远不要在用户提交的内容上使用

v-cloak

v-cloak指令没有值。

  1. 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉元素上的v-cloak属性。
  2. 使用css的display:none 可以解决网速慢时展示出 {{xxx}} 的问题
{{name}}

v-once

v-once指令没有值。事件修饰符也有个once别搞混了,用法不一样

  1. 使用该指令的元素内容,只会进行初次传值渲染。v-once所在节点在初次动态渲染后,就视为静态内容了。
  2. 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。

v-pre

  1. 跳过其所在节点的vue编译过程
  2. 可利用他跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译

自定义指令 directives

  • vue里使用directives来自定义指令,指令是写成一个函数形式或对象形式。
  • 每个函数接收两个参数,参数一:该指令绑定的对象;参数二:该指令书写时后面引号接的东西(信息对象),通常用他的value

当前值是{{num}}

  • 书写的函数型指令何时会被执行?
  1. 指令与元素成功绑定时(一上来)
  2. 指令所在的模板被重新解析时。(例如使用到的data里的值被修改了)

对象形式自定义指令

  • 函数形式是简写形式,实际上对象形式才是自定义指令的本体。
  • 其中包括三个阶段:bind、inserted、update。这三个东西被称为自定义指令的配置。
  • bind是指令与元素成功绑定时。inserted是所在元素被插入页面时。update是指令所在的模板被重新解析时。参数都是element和binding。有很多操作时只有在inserted之后才有效的,这点要记住
directives: {
    fbind: {
        bind(element,binding){
            
        },
        inserted(element,binding){
            element.focus()
        },
        update(element,binding){
        
        }
    }
}

自定义指令注意点

  1. 指令定义时不加v-,但使用时要加 v-
  2. 指令名不能使用驼峰命名法,vue会默认全部转成小写。真要多个单词写用斜杠接起来。例如 v-focus-bind。在写指令的时候指令对象名用引号包起来。'v-focus-bind'(element,binding){}
  3. 全局指令书写形式 Vue.directive(指令名,配置对象)Vue.directive(指令名,回调函数)

Vue生命周期

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

完整生命周期,8个(4对)

  1. beforeCreate
  2. created
  3. beforeMount
  4. mounted(常用;发送ajax请求,启动定时器,绑定自定义事件,订阅消息等初始化操作)
  5. beforeUpdate
  6. updated
  7. beforeDestroy(常用;清除定时器,解绑自定义事件,取消订阅等收尾工作)
  8. destroyed

[图片上传失败...(image-db9fe8-1660811061785)]

Vue2组件


    
  • 使用组件三大步骤1.创建/定义组件、2.注册组件、3.使用组件(写组件标签)
  • 如何定义一个组件?
    使用Vue.extend(OPTIONS)创建,其中OPTIONS和new Vue(OPTIONS)时传入那个配置对象几乎一样。但区别如下
    1. el不要写,因为最终所有的组件都要经过一个vm管理,由vm中的el决定服务那个容器
    2. data必须写成函数,避免组件复用时候,多个组件互相篡改数据
  • 如何注册组件?
    1. 局部注册:靠 new Vue 时候写的 components 配置项
    2. 全局注册: 靠 Vue.components('组件名',组件)
  • 组件书写结构时候用 template 项来写,template里面必须要有且只有一个父标签
  • 使用组件:

关于组件的注意点

  1. 关于组件名:
    1. 一个单词组成:
      • 第一种写法(首字母小写):zujian
      • 第二种写法(首字母大写):Zujian
    2. 多个单词组成:
      • 第一种写法(kebab-case命名):my-school
      • 第二种写法(CamelCase命名):MySchool(需要Vue脚手架支持)
    3. 备注:
      • 组件名要回避HTML已有的元素标签名
      • 可以使用name配置项指定组件在开发者工具中显示的名字
  2. 关于组件标签:
    • 第一种写法:
    • 第二种写法:
    • 备注:不使用脚手架时,第二种写法会导致后续组件不能渲染
  3. 一个简写方式:
    const zujian = Vue.extend(OPTIONS) 可简写为 const zujian = OPTIONS

关于VueComponent

  1. Vue组件本质是一个名为VueComponent的构造函数,是由Vue.extend生成的
  2. 我们在使用组件的时候(写上组件标签时)Vue解析时会帮我们创建组件的实例对象(即执行new VueComponent)
  3. new调用构造函数,每次调用返回的都是一个全新的VueComponent
  4. 关于组件的this指向
    1. 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数,他们的this均是vc
    2. new Vue中的data函数、methods中的函数、watch中的函数、computed中的函数,他们的this均是vm,注意区别

vue组件与vue的重要关系

Vue组件实例.prototype.__proto__ === Vue.prototype
为什么要有这个关系:让组件实例对象可以访问到Vue原型上的属性和方法

Vue脚手架

安装

npm i -g @vue/cli
# OR
yarn global add @vue/cli

创建一个项目:

vue create my-project
# OR
vue ui

脚手架文件结构:

|-- undefined
    |-- .gitignore:git忽略文件配置
    |-- babel.config.js:babel配置文件
    |-- jsconfig.json
    |-- package-lock.json:包版本控制文件
    |-- package.json:应用包配置文件
    |-- README.md:应用描述文件
    |-- vue.config.js:vue配置文件
    |-- dist:打包后文件
    |-- public:静态资源文件夹,webpack会原封不动的打包文件
    |   |-- favicon.ico:页标签图标
    |   |-- index.html:主页面
    |-- src
        |-- App.vue:汇总所有组件
        |-- main.js:入口文件
        |-- assets:静态资源文件夹,webpack会模块化打包
        |   |-- logo.png
        |-- components:组件文件夹
            |-- HelloWorld.vue

关于不同版本的Vue

  • vue.js 与 vue.runtime.xxx.js 的区别
    1. vue.js 是完整版的vue,包含核心功能和模板解析器
    2. vue.runtime.xxx.js 是运行版的vue,只包含核心功能,没有模板解析器,所以需要render函数
  • 因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容。

vue.config.js配置文件

  • 使用 vue inspect > output.js 可以查看到vue脚手架的默认配置
  • 使用 vue.config.js 可以对脚手架进行个性化定制
  • 新手通常把eslint关闭 lintOnSave:false

ref属性

  1. 被用来给元素或子组件注册引用信息(id的替代者),然后用 this.$refs.*** 获取


  1. 应用在html标签上获取的是真实DOM元素,应用在逐渐标签上是组件实例对象(vc)
  2. 使用方式:
    • 打标识:

    • 获取:this.$refs.xxx

组件传值接值 和 props配置项

传值

  • 方式:在使用组件的时候携带标签属性,为一个个名值对形式

  • 用props接收过来的值会在组件的vc身上存着,在开发者工具里的props可以看到

props配置项

  • 功能:让组件接收外部传过来的数据,默认类型是string类型,如要修改例如可用v-bind改为number。
  1. 方式一:数组形式(简写形式),顺序不重要,对上号就行

  1. 方式二:接收时只对数据进行类型限制

  1. 方式三:接收时对每个数据进行严格设置,可以配置type、default、required。通常default、required不会同时使用,逻辑问题

props注意点

  1. vue不允许修改props接收过来的值,否则发出警告。如要修改,先把props的值存在data之后再修改


  1. 如果使用的组件上的data有与props同名的,优先使用props的,即父组件传过来的那个值。
  2. 传值时候不要使用vue预留的指令当作传值的名
  3. 数组方式传入的时候注意变量要用引号包起来

mixin混入

new Vue({
    mixin:[xxx,xxx]
})
  • 功能:可以把多个组件公用的配置提取成一个混入对象,提取的文件是一个js格式的文件
  1. 第一步:定义混合,写一个js文件,然后里面写入配置项
const hun1 = {
    data(){...},
    methods:{...}
    ...
}
  1. 第二步,使用局部混入或全局混入。局部混入写在局部组件的vue配置项里
new Vue({
    mixins:[xxx,xxx]
})

全局混入一般写在main.js里

Vue.mixin(xxx)
  1. 注意点:混入项和组件自带项冲突时,数据以组件自带的data为准。如果两者都有生命周期钩子,则先执行混入项的生命周期钩子。

vue插件

vue插件是一个包含install方法的一个对象,install的第一个参数是Vue构造函数,第二个第三个第n个是插件使用者传递的数据。
定义完Vue插件之后在main.js使用 Vue.use(插件) 即可。

//定义一个plugins.js

export default{
    install(Vue){
        Vue.directive(...)
        Vue.mixin({...})
        Vue.prototype.hello=...
    }
}

在main.js里使用

import plg1 from './plugins.js'
Vue.use(plg1)

给组件触发自定义事件 this.$emit

this.$emit(eventName,params) 触发自定义事件的两个参数,参数1是触发的事件名,参数2是传过去的参数。
this.$on('eventName',params)或者v-on:eventName="fn" fn(params) 类似这样接收参数


methods:{
    demo(value){console.log("demo被调用了,得到的值是"+value)}
}

以上案例,在使用组件的时候,绑定了一个自定义事件“zidingyi”,接下来,去那个组件里面使用this.$emit('zidingyi',this.name)触发该事件,就可以在子组件把数据传输给父组件。



这个时候在页面使用button就会在控制台输出 demo被调用了,得到的值是家里蹲大学

通过ref给组件绑定自定义事件


methods:{
    demo(value){console.log("demo被调用了,得到的值是"+value)}
}
mounted(){
    this.$refs.student.$on('zidingyi',this.demo)
}

通过ref给逐渐绑定自定义事件灵活性更高,可以在异步给组件绑定自定义事件

this.$off() 解绑自定义事件



  • this.$off()可以传递一个字符串为参数,如果需要解绑多个自定义事件,则需要写成一个数组形式 this.$off(["zidingyi","chufa"])
  • 如果 this.$off() 不传递任何参数,则解绑该组件身上所有的自定义事件
  • 如果组件进行了destroyed 生命周期,那么身上绑定的自定义事件也会解绑,这是生命周期自身的特性

自定义事件总结

  • 作用:子组件给父组件传内容,使用场景:子组件给父组件传数据,在父组件中给B绑定自定义事件。
  • 通过this.$refs.xxx.$on('atguigu',回调) 绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向的是绑定者。
  • 组件上也可以绑定原生DOM事件,需要使用native修饰符,本质是给组件的根标签绑定原生DOM事件,点任何子标签都会冒泡到根标签。
  • 给原生DOM绑定自定义事件是没有意义的,因为没有办法触发emit('zidingyi',参数)"

全局事件总线(GlobalEventBus)

是一种组件间通信的方式,适用于任意组件间通信

安装全局事件总线

在创建vue实例的时候在beforeCreate钩子里面给vue原型挂上on$off等方法

new Vue({
    ......
    beforeCreate(){
        Vue.prototype.$bus = this
    },
    ......
})

使用事件总线

谁需要数据的,就先往谁身上先写一个方法,然后把这个方法,挂在一个自定义事件上

methods(){
    reqData(data){
        //data为事件触发者传过来的参数
    }
}
mounted(){
    this.$bus.$on('xxxreqData',this.reqData)
}

谁发送数据的,就在这个组件通过这个自定义事件把数据发送过去

this.$bus.$emit('xxxreqData',DATA)

就是根据这个挂在$bus上的自定义事件来实现通信

消息订阅与发布,pubsub-js库

也是一种组件间同行的方式,可以适用于任意组件间通信。

使用方法

  1. 安装pubsubjs npm i pubsub-js
  2. 在使用的组件里面引入pubsub import pubsub from 'pubsub-js'
  3. 使用pubsub的api subscribe 去订阅一个自定义消息名的消息,第一个参数是消息名,第二个参数是这个消息里的数据。注意这个api里面的this是undefined。并且注意,作为subscribe的回调的形参一默认是消息名字,形参二后面的才是传输的数据。
mounted(){
    this.pid = pubsub.subscribe('MSGNAME',(MSGNAME,data)=>{data...})
}
  1. 在提供数据的组件使用 publish 这个api去发布消息,第一个参数是自定义消息名,第二个参数是数据。
pubsub.publish('MSGNAME',data)
  1. 最好在beforeDestroy钩子中使用 unsubscribe(pid) 这个api去取消订阅,参数是使用订阅时声明的id变量
pubsub.unsubscribe(pid)

$nextTick

this.$nextTick(回调函数)
this.$nextTick(()=>{
    //...更新dom后要进行的操作
})
  • 作用:在这一轮DOM更新结束后的时刻执行参数里面的回调函数
  • 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
    nextTick,在Vue里,我们在更新数据之后,DOM会在这一轮宏任务之后微任务里进行更新,倘若这一次宏任务中进行了一些读取DOM的操作,则会发现读取的是宏任务后的DOM信息,因为还没到vue更新DOM的微任务。如果想要在更新DOM的微任务以后对DOM进行一些操作,则把这些操作写在$nextTick的回调函数里面

Vue与CSS3

Vue动画

CSS3的keyframe动画,搭配Vue的 标签,以及v-enter-activev-leave-active 类名




Vue过渡

实际上vue给一套transition标签内置了六个class,分别是以下六个,如果只是动画,只使用active那两个就可以了

.v-enter .v-enter-active .v-enter-to .v-leave .v-leave-active .v-leave-to



transition-group 多个过渡、动画标签

一个transition标签里面只能套一个子元素,让一个子元素给vue自动形成六个标签。如果需要套多个子元素,则需要用到,注意,如果使用transition-group,那么每一个子元素都要给key值


      

你好啊

我不好

transition和transition-group标签上的属性

属性名 功能
name="xxx" 自动生成动画的类名的前缀,第三方动画库也会用到
appear 一开始就执行一次动画
enter-active-class 第三方动画库用到
leave-active-class 第三方动画库用到

Vue配置代理devServer.proxy 解决跨域

module.exports = defineConfig({
  devServer: {
    proxy: 'http://192.168.1.10:5000'
  }
})

在vue.config.js文件中写入以上内容即可实现简单代理解决跨域问题,请求的时候请求本机地址即可。
但如果本地public资源有同名请求则冲突。且只能配置一台代理

module.exports = defineConfig({
  devServer: {
    proxy: {
        ''/student': {
            target: 'http://192.168.1.10:5000',
            pathRewrite: { '^/student': '' },
        },
        '/car': {
            target: 'http://192.168.1.10:5001',
            pathRewrite: { '^/car': '' },
        },
    }
  }
})

以上方式可以开启多个代理服务器,proxy写成一个对象形式,里面的值也写成一个对象的形式。
对象的键名是路由,为该代理请求的后缀,如果不写pathRewrite配置项,请求资源时也会带上此路由。
ws:true 用于支持websocket,changeOrigin:true 用于控制请求头中的host值,这两如果不写,默认值也是true

slot插槽

默认插槽 slot标签

在组件里面使用slot标签进行插槽占位


在使用组件的地方在双组件标签里面写上其他内容,那么这些内容就会使用插槽占的位置,比如这个例子,img标签就会使用slot的位置


      

具名插槽 带有name属性的slot标签

在组件里面使用slot标签进行插槽占位,并带上name属性


在vue2里用带有slot属性的标签即可为插槽传入内容(已弃用),请使用 v-slot,但注意,v-slot只能用在template标签上,这点与slot不一样,只有一种特殊情况就是只使用默认插槽,就可以把v-slot直接用在组件上

...旧写法已弃用