VUE学习笔记

一、Vue核心

模板语法

插值语法(用于解析标签体内容)

{{name}}

里面可以写数据或者JavaScript代码

指令语法(用于解析标签)

Vue有很多指令,v-xxx的形式

单向绑定

//可以给仍和标签里的属性做绑定通过vue改变属性值简写为:
v-bind: ==> :
<a v-bind:href="url"></a>

双向绑定

//双向绑定可以标签改data里的数据,只能用于输入标签上,有value值
v-model:value='name'
//简写
v-model="name"

data和el的两种写法

el的两种写法

const v = new Vue({
			el:"#root",  //el指定当前vue为哪个容器去服务
			data:{		//用于存储数据,供el指定的容器去使用
				name:"hello",
			}
		})
//或者
const v = new Vue({
			data:{		//用于存储数据,供el指定的容器去使用
				name:"hello",
			}
		})
v.$mount('#root')  	//更灵活$mount挂载

data的两种写法

new Vue({
			el:"#root",  //el指定当前vue为哪个容器去服务
			data:{		//用于存储数据,供el指定的容器去使用
				name:"hello",
			}
		})
//第二种,不能写箭头函数
new Vue({
			el:"#root",  //el指定当前vue为哪个容器去服务
			data:function(){
                return{
                    name:'hello'
                }
            }
		})
//等于
new Vue({
			el:"#root",  //el指定当前vue为哪个容器去服务
			data(){
                return{
                    name:'hello'
                }
            }
		})

MVVM模型

M:模型(Model)=>数据(data)

V:视图(View)=>模板

VM:视图模型(View Model)=>Vue实例对象

数据代理(data)

Object.defineProperty方法

		let number = 19
		let person = {
			name: "张三",
			sex: "男",
			// age:19
		}
		Object.defineProperty(person, "age", {
			// value:19,
			// enumerable:true, //控制属性是否可以遍历,默认值false
			// writable:true, 	//控制属性是否可以被修改,默认值false
			// configurable:true //控制属性是否可以被删除,默认值false
			//当有人读取了person的age属性时,get函数(getter)就会被调用,返回值就设置为age的值
			get() {
				console.log('读取了age属性')
				return number
			},
			//当有人修改了person的age属性时,set函数(setter)就会被调用,且会收到修改的值
			set(v) {
				console.log('有人修改了age的值为',v)
				number = v
			}
		})

Vue数据代理

事件处理(methods)

点击事件

v-on:click="clisk1" //当点击这个标签的时候调用Vue实例里面的clisk1函数
@click="click2"		//简写
new Vue(
	el:"#root",
    data:{
    	app:"iphon"
    },
    methods:{
        click1(event){	//返回的是标签对象
            alert('点到我了')
        }
    }
)
//传递自定义参数
@click="click2(666,$event)"		//括号里面的是要传递到Vue函数里面的,单独传递一个666会让原本的标签对象丢失,所以用$event占位
new Vue(
	el:"#root",
    data:{
    	app:"iphon"
    },
    methods:{
        click1(shuzi,event){	//返回的是标签对象
            alert('点到我了')
        }
    }
)

事件修饰符

prevent:阻止默认事件
stop:阻止事件冒泡
once:事件只触发一次
capture:使用事件的捕获模式
self:只有event.target是当前操作的元素时才触发事件
passive:事件的默认行为立即执行,不用等待函数执行完成才执行默认事件
//能连着写.self.once
@click.prevent="click1"	//阻止默认事件(跳转页面)
@click.stop="click2"	//会出现两次alert弹窗,阻止冒泡只出现一次
<div @click="click2">
    <button @click.stop="click2">点我</button>
</div>
//只会触发一次,只能点击一次
@click.once="click2"
//事件捕获->冒泡,点击了就执行,不等待事件捕获
<div @click.capture="click2">
    <button @click="click2">点我</button>
</div>
//对象是当前标签时才触发
<div @click.self="click2">
    <button @click="click2">点我</button>
</div>

//滚动事件
<div @scroll="函数"> </div>	//scroll给滚动条添加的事件,wheel给鼠标滚轮添加事件

键盘事件

<!--keyup按下然后放开时触发函数,keydown相反
特殊(系统修饰键):ctrl\alt\shift\meat
	配合keyup:按下这个键再按其它键然后释放才被触发(组合键)ctrl.y=>ctrl+y
	配合keydown:正常触发
回车》enter
删除and退格》delete
退出》esc
空格》space
换行》tab
上》up
下》down
左》left
右》right
-->
<input type="text" placeholder="按下回车提示" @keyup.enter="demo">

计算属性

data里面的是属性里的

computed里面是计算属性

new Vue({
        el:"root",
        data:{
            a:1,
            b:2
        },
        computed:{
            //只要有人读取了fullName时,get就会被调用,且返回值就作为fullName的值,html里调用直接插值语法{{fullName}}
            //get调用的时候:1,初次读取的时候    2依赖的数据发生改变的时候
            fullName:{
                get(){
                    return this.a+this.b
                },
                //set调用时:当fullName被调用时
                set(){}
            },
            //简写:不考虑修改时使用
            fullname:function (){
                return this.a+this.b
            }
        }
    })

监视属性

const x = new Vue({
        el:"root",
        data:{
            a:true
        },
        watch:{
            	a:{
                    immediate:true,//初始化时就调用一下
                	//当a发生改变时调用,new是新值,old是旧值
               	 	handler(new,old){
                        console.log(new,old)
                    }   
                }
            }
        }
    })
//写法二
x.$watch('a',{
    handler(new,old){
           console.log(new,old)
    } 
})

深度监视

Vue里的watch默认监测少对象内部值的改变(单层)

配置deep:true可以监测对象内部值的改变(多层)

备注:

​ Vue自身可以检测到对象内部值的改变,单Vue提供的watch默认不可以

//监视多级结构的某个属性变化
const x = new Vue({
        el:"root",
        data:{
            a:true,
            b:{
            	s:1,
                k=2
        	}
        },
        watch:{
            	'b.s':{
               	 	handler(new,old){
                        console.log(new,old)
                    }   
                }
            }
        }
    })
//监视多级结构里的所有属性的改变
const x = new Vue({
        el:"root",
        data:{
            a:true,
            b:{
                s:1
            }
        },
        watch:{
            b:{
                deep:true,	//深度监视
                handler(newshu,old){console.log(newshu,old)
                }
            }
        }
    })

监视属性简写

不能配置深度监视等配置项

const x = new Vue({
        el:"root",
        data:{
            a:true,
            b:{
                s:1
            }
        },
        watch:{
            b(newshu,oldshu){console.log(newshu,oldshu)}
            }
    })

//
x.$watch('b',function(newshu,oldshu){console.log(newshu,oldshu)})

computed和watch之间的区别

1.computed能完成的功能,watch都可以完成

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

绑定样式

css

字符串写法绑定样式
<div class="a" :class="func" @click="mycss"></div>
数组写法
<div class="a" :class="["a","b","c"]" @click="mycss"></div>
对象写法
<div class="a" :class="c" @click="mycss"></div>
<script type="text/javascript">
    const x = new Vue({
        el:"#root",
        data:{
            a:"云海",
            b:['b','c'],
            c:{
                b:false,
                c:false
            }
        },
        methods:{
            mycss(){
                this.b = "c"
            }
        }
    })
</script>

style

<div id="root" :style="b" @click="mycss">{{a}}</div>

</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script type="text/javascript">
    const x = new Vue({
        el:"#root",
        data:{
            a:"云海",
            b:{
                //样式是两个单词组成的时候之间的-去掉,除了第一个单词其他的单词首字母大写
                fontSize:"40px",
            },
        },
        methods:{
            mycss(){
                this.b = "c"
            }
        }
    })
</script>

<div id="root" :style="[{color:red},{xxx:xxx}]" @click="mycss">{{a}}</div>

条件渲染

v-show="true" <!--显示隐藏变化频率高-->
v-if = "1 === 1" <!--强力显示隐藏变化频率不高-->
v-else-if = "n==3"
<!--中间不能打断-->
    <div v-if="b">{{a}}</div>
    <div v-else-if="b">{{a}}</div>
    <div v-else-if="b">{{a}}</div>
    <div v-else>{{a}}</div>

列表渲染

基本列表

遍历数组

<div id="root">
    <ul>
<!--        用到v-for就要设置唯一值:key,index是索引-->
        <li v-for="(b,index) in a" :key="b.id">{{b.id}}--{{b.name}}</li>
    </ul>
</div>


</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script type="text/javascript">
    const x = new Vue({
        el:"#root",
        data:{
            a:[{id:1,name:'ajax'},{id:2,name:'atm'},{id:3,name:'data'}]
        },

    })
</script>

遍历对象

当作python里的遍历字典就好了,可以获取到两个值key,value 键,值

遍历字符串

类似列表,第一个值是字符,另一个是索引

遍历指定次数

遍历5次1,2,3,4,5 ,index是索引
<li v-for="(b,index) in 5" :key="b.id">{{b}}--{{index}}</li>

key的原理

虚拟DOM中key的作用

​ key是虚拟DOM对象的标识,当数据发生变化时Vue会根据【新数据】生成【新的虚拟DOM】,随后镜像新旧DOM的对比

对比规则

​ 1、旧的虚拟DOM中找到新的虚拟DOM相同的key:

​ 如果虚拟DOM中的内容没变,之久使用之前的真实DOM

​ 如果虚拟DOM中的内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM

​ 2、旧的虚拟DOM中未找到于新的虚拟DOM相同的key:

​ 创建新的真实DOM,随后渲染到页面

Vue检测数据的原理

//data里的对象添加数据,不能在实例化对象和data身上加
Vue.set(vm.a,'sex','男')	//加到实例上key=sex ,value=男
this.$set(vm.a,'sex','男')

this.$delete(vm.a,'sex')//删除vm.a上的sex
//根据索引修改数组值
this.vm.a.splice(0,1,'逛街')

收集表单

<input type="text"/>

​ 收集到的就是用户输入的value值

<input type="radio"/>

​ 收集到的就是value值,但是要提前设置value值

<input type="checked"/>

​ 没有配置value值搜集到的就是checked(勾选or未勾选,是布尔值)

​ 配置input的value属性值:

​ v-model的初始值是非数组,那么搜集到的就是checked

​ v-model的初始值是数组,那么搜集到的就是value组成的数组

v-model的修饰词

v-model.number		//输入的值转为数字 配合type="number"使用
v-model.lazy		//失去焦点的一瞬间提交数据
v-model.trim		//去除前后的空格,中间的空格去不了

过滤器(filters)

time的值传递给getTime 可以多次{{time | getTime | postTime}}

<div id="root">
    <h2>{{time | getTime}}</h2>
</div>


</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.3/dayjs.min.js"></script>
<script type="text/javascript">
    const x = new Vue({
        el:"#root",
        data:{
            time:Date.now()
        },
        filters:{
            //局部过滤器
            getTime(value,str='YYYY年MM月DD日 HH:mm:ss') {
                return  dayjs(value).format(str)
            }
        }

    })
</script>

全局过滤器

Vue.filter("getTime",function(value){})

内置指令

v-bind	//单向绑定	:
v-model	//双向绑定
v-for	//遍历
v-on	//绑定事件	@	@blur失去焦点时触发
v-if
v-else-if
v-else
v-show	
v-text	//向标签替换text,不可以解析html语句
v-html	//向标签替换text,可以解析html语句
v-cloak	//无值,当Vue.js请求堵塞的时候(网速慢的时候),标签有v-colak当Vue介入v-cloak就被删除,[v-cloak]{}标签里含有v-cloak的所有标签,用来设置样式
v-once	//没有值,在第一次渲染的时候就变成静态的内容了
v-pre	//无值,vue不去解析的地方,用它来跳过不需要插值的地方,后面就不解析了

自定义指令(directives)

自定义的时候big用的时候v-big

element是真实DOM(标签)binding(绑定的信息)

简易写法

new Vue = ({
    el:"#root",
    data:{},
    directives:{
        //big函数什么时候会被调用,1绑定成功的时候 2、指令所在的模板被重新解析时
        big(element,binding){
            
        }
    }
    
})

完整写法

指令名多个单词时用v-xxx-yy,自定义的时候写’xxx-yy’,自定义的this都是windows

new Vue = ({
    el:"#root",
    data:{},
    directives:{
        big:{
            //绑定的时候调用(一上来就用)
            bind(element,binding){},
            //指令所在元素被插入页面时调用
            inserted(element,binding){},
    		//指令所在模板被重新解析时调用
    		update(element,binding){}
        }
            
        }
})

全局指令

Vue.directive("big",{
            //绑定的时候调用(一上来就用)
            bind(element,binding){},
            //指令所在元素被插入页面时调用
            inserted(element,binding){},
    		//指令所在模板被重新解析时调用
    		update(element,binding){}
        })

生命周期

生命周期:

​ 又叫:生命周期回调函数、生命周期函数、生命周期钩子

​ 是生命:Vue在关键时刻帮我们调用的一些特殊名称的函数

​ 生命周期函数的名字不可更改,单函数的具体内容是我们根据需求编写的

​ 生命周期函数中的this指向的是vm 或 组件实例对象

渲染结束调用 (moubted)

const x = new Vue({
    el:"#root",
    data:{
        time:Date.now()
    },
    //挂载完毕时调用只调用一次
    mounted(){
        
    }

})

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I0gCmZqT-1673171032560)(./img/image-20220713220020832.png)]

Vue的一生:

!是重要的函数

将要创建 调用brforeCreate函数

创建完毕 调用created函数

挂载完毕!调用mounted函数

将要更新 调用beforeUpdate函数

更新完毕 调用uodated函数

将要销毁!调用beforeDestroy函数

销毁完毕 调用destroyed函数

二、组件化编程

模块与组件、模块化与组件化编程

模块

​ 一个js文件就是一个模块

组件

​ 用来实现局部(特定)功能效果的代码集合(html/css/js/img/…)

模块化

​ 当应用中的js都以模块来编写,那么这个应用就是一个模块化应用

组件化

​ 当应用中的功能都是多组件的方式来编写的,那么,这个应用就是一个组件化的应用

非单文件组件

​ 一个文件中包含n个组件

基本使用

组件名

单个单词:全小写

​ 首字母大写

多个单词:my-school注册时要加引号

​ MySchool每个字母的首字母大写(脚手架里用)

尽可能必要把组件名定义了与html里预留的标签不一致

<body>
<div id="root">
<!--    第三步编写组件标签-->
    <hello></hello>
    <schoo></schoo>
    <hr>
    <sutdent></sutdent>	//标签里可以写成自闭合区间
</div>


</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script type="text/javascript">
    //创建school组件,他没有el配置项,因为最终都要被一个vm管理,有vm决定他服务于哪个容器
    //简写 
    //const s = {} Vue会自动补上extend
    //标准写法
    const school = Vue.extend({
        name:'yyds',	//vue调试工具里名字就改成了Yyds,name默认注册名
        template:`
          <div>
          <h2>学校名称:{{ name }}</h2>
          <h2>学校地址:{{ address }}</h2>
          <button @click="showName">点我显示学校名</button>
          </div>`,
        data(){
            return{
                name:"学校",
                address:"北京"
            }
        },
        methods:{
            showName(){
                alert(this.name)
            }
        }
    })
    const sutdent = Vue.extend({
        template:`
          <div>
          <h2>学生名称:{{ name }}</h2>
          <h2>学生年龄:{{ age }}</h2>
          </div>`,
        data(){
            return{
                name:"yh",
                age:18
            }
        }
    })
    const hello = Vue.extend({
        template:`<div><h2>你好!!!{{name}}</h2></div>`,
        data(){
            return{
                name:"tom"
            }
        }
    })
    //注册组件
    Vue.component('hello',hello)    //全局注册,要在实例容器之前
    const vm = new Vue({       //非全局注册
        el:"#root",
        components:{
            schoo:school,   //调用时需要改名字时用key:value完整写法
            sutdent         //调用时不需要改组件名直接用组件名
        }
    })
</script>
组件的嵌套
<body>
<div id="root">
<!--    第三步编写组件标签-->
</div>


</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script type="text/javascript">
    Vue.config.productionTip = false
    
    //创建sutdent组件
    const sutdent = Vue.extend({
        template:`
          <div>
          <h2>学生名称:{{ name }}</h2>
          <h2>学生年龄:{{ age }}</h2>
          </div>`,
        data(){
            return{
                name:"yh",
                age:18
            }
        }
    })
    
    //创建school组件,把sutdent嵌套
    const school = Vue.extend({
        template:`
          <div>
            <h2>学校名称:{{ name }}</h2>
            <h2>学校地址:{{ address }}</h2>
            <sutdent></sutdent>
          </div>`,
        data(){
            return{
                name:"学校",
                address:"北京"
            }
        },
        components: {
            sutdent
        }
    })
    
    // 创建hello组件
    const hello = Vue.extend({
        template:`<h2>{{msg}}</h2>`,
        data(){
            return{
                msg:"简单"
            }
        }
    })
    
    //创建app组件,管理其它全部组件(一人之下,万人之上)
    const app =Vue.extend({
        components:{
            school,
            hello
        },
        template:`<div>
        <school></school>
        <hello></hello>
        </div>`
    })
    
    //创建vm管理app组件
    new Vue({
        el:"#root",
        template:`<app></app>`,
        components:{
            app
        }
    })
</script>
VueComponent(vc)

VueComponent的实例对象,简称vc(也可称为:组件实例对象)。

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

​ 我们只需要写,Vue解析是就会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)

​ 每次调用Vue.extend,返回的都是一个全新的VueComponent!

​ 关于this指向

​ 组件配置中:

​ data函数。methods中的hans、watch中的函数、comouted中的函数,他们的this均是{VueComponent}

​ new Vue(options)配置中:

​ data函数、methods中的函数、watch中的函数,他们的this均是{Vue实例对象}

Vue和VueComponent的关系

VueComponent原型的隐式指向了Vue的原型,让vc可以访问到vue原型上的属性和方法
VueComponent.prototype.__proto===Vue.prototype

单文件组件(Vue常用)(xxx.vue)

​ 一个文件中只包含1个组件

School.vue

<template>
<!--  组件的结构-->
  <div id="root" class="demo">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="showName"></button>
  </div>
</template>

<script>
  // //组件的交互相关的代码\1
  // const School = Vue.extend({
  //   data(){
  //     return{
  //       name:"迪迦",
  //       age:18
  //     }
  //   },
  //   methods:{
  //     showName(){
  //       alert(this.name)
  //     }
  //   }
  // })
  // //默认暴露
  // export default School
  //2!
  export default {
    name:'School',
    data(){
      return{
        name:'tom',
        age:18
      }
    },
    methods:{
      showName(){
        alert(this.name)
      }
    }
  }
</script>

<style>
  /*组件样式*/
  .demo{
    background-color: red;
  }
</style>
运行版本中没有模板编辑器mian.js里不能用模板函数

ref属性

​ 用来给元素或子组件注册引用信息(id的替代者)

​ 应用在html标签上获取的是真实的DOM元素,应用在组件标签上是组件实例对象(VC)

​ 使用方法:

​ 打标识:

​ 获取:this.$refs.xx

配置项props

让组件接收外部传过来的数据

​ 传递数据:

​ 接收数据

<script>
export default {
  name: "School-one",
  data() {
    return {
      lista:false
    }
  },
  methods: {
    showName() {
      if (this.lista===false){
        this.lista=true
      }else {
        this.lista=false
      }
    }
  },
  //传入的值尽量不修改,如果需要修改复制一份到data里从data调用修改
  // props: ['name','shutdows','age'], //简单声明接收,不限制接收类型

  // props: {
  //   name:String,
  //   shutdows:String,
  //   age:Number
  // },    //接收进行数据类型限制
  // 接收的同时对数据进行类型限制+默认值设置+必要性限制
  props: {
    name: {
      type: String,
      required:true,  //name是必须要传的
    },
    shutdows:{
      type:String,
      required: true
    },
    age:{
      type:Number,
      default:99    //默认值
    }
  },
}
</script>

配置项mixin

​ 功能:可以把多个组件共用的配置提取成一个混入对象

​ 使用方式

​ 创建一个js文件和mian平级

//mixin.js
//主动暴露export default {} 引用不要花括号
//分别暴露引用需要花括号
export const mixin = {
    methods: {
        showName() {
            alert(this.name+'你吗死了')
        }
    },
}
//School.vue
//引用混合
import {mixin} from "@/mixin";

export default {
  name: "School-one",
  data() {
    return {
      name:'tom',
      lista:true
    }
  },
  //局部混合
  mixins: [mixin],

}
//main.js
import { createApp } from 'vue'
import App from './App.vue'
// import {mixin} from "@/mixin";

createApp(App).mount('#app')    //确定容器前.mixin(mixin)全局混合

插件

​ 功能:用于增强Vue

​ 本质:包含install方法的一个对象,install的第一个参数是value,第二个以后的参数是产检使用者传递的数据。

​ 定义插件:

​ 对象.install = function(Vue,options){

​ //添加全局过滤器

​ Vue.filter()

​ //添加全局指令

​ Vue.directive()

​ //添加全局混入

​ Vue.mixin()

​ //添加实例方法

​ Vue.peototype.$myEnd = function(){}

​ }

​ 使用插件:Vue.use()

scoped样式

防止样式命名相同,使样式局部生效

<style scoped></style>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PpUgaHeV-1673171032561)(./img/image-20220716141833486.png)]

总结TodoList案例

1、组件化编码流程:

​ (1)、拆分静态组件:组件要按照更能点分析,命名不要与HTML元素冲突

​ (2)、实现动态组件:考虑好数据存放位置,数据的一个组件在用,还是一些组件在用:

​ 1)、一个组件在用:放在自身即可

​ 1)、一些组件在用:防在他们共同的父组件上(状态提升)

​ (3)、实现交互:从绑定事件开始

2、props适用于

​ (1)、父组件与子组件通信

​ (2)、子组件与父组件通信(父组件要给子组件传递一个函数)

3、使用v-model时切记:

​ v-model绑定的值不能是props传递过来的值,因为props是不可以修改的

4、props传递过来的若是对象类型的值,修改对象中的的属性时Vue不会报错,单不推荐这样做

webStorage

1.存储内容大小一般支持5MB左右(不同浏览器可能不一样)
2.浏览器端通过Windows.sessionStorage和Windows.localStorage属性来实现本地存储机制
3.相关API
	1.xxxxxxStorage.setItem('key','value')
		该方法接收一个键和值作为参数,会把键值添加到存储中,如果键名存在,则更新器对应的值
	2.xxxxxxStorage.getItem('key')
		返回对应键名的值
	3.xxxxxxStorage.removeItem('key')
		删除
	4.xxxxxxStorage.clear()
		全部清除
注意:
	SessionStorage存储的内容会随着浏览器窗口关闭而消失
	LocalStorage需要手动清除才会消失
	如果getItem获取不到为即为null
	JSON.parse(null)结果依然是null

自定义事件

组件间的一种通讯方式,适用于:子组件===》父组件

1.绑定自定义事件
	在组件标签上<School @nihao="function"/> / <School @nihao.once="function"/>
	或者设置ref=>this.$ref.School.$on('nihao',function) / this.$ref.School.$once('nihao',function)只触发一次
2.组件里触发
	函数里	this.$emit('nihao',data1,data2)
	解绑一个自定义事件	this.$off('nihao')
	解绑多个	this.$off(['nihao','niya'])
	暴力解绑(全部解绑)	this.$off()
3.function里接收数据,第一个为data,后面的在params里(也可以正常写)
	xxx(data,...params){}
4.this.$destroy()//销毁后所有的自定义事件全部无效了
5.组件上也可以绑定原生DOM事件,但是需要native修饰符<school @click.native/>
6.通过this.$refs.xxx.$on('nihao',function)绑定自定义事件时,回调(function)要么配置在methods中,要么用箭头函数,否者this指向的时调用这个自定义事件的组件

全局事件总线(GlobalEventBus)

1.一种组件间通讯的方式,适用于任意组件间通讯

2.安装全局事件总线:

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

3.使用事件总线:

​ 1.接收数据:A组件想接收数据,则在A组件中给$bus绑定事件,事件回调留在A组件自身

methods(){
    demo(data){......}
}
    ......
mounted(){
        this.$bus.$on('xxx',this.name)
    }

​ 2.提供数据:this. b u s . bus. bus.emit(‘xxx’,data)

4.最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件

beforeDestroy() {
    this.$bus.$off('schoolName')
  }

消息订阅与发布(pubsub)

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

2.使用步骤:

​ 1.安装pubsub: npm i pubsub-js

​ 2.导入:import pubsub from ‘pubsub-js’

​ 3.接收数据:A组件想接收数据,则在A组件订阅消息,订阅的回调留在A组件自身

export default {
  name: "school-a",
  data() {
    return {
      name: "changz",
      address:"北京"
    }
  },
  methods: {
    datas(msgName,data) {	//msgName是消息名称,可以用下划线占位不用_
      alert(1)
    }
  },
  mounted() {
    this.pubid = pubsub.subscribe('hello',this.datas) //订阅消息,this.datas可以写成箭头函数不用在methods里写
  },
  beforeDestroy() {
    pubsub.unsubscribe(this.pubid)
  }
}

4.提供数据:

export default {
  name: "student-a",
  data(){
    return{
      name:'Tom',
      sex:'男'
    }
  },
  mounted() {
    pubsub.publish('hello',this.name)	//提供数据
  }
}

5.最好在veforeDestroy钩子中取消订阅

当data里的数据为布尔值时判断存不存在

export default {
  name: "student-a",
  data(){
    return{
      name:'Tom',
      sex:'男'
    }
  },
  mounted() {
    pubsub.publish('hello',666)
  }
}
用hasOwnProperty判断data身上有没有一个属性
data.hasOwnProperty('name')

nextTick

1.语法:this.$nextTick(function)

2.作用:在下次DOM更新结束后执行去指定的回调

3.当改变数据后裔,要基于更新后的新DOM经行某些操作时,要在nextTick所指定的回调函数中执行

Vue封装的过度与动画

1.作用:在插入、更新或移除DOM元素时,在合适的时候给元素添加样式名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XW7qjhir-1673171032561)(./img/image-20220717165740380.png)]

3.写法:

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B2YqA3Zg-1673171032561)(./img/image-20220717165959667.png)]

Vue脚手架配置代理(我没遇到)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BSrzsFYm-1673171032561)(./img/image-20220717181025019.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0YiyYckK-1673171032562)(./img/image-20220717181136491.png)]

Ajax请求

axios(推荐)

安装axios:npm i axios

<template>
  <div>
    <div v-for="i in todo" :key="i.id">
        <div>{{ i.id }}</div>
        <div>{{ i.name }}</div>
        <div>{{ i.age }}</div>
      <hr>
    </div>
    <button @click="getData">获取学生信息</button>
  </div>0
</template>

<script>
import axios from 'axios'
export default {
  name: "txte-a",
  data() {
    return {todo:[{id:'001',name:'tom',age:18}]}
  },
  methods: {
    getData() {
      axios.get('http://127.0.0.1:4523/m1/1074324-0-default/server').then(data=>{
        this.todo.unshift(data.data)
      }).catch(error=>alert("请求错误"+error.message))
    }
  },
}
</script>

vue-resource

安装vue-resource:npm i vue-resource

main.js

import Vue from 'vue'
import App from './App.vue'
import vueResource from 'vue-resource'	//导入库

Vue.config.productionTip = false
Vue.use(vueResource)	//封装到vc
new Vue({
  render: h => h(App),
  beforeCreate() {
    Vue.prototype.$bus = this
  }
}).$mount('#app')
<template>
  <div>
    <div v-for="i in todo" :key="i.id">
        <div>{{ i.id }}</div>
        <div>{{ i.name }}</div>
        <div>{{ i.age }}</div>
      <hr>
    </div>
    <button @click="getData">获取学生信息</button>
  </div>
</template>

<script>
export default {
  name: "txte-a",
  data() {
    return {todo:[{id:'001',name:'tom',age:18}]}
  },
  methods: {
    getData() {
      this.$http.get('http://127.0.0.1:4523/m1/1074324-0-default/server').then(data=>{
        this.todo.unshift(data.data)
      }).catch(error=>alert("请求错误"+error.message))
    }
  },

}
</script>

插槽

1.作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件==》子组件

2.分类:默认插槽,具名插槽,作用域插槽

3.使用方式

默认插槽

父组件:
<School>
    <div>
        html结构
    </div>
</School>
子组件:
<template>
	<div>
        <solt>
            html结构
        </solt>
    </div>
</template>

具名插槽

父组件:
	<school>
		<template slot='center'>
        	<div>
                html结构
            </div>
        </template>
        
        <template v-solt:footer>
        	<div>
                html结构
            </div>
        </template>
	</school>
子组件:
	<template>
		<div>
        	<solt name="center">
            	html结构
        	</solt>
            
            <solt name="footer">
            	html结构
        	</solt>
    	</div>
	</template>

作用域插槽

理解:数据在组件自身,但根据数据生成的结构需要组件的使用者开决定。(gemas数据在app组件中,但使用数据所遍历出来的结构由App组件决定)

父组件:
<school>
    <template scope="sutdentData">
        <ul>
            <li v-for="i in sutdentData.games">
                {{i}}
            </li>
        </ul>
    </template>
</school>

<school>
    <template slot-scope="sutdentData">
        <h4 v-for="i in sutdentData.games">
            {{i}}
        </h4>
    </template>
</school>
子组件:
<template>
    <div>
        <slot :games="games"></slot>
    </div>
</template>
<script>
    export default{
        name:"school",
        prpos:['title'],
        data(){
            return{
                games:['a','b','c']
            }
        }
    }
</script>

Vuex

vuex是什么

1.概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式管理(读/写),也就是一种组件间通信的方式,且适用于任意组件间的通信。

什么时候使用vuex

1.多个组件依赖于同一状态

2.来自不同组件的行为需要变更同一状态

搭建Vuex环境

1新建一个文件夹Vuex(或store),在文件夹里新建一个index.js(官方命名)/src/Vuex/index.js

//该文件用于创建Vuex最核心的store
//引入Vue
import Vue from "vue";
//应用Vuex插件
Vue.use(Vuex)
//引入Vuex
import Vuex from 'vuex'
//准备actions用于响应组件中的动作
const actions = {
    //context是上下文,value是传递的数据
    jia(context,value){
        context.commit('JIA',value)
    }
}
//准备mutations用于操作数据(state)
const mutations = {
    //state是下面的数据,value是传递过来的数据
    JIA(state,value){
        state.todo.unshift(value)
    }
}
//准备state用于存储数据,初始化数据
const state = {todo:[{id:'13',name:'李华',age:89}]}
//创建store并暴露store
export default new Vuex.Store({
    actions,
    mutations,
    state
})

2.在main.js中创建vm时传入store配置项/src/main.js

import store from "./vuex";
new Vue({
  store,
  render: h => h(App),
  beforeCreate() {
    Vue.prototype.$bus = this
  }
}).$mount('#app')

基本使用

//Vue组件里,可直接调用,操作(网络请求AJAX)交给actions,改写交给mutations
this.$store.dispatch('jia',data.data)	//dispatch调用actions
this.$store.commit('JIA',data.data)		//commit调用mutations

getters(非必要)

当state中的数据需要加工后再使用时,用getters加工(类似于计算属性)要有返回值

/src/Vuex/index.js

//准备getters用于将state中的数据进行加工
const getters = {
    bigSum(state){
        return state.todo[0].id+'1'
    }
}

export default new Vuex.Store({
    actions,
    mutations,
    state,
    getters
})

使用

Vue组件里

<div>{{$store.getters.bigSum}}</div>

mapState和mapGetters

…是把获得的变成对象铺开

import {mapState,mapGetters} from 'vuex'
export default {
  name: "txte-a",
  data() {
    return {}
  },
  computed:{
    //借助mapState从state里读取数据为计算属性
    // 对象写法
    ...mapState({id:'id',name:'name',age:'age'}),
    //数组写法(前提是你想生成的计数属性名称和state里数据的名称一致)
    ...mapState(['id','name','age']),
    //借助mappSetters从getters里读取数据为计算属性
    ...mapGetters({bigSum:'bigSum'}),
    ...mapGetters(['bigSum'])
  },
  methods: {
    getData() {
      this.$http.get('http://192.168.2.110:4523/m1/1074324-0-default/server').then(data=>{
        console.log(data)
        this.$store.dispatch('jia',data.data)
      }).catch(error=>alert("请求错误"+error.message))
    }
  },
}

mapMutations和mapActions

import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
export default {
  name: "txte-a",
  data() {
    return {}
  },
  computed:{
    //借助mapState从state里读取数据为计算属性
    // 对象写法
    ...mapState({id:'id',name:'name',age:'age'}),
    //数组写法(前提是你想生成的计数属性名称和state里数据的名称一致)
    ...mapState(['id','name','age']),
    //借助mappSetters从getters里读取数据为计算属性
    ...mapGetters({bigSum:'bigSum'}),
    ...mapGetters(['bigSum'])
  },
  methods: {
    // this.$store.commit('jia')
    //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations传参是要在后面加括号
    ...mapMutations({JIA:'JIA'}),  //对象写法
    ...mapMutations(['JIA']),  //数组写法
    
    // this.$store.dispatch('jia')
    //借助mapActions生成对应的方法,方法中会调用dispatch去联系actions传参是要在后面加括号
    ...mapActions({jia:'jia'}),  //对象写法
    ...mapActions(['jia'])  //数组写法
  },
}

调用

<div @click="JIA(data)"></div>
<div @click="jia(data)"></div>

Vuex模块化+命名空间

index.js

import Vue from "vue";
Vue.use(Vuex)

import Vuex from 'vuex'
import axios from "axios";

const getList = {
    namespaced:true,    //开启命名空间
    actions:{
        jia(context){
            axios.get('http://192.168.2.110:4523/m1/1074324-0-default/server').then(data=>{
                console.log(data)
                context.commit('JIA',data.data)
            }).catch(error=>alert("请求错误"+error.message))
        }},
    mutations:{
        JIA(state,value){
            console.log(value)
            state.todo.unshift(value)
        }},
    getters:{
        bigSum(state){
            return state.todo[0].id+'1'
        }},
    state:{todo:[{id:'13',name:'李华',age:89}]}
}

export default new Vuex.Store({
    modules:{
        getList
    }
})

Vue组件里

<template>
  <div>
    <div v-for="i in $store.state.getList.todo" :key="i.id">
        <div>{{$store.getters.bigSum}}</div>
        <div>{{ i.id }}</div>
        <div>{{ i.name }}</div>
        <div>{{ i.age }}</div>
      <hr>
    </div>
    <button @click="jia">获取学生信息</button>
  </div>
</template>

<script>
import {mapActions} from 'vuex'
export default {
  name: "txte-a",

  methods: {
      //手写
    // jai(){
    //   this.$store.commit('getList/JIA')
    // },
      //模块生成
    ...mapActions('getList',['jia']),  //要在前面加上一个参数模块的名字
  },
}
</script>

手写的天坑

this.$store.getters['getList/bigSum']

可以把每个模块封装为js文件,记得暴露

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W3Wktttl-1673171032562)(./img/image-20220719202816117.png)]

路由(router)

路由就是一组Key-Value的对应关系

多个路由,需要经过路由器管理

1.基本使用

​ 1.安装vue-router,命令 npm i vue-router

​ 1.应用插件 Vue.use(VueRouter)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xWn5vis3-1673171032562)(./img/image-20220720155200176.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0GQCI7YL-1673171032562)(./img/image-20220720155217611.png)]

<!--      实现路由切换 active-class有人点击时加入样式-->
      <router-link to="" active-class=""></router-link>
<!--      指定组件的呈现位置-->
      <router-view></router-view>

路由组件一般存放在pages文件夹,一般组件通常存放在components文件夹

通过切换,‘隐藏’了的路由组件,默认是被销毁掉的,需要的时候再去挂载

给个组件都有自己的$route属性,里面存储着自己的路由信息

整个应用只有一个router,可以通过组件的$router属性获取到

2.嵌套(多级)路由

/router/index.js

export default new VueRouter({
    routes:[
        {
            path:'/txte',
            component:txte,
            //配置子路由,子路由前面不加/
            children:[{
                path:'txte',
                component:txte
            }]
        },
    ]
})

Vue组件里

路径要带上完整路径
<router-link to="/txte/txte" active-class=""></router-link>

3.路由的query参数

<router-link to="/txte?id=12" active-class=""></router-link>
<!--或者-->
<router-link :to="{
                  path:'/txte',
                  query:{
                  id=12
                  }
                  }" active-class="">
</router-link>

组件里获取

$query.id

4.命名路由

简化路由的跳转

设置名称

export default new VueRouter({
    routes:[
        {
            name:'index'
            path:'/txte',
            component:txte,
            children:[{
            	name:'txte'
                path:'txte',
                component:txte
            }]
        },
    ]
})

使用名称

<router-link :to="{
                  name:'index'
                  query:{
                  id=12
                  }
                  }" active-class="">
</router-link>

4.路由的params参数

vue组件里

<router-link to="/txte/12" active-class=""></router-link>

路由

export default new VueRouter({
    routes:[
        {
            path:'/txte/:id',
            component:txte,
        },
    ]
})

获取

$router.params.id

注意:路由携带params参数时,若使用to的对象写法,则不能使用path,必须使用name配置

5.路由的props

让路由组件跟方便收到值

export default new VueRouter({
    routes:[
        {
            path:'/txte/:id',
            component:txte,
            //写法一,值为对象,改对象中的所有key-value都会一props的形式传递给txte组件
            //props:{a:1,b:'hello'}	//传递死数据
            
            //写法二,值为布尔值,布尔值为真,就会把该路由组件收到的所有params产生,一peops的形式传给txte组件
            //props:true
            
            //写法三,值为函数
            props($route){
                return{
                    id:$route.query.id,
                    title:$route.query.title
                }
            }
        },
    ]
})

接收组件

export default {
    name:'txte',
    props:['id','title']
}

6.router-link的replace模式(默认push)

replace模式浏览器不能前进后退(替换当前浏览记录)

<router-link replace to="/text" active-class=""></router-link>

7.编程式路由导航

作用:不借助router-link实现跳转,让跳转更灵活

export default {
  name: "txte-a",
  methods: {
    //push方法跳转
    push() {
      this.$storer.push({
        name:'txte',
        params:{
          id:12
        }
      })
    },
    //replate方法跳转
    replate(){
      this.$storer.replate({
        name:'txte',
        params:{
          id:12
        }
      })
    },
    //前进
    forshow(){
      this.$storer.forshow()
    },
    //后退
    back(){
      this.$storer.back()
    },
    //前进3步为负数时后退
    go(){
      this.$storer.go(3)
    }
  },
}

8.缓存路由组件

keep-alive让组件不显示的时候不被销毁,不写include默认全部不销毁,写了include表示中有txte-a这个组件不销毁,txte-a是组件名

:include="['txte','hello']"	不销毁多个
<keep-alive include="txte-a">
    <router-link to="/text" active-class=""></router-link>
</keep-alive>

9.activated和deactivated(生命周期钩子)

作用:路由组件独有的两个钩子,用于捕获路由组件的激活状态

activated路由组件被激活时触发

deactivated路由组件失活时触发

10.路由守卫(权限)

作用:对路由器进行权限控制

分类:全局守卫、独享守卫、组件内守卫

1.全局守卫

import VueRouter from "vue-router";
import txte from "@/components/txte";
//创建并暴露一个路由器
const router = new VueRouter({
    routes:[
        {
            path:'/txte',
            component:txte,
            //配置是否需要校验权限,meta里面是给程序员存储页面信息的
            meta:{isAuth:true,title:'主页'},
            children:[{
                path:'txte',
                component:txte
            }]
        },
    ]
})

//全局前置路由守卫(每次路由切换前调用,初始化也执行) to是去哪  from来自哪 next是放行
router.beforeEach((to, from, next)=>{
    if (to.meta.isAuth){
        next()
    }else{
        next()
    }
})
//全局后置路由守卫
router.afterEach((to,from)=>{
    document.title = to.meta.title || '云海'
})

export default router

2.独享守卫

import VueRouter from "vue-router";
import txte from "@/components/txte";
const router = new VueRouter({
    routes:[
        {
            path:'/txte',
            component:txte,
            //配置是否需要校验权限,meta里面是给程序员存储页面信息的
            meta:{isAuth:true,title:'主页'},
            //独享守卫(只有前)
            beforeEnter:(to, from, next)=>{next()},
            children:[{
                path:'txte',
                component:txte
            }]
        },
    ]
})
export default router

3.组件内路由守卫

txte.vue

export default {
  name: "txte-a",
  //通过路由规则,进入组件时被调用
  beforeRouteEnter(to,from,next){
    next()
  },
  //通过路由规则,离开组件时被调用
  beforeRouteLeave(to,from,next){
    next()
  }
}

11.路由器工作的两种模式

对于一个url来说,什么是hash值?----#及后面的内容就是hash值

hash值不会包含在HTTP请求中,即:hash值不会带给后端

hash模式:

​ 地址中永远带着#号,不美观

​ 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记不合法

​ 兼容性较好

history模式:

​ 地址感觉,美观

​ 兼容性与hash对比略差

​ 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题

import VueRouter from "vue-router";
import txte from "@/components/txte";
const router = new VueRouter({
    //默认是hash但是后面有/#/
    mode:"history",
    routes:[
        {
            path:'/txte',
            component:txte,
            //配置是否需要校验权限,meta里面是给程序员存储页面信息的
            meta:{isAuth:true,title:'主页'},
            //独享守卫(只有前置)
            beforeEnter:(to, from, next)=>{next()},
            children:[{
                path:'txte',
                component:txte
            }]
        },
    ]
})
export default router

Vue UI组件库

移动端常用UI组件库

Vant、Cube UI、Mint UI

PC端常用组件库

Element UI

IView UI

Vue3

1.vite创建工程

vite中文网

2.常用Composition API(组合API)

拉开序幕的setup

​ 理解:Vue3.0中的一个新的配置项,值为一个函数
​ setup是所有Composition API(组合API)“表演的舞台”
​ 组件中用到的:数据、方法等,均要配置在setup中
​ setup函数的两种返回值:
​ 若返回一个对象,则对象中的属性、方法,在模板中均可直接使用!
​ 若返回一个渲染函数:则可以自定义渲染内容
​ 注意:
​ 尽量不要与Vue2.x配置混用
​ Vue2配置(data、methos、computed…)中可以访问到setup中的属性、方法
​ 但是setup不能访问到Vue2配置(data、methos、computed…)
​ 如果有重名,setup函数优先
​ setup函数不能是一个asynchans,因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性(后期也可以返回一个Promise实力,但需要Suspense和异步组件的配合)

ref函数(不是Vue2里的)

​ 作用:定义一个响应式的数据
​ 语法:const xxx = ref(initValue)
​ 创建一个包含响应式数据的引用对象(reference对象,简称ref对象)
​ JS中操作数据:xxx.value
​ 模板中读取数据:不需要.value,直接模板语法即可
​ 备注
​ 接收的数据可以是:基本类型、也可以是对象类型
​ 基本类型的数据:响应式依然是依靠Object.defineProperty()的get与set完成的
​ 对象类型的数据:内部使用了Vue3中的一个新函数–reactive函数

reactive函数

​ 作用:定义一个对象类型的响应式数据(基本类型不能用,要用ref函数,也可以把基本类型封装为对象使用)
​ 语法:const 代理对象 = reactive(源对象) 接收一个对象(或数组),返回一个代理对象(proxy的实例对象,简称proxy对象)
​ reactive定义的响应式数据是“深层次的”
​ 内部基于ES6的Proxy事项,通过代理对象操作源对象内部数据进行操作

Vue3中的响应式原理

Vue2的响应式

​ 实现原理:
​ 对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)
​ 数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更方式进行了包裹)
​ 存在的问题:
​ 新增属性、删除属性,界面不更新(vue2没有检测到)
​ 直接通过索引修改数组,界面不更新(vue2没有检测到)

Vue3的响应式

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

new Proxy(data,{
  //拦截读取属性值 target是对象 prop是对象里被用的名称(key)value是修改后的值
  get(target, prop) {
    return Reflect.get(target,prop)
  },
  set(target,prop,value) {
    return Reflect.set(target,prop,value)
  },
  deleteProperty(target,prop) {
    return Reflect.deleteProperty(target,prop)
  }
})

reactive与ref对比

从定义数据角度对比:
ref用来定义:基本类型数据
reactive用来定义:对象(或数组)类型数据
备注:ref也可以用来定义对象(或数组)类型数据,他会内部通过reactive转为代理对象
从原理角度
ref通过Object.defineProperty()getset来实现响应式(数据劫持)
reactive通过使用Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部的数据
从使用角度:
ref定义的数据:操作数据需要.value,读取时不用.value
reactive定义的数据:操作和读取数据时均不要.value

setup的两个注意点

setup执行时机
beforeCreate执行前执行
setup的参数
props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性
context:上下文对象
attrs:值为对象,半酣:组件从外部传递过来,但没有在props配置中声明的属性,相当于this.$attrs
alots:收到的插槽内容,相当于this.$slots
emit:分发自定义事件的函数,相当于this.$emit

计数属性和监视

computed函数

与vue2中computed配置功能一致

   //计算属性简写
    let full = computed(()=>{
      return a.age+a.name
    })
    //计算属性完整写法
    let full = computed({
      get(){
        return a.age+a.name
      },
      set(value){
        a.name = value
      }
    })
watch函数

与vue2中配置功能一致

两个坑:

​ 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置项失效)

​ 监视reactive定义的响应式数据中某个属性时:deep配置有效

    //情况一:监视ref定义的一个响应式数据
    watch(a,(newValue,oldValue)=>{
      console.log(newValue+'<='+oldValue)
    },{immediate:true,deep:true})

    // //情况二:监视ref定义的多个响应式数据
    watch([a,b],(newValue,oldValue)=>{
      console.log(newValue+'<='+oldValue)
    },{immediate:true,deep:true})

    //情况三:监视reactive所定义的一个响应式数据的全部属性,无法正确获取oldValue(天坑勿用)
    // 强制开启了深度监视(关不掉)
    watch(a,(newValue,oldValue)=>{
      console.log(newValue+'<='+oldValue)
    },{immediate:true,deep:false})

    //情况四:监视reactive定义的一个响应式数据中的某个属性
    watch(()=>a.li.lk.sx,(newValue,oldValue)=>{
      console.log(newValue+'<='+oldValue)
    },{immediate:true,deep:false})

    //情况五:监视reactive定义的一个响应式数据中的一些属性
    watch([()=>a.li.lk.sx,()=>a.li.lk.sy],(newValue,oldValue)=>{
      console.log(newValue+'<='+oldValue)
    },{immediate:true,deep:false})

    //特殊情况
    watch(()=>a.li.lk,(newValue,oldValue)=>{
      console.log(newValue+'<='+oldValue)
    },{deep:true})//这里由于监视的时reactive定义的对象中的属性使用deep属性有效
watchEffect函数

watch:既要指明监视属性,也要指明监视回调

watchEffect:不用指明监视哪个属性,监视的回调中用到哪个属性就监视哪个属性

watchEffect与computed相似:

​ 但computed注重技术按出来的值(回调函数的返回值),所以必须要写返回值

​ 而watchEffect更注重过程(回调函数的函数体),所以不用写返回值

watchEffect(()=>{
      const xz = a.age
    })

Vue3生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zPfXfZbX-1673171032563)(img/uTools_1658665750479.png)]

Vue3中可以继续使用Vue2中的生命周期钩子,但是有两个被改名字了:

  • beforeCreate====>beforeUnmount
  • destroyed====>unmounted

Vue3也提供了Composition API形式的生命周期钩子,与Vue2中的钩子对应关系如下:

  • berforeCreate===>setup()
  • created=========>setup()
  • beforeMount=====>onBeforeMount
  • mounted=========>onMounted
  • beforeUpdate====>onBeforeUpdate
  • update==========>onUpdate
  • beforeUnmount===>onBeforeUnmount
  • unmounted=========>onUnmounted

自定义hook函数

取名/hooks/usexxx

本质是一个函数,把setup函数中使用的Composition API进行封装。

类似于vue2中的mixin

自定义hook的优势:复用代码,让setup中的逻辑根清楚易懂

toRef

作用:创建一个ref对象,其value值指向另一个对象中的某各属性

语法:const name = toRef(person,'name)person下的name

应用:要将响应式对象中的某个属性单独提供给外部使用时

拓展:toRefstoRef功能一致,但可以创建多个ref对象

语法:toRefs(person)

3.其它Composition API

shallowReactiveshallowRef

shallowReactive:只出来对象最外层属性的响应式(浅响应式)

shallowRef:只处理基本数据类型的响应式,不进行对象响应式的处理

什么时候用

  • 如果有一个对象数据,结构嵌套比较深,但变化时只是外层属性变化===》shallowReactive
  • 如果y偶一个对象数据,后续功能不会修改改对象中的属性,为啥生成新的对象来代替===》shallowRef

readonlyshallowRandonly

readonly:让一个响应式数据变为只读(深只读)

shallowRandonly:让一个响应式数据变为只读(浅只读)

应用场景:不希望数据被修改时

toRaw与markRaw

toRaw

  • 作用将一个由reactive生成的响应式对象转为普通对象
  • 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面的更新

markRaw

  • 作用:标记一个对象,使其永远不会成为响应式对象。
  • 使用场景:
  1. 有些值不应该被设置为响应式的,例如复杂的第三方类库等
  2. 当渲染具有不可变数据源的大列表时,跳过响应式转换可以体改性能

customRef

  • 作用:创建一个自定义ref,并对其依赖向跟踪和更新触发镜像显式控制
    function myRef(value){
      let timer
      return customRef((track, trigger) => {
        return{
          get(){
            track()   //通知Vue追踪value的变化(提前和get申明,让他知道value有用
            return value
          },
          set(newValue){
            clearTimeout(timer)
            value = newValue
            setTimeout(()=>{
              console.log(value)
              trigger()   //通知Vue去重新解析模板
            },1000)
          }
        }
      })
    }
    // let as = ref(1)
    let as = myRef(1)

provide与inject

  • 作用:实现祖孙组件间通信
  • 用法:父组件有一个provide选项来提供数据,后代组件有一个inject选项来开始使用这些数据

祖组件:

  setup(){
    let car = reactive({
      name: '奔驰',
      price:"40w",
    })
    provide('car', car)
    return {...toRefs(car)}
  }

后代组件:

  setup(){
    let car = inject('car')
    return {car}
  }

响应式数据的判断

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

4.Composition API的优势

  • Options API存在的问题

传统Options API中,新增或者修改一个需求,就需要分别在data,methods,computed里修改

  • Composition API的优势

我们可以更优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起

5.新组件

Fragment

  • 在Vue2中:组件必须有一根跟标签
  • 在Vue3中:组件可以没有根标签,内部会将多个标签包裹在一个Fragment虚拟元素中
  • 好处:建设标签层级,减小内存占用

Teleport

将我们的组件html结构移动到指定位置

<template>
  <button @click="tans = true">点我弹窗</button>
  <teleport to="body">
    <div class="tansr" v-show="tans">
      <h2>弹窗</h2>
      <h2>内容</h2>
      <h2>内容</h2>
      <h2>内容</h2>
      <button @click="tans = false">关闭弹窗</button>
    </div>
  </teleport>
</template>

Suspense

  • 等待异步组件时渲染一些额外内容,让用户有更好的体验

  • 使用步骤

    异步引入组件

    // import HelloWorld from "@/components/HelloWorld";
    import {reactive,toRefs,provide,defineAsyncComponent} from "vue";
    const HelloWorld = defineAsyncComponent(()=>import('./components/HelloWorld.vue'))
    

    使用Suspense包裹组件,并配置好defaultfallback

        <Suspense>
    <!--      实际应该显示的-->
          <template v-slot:default>
            <HelloWorld/>
          </template>
    <!--      实际显示的没加载完成时显示-->
          <template v-slot:fallback>
            <h2>正在加载......</h2>
          </template>
        </Suspense>
    

6.其他

全局API的转移

  • Vue2有许多全局API和配置

    例如:注册全局组件、注册全局指令等

    //注册全局组件
    Vue.component('MyButton',{
        data:()=>({
            count:0
        }),
        template:`<div></div>`
    })
    //注册全局指令
    Vue.directive('focus',{
        inserted:el => el.focus()
    })
    
  • Vue3中对这些API做出里调整

    将全局API,即Vue.xxx调整到应用实例(app)上

    2.x全局API3.x实例API(app)
    Vue.configapp.config.xxxx
    Vue.config.productionTip(关闭提示)移除
    Vue.componentapp.component
    Vue.directiveapp.directive
    Vue.mixinapp.mixin
    Vue.useapp.use
    Vue.prototypeapp.config.globalProperties
    Vue.extend移除

其他改变

  • data选项应该始终被声明为一个函数

  • 过度类目的更改:

    • Vue2写法

      .v-enter,
      .v-leave-to{
      opacity:0
      }
      .v-leave,
      .v-enter-to{
      opacity:1
      }
      
    • Vue3写法

      .v-enter-from,
      .v-leave-to{
      opacity:0
      }
      .v-leave-from,
      .v-enter-to{
      opacity:1
      }
      
  • 移除keyCode作为v-on的修饰符(按键编码),同时也不再支持config.keyCodes(按键的别名)

  • 移除v-on.native修饰符(vue2的原生点击事件)

    • 父组件绑定事件

      <school
              @click = 'function'
              @close = 'function'
              />
      
    • 子组件中声明自定义事件

      <script>
          export default{
              //emits里写的才会被认为是自定义事件,不写就是原生click
              emits:['close']
          }
      </script>
      
  • 移除过滤器(filter)

    用方法调用和计算属性去替换
    h2>内容
    <button @click=“tans = false”>关闭弹窗

```

Suspense

  • 等待异步组件时渲染一些额外内容,让用户有更好的体验

  • 使用步骤

    异步引入组件

    // import HelloWorld from "@/components/HelloWorld";
    import {reactive,toRefs,provide,defineAsyncComponent} from "vue";
    const HelloWorld = defineAsyncComponent(()=>import('./components/HelloWorld.vue'))
    

    使用Suspense包裹组件,并配置好defaultfallback

        <Suspense>
    <!--      实际应该显示的-->
          <template v-slot:default>
            <HelloWorld/>
          </template>
    <!--      实际显示的没加载完成时显示-->
          <template v-slot:fallback>
            <h2>正在加载......</h2>
          </template>
        </Suspense>
    

6.其他

全局API的转移

  • Vue2有许多全局API和配置

    例如:注册全局组件、注册全局指令等

    //注册全局组件
    Vue.component('MyButton',{
        data:()=>({
            count:0
        }),
        template:`<div></div>`
    })
    //注册全局指令
    Vue.directive('focus',{
        inserted:el => el.focus()
    })
    
  • Vue3中对这些API做出里调整

    将全局API,即Vue.xxx调整到应用实例(app)上

    2.x全局API3.x实例API(app)
    Vue.configapp.config.xxxx
    Vue.config.productionTip(关闭提示)移除
    Vue.componentapp.component
    Vue.directiveapp.directive
    Vue.mixinapp.mixin
    Vue.useapp.use
    Vue.prototypeapp.config.globalProperties
    Vue.extend移除

其他改变

  • data选项应该始终被声明为一个函数

  • 过度类目的更改:

    • Vue2写法

      .v-enter,
      .v-leave-to{
      opacity:0
      }
      .v-leave,
      .v-enter-to{
      opacity:1
      }
      
    • Vue3写法

      .v-enter-from,
      .v-leave-to{
      opacity:0
      }
      .v-leave-from,
      .v-enter-to{
      opacity:1
      }
      
  • 移除keyCode作为v-on的修饰符(按键编码),同时也不再支持config.keyCodes(按键的别名)

  • 移除v-on.native修饰符(vue2的原生点击事件)

    • 父组件绑定事件

      <school
              @click = 'function'
              @close = 'function'
              />
      
    • 子组件中声明自定义事件

      <script>
          export default{
              //emits里写的才会被认为是自定义事件,不写就是原生click
              emits:['close']
          }
      </script>
      
  • 移除过滤器(filter)

    用方法调用和计算属性去替换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值