vue3基础语法

一.组合式 API 也就是composition-api

(1) vue2 组件的局限性

 1. 组件越大,可续性越差

 2. 相同的代码逻辑很难在多个组件中复用

(2) 提供以下几个函数

 1. setup  :组合api 的方法都是写在这里面的

 2. ref : 定义响应式数据 字符串 bool 

 3. reactive :定义响应式数据   对象

 4. watchEffet :监听数据变化

 5. watch :监听数据变化

 6. computed :计算属性

 7. toRefs  :解构响应式对象数据

 8. 生命周期的hooks

(2.1) setup

官网

1. setup 函数会在 beforeCreate、created 之前执行,setup的生命周期 在 beforeCreate、created 之后执行

2. setup 有2个参数

    

props 的父组件传递过来的参数

    ctx 上下文对象

        ctx.attrs

        ctx.slots

        ctx.parent

        ctx.root

        ctx.emit

        ctx.refs

3. 在 setup() 函数中无法访问到 this【没有 this。这意味着,除了 props 之外,你将无法访问组件中声明的任何属性——本地状态、计算属性或方法。】

4. 执行 setup 时,组件实例尚未被创建,你只能访问以下 property【props,attrs, slots, emit 】,你将无法访问以下组件选项【data,computed ,methods】

<template>

    <div class="setup">

    </div>

</template>

<script>

export default {

    setup() {

        console.log('setup')

    },

    beforeCreate() {

        // console.log("beforeCreate");

    },

    created() {

        // console.log("created");

    }

};

</script>

 

(2.2) ref ,reactive 定义响应式数据

ref 【定义字符串,num,bool,数组】 

reactive【定义对象】

<template>

    <div class="setup">

        <h2>1.ref ,reactive 定义响应式数据</h2>

        <div>{{title}}{{userInfos.username}}---{{userInfos.age}}</div>

        <br />

        <button @click="getUserName">获取用户名称</button>

        <div>双向数据绑定 影响ref,reactive</div>

        <br />

        <input v-model="title" />

        <input v-model="userInfos.username" />

    </div>

</template>

<script>

import { ref, reactive } from "vue";

export default {

    setup() {

        var title = ref("用户信息:");

        const repositories = ref([]);// 定义数组

        var userInfos = reactive({

            username: "张三",

            age: 20

        });

        // 定义方法

        var getUserName = () => {

            // 获取reactive的数据

            console.log("username:", userInfos.username);

            //获取ref 的数据

            console.log("title:",title.value);

 

                // 修改reactive的数据

            userInfos.username = "张艺";

            //修改ref 的数据

            title.value = "改变用户信息:";

        };

        return {

            title,

            userInfos,

            getUserName

        };

    }

};

</script>

(2.3) toRefs 解构响应式对象数据

<h2>2.toRefs 解构响应式对象数据</h2>

{{worksName}}

<input v-model="worksName" />

 

setup() {

    // 2.toRefs 解构响应式对象数据

    var worksInfos = reactive({

        worksName: "张三",

        worksDesi: "到好多好好的"

    });

    return {

       ...toRefs(worksInfos) //...worksInfos  这样的话可以显示数据,但是不能双向绑定数据

    };

}

(2.4) computed 计算属性 【只能在setup】

  <input v-model="firstName" />

    <input v-model="lastName" />

    <div>{{fullName}}</div>

    setup() {

        //3.computed :计算属性

        var userInfos2 = reactive({

            firstName: "王",

            lastName: "一搏"

        });

 

        var fullName = computed(() => {

            return userInfos2.firstName + userInfos2.lastName;

        });

 

        return {

            ...toRefs(userInfos2),

            fullName

        };

(2.5) readonly "深层"的只读代理 (少用)

将响应式 数据(ref,reactive定义的数据),转正非响应式的数据(也就是原始数据)

readonly 传入一个对象(响应式对象),返回一个原始对象 只能读取不能修改。

var obj={

    username:"李小英"

}

obj 就是原始数据, 可以渲染在页面中,但是不能双向绑定

var userInfos = reactive({

    username: "张三",

    age: 20

});

userInfos  响应式数据,

可以把响应式数据 转成非响应式数据,

const copy = readonly(userInfos) //copy.username 只能读取,不能修改

(2.6)  watchEffet 监听数据变化

    在响应式地跟踪其依赖项时,立即运行一个函数,并在更改依赖项时重新运行它。

<h2>4.watchEffet 监听数据变化 --侦听器</h2>

    <div>{{data.count}}</div>

    <button @click="stop">手动关闭侦听器</button>

    const data = reactive({

        count: 1,

        num: 1

    });

    const stop = watchEffect(() => {

        console.log("侦听器:", data.count);

    });

    setInterval(() => {

        data.count++;

    }, 1000);

 

(2.7) watch , watch与watchEffect区别

1.watch与watchEffect区别:

const data = reactive({

    count: 10,

    num: 1

});

 

1. 懒执行,也就是说只有侦听的值变更时才执行回调

    watchEffect(() => {

        console.log("侦听器:", data.count);// 可以输出1

    });

    watch(data, () => {

        console.log("watch 监听:", data.count);// 输出2

    });

    watch  只有监听到值(data.count)发生变化 才执行,watchEffect都可以执行

2. 更明确哪些状态的改变会触发侦听器重新运行

    watchEffect 可以监听具体的对象【如:data.count】,watch 只能监听ref或是reactive定义的对象【如: data】

3. 访问侦听状态变化前后的值

    watch(numVal, (newVal, oldVal) => {

        console.log("numVal新值跟旧值的变化:", newVal, oldVal);

    });

案例: 

<h2>5.watch 监听数据变化 --侦听器</h2>

    <div>{{data.count}}</div>

    <div>watch 双向数据绑定,前后数据</div>

    {{numVal}}

    <input v-model="numVal" />

    <input v-model=data.count"/>

 

    const data = reactive({

        count: 10,

        num: 1

    });

    // (1).简单的引用

    // 要监听对象data ,但是不能监听对象里的值data.count

    watch(data, () => {

        console.log("watch 监听:", data.count);

    });

    setInterval(() => {

        data.count++;

    }, 1000);

    var numVal = ref("1");

    // (2).watch 的两个参数,代表新的值和旧的值

    watch(numVal, (newVal, oldVal) => {

        console.log("numVal新值跟旧值的变化:", newVal, oldVal);

    });

    //(3). watch 多个值,返回的也是多个值的数组

    watch([numVal, data], (newValue, oldValue) => {

        console.log("old", oldValue); //["13",Proxy {count: "144", num: 1}]

        console.log("new", newValue); //["134",Proxy {count: "144", num: 1}]

    });

    // (4).使用 getter 的写法 watch reactive 对象中的一项

    watch([numVal, () => data.count], (newValue, oldValue) => {

        console.log("old", oldValue); //old (2) ["1", 10]

        console.log("new", newValue); //new (2) ["1", "103"]

        console.log("updated:" + numVal.value + data.count); //updated:1103

    });

 

(2.8) 生命周期

生命周期的vue3更新:

在vue3中对生命周期钩子的命名进行一些简单的命名更新,并且在setup函数中提供了新的生命周期函数钩子。

1. 命名改变

vue3对beforeDestroy 和destroy进行命名的修改,分别修改为beforeUnmount,unmounted。这个是命名的改变,回调时机上并没有发生任何的改变。

2. setup函数中提供了新的生命周期函数钩子

官网

都是 setup () 内部调用生命周期钩子,没有beforeCreate,created ,其他都是一样

(2.9)Provide / Inject

官网

不管组件层次 结构多深,都可以使用这个Provide(传递参数) / Inject (接受参数)

1.非组合api 写法

app.vue

<template>

    <div>

        <div>祖父组件:{{location}}</div>

        <button @click="fn">改变location的值</button>

        <provides></provides>

    </div>

</template>

<script>

import provides from "@/views/provide.vue";

export default {

    name: "App",

    components: {

        provides

    },

    data() {

        return {

            location: "传递祖父的参数"

        };

    },

    methods: {

        fn() {

            this.location = "改变值";

        }

    },

    provide() {

        return {

            location: this.location,

            geolocation: {

                longitude: 90,

                latitude: 135

            }

        };

    }

};

</script>

provides:

<template>

    <div>

        <h2>Provide / Inject</h2>

        <loaction></loaction>

    </div>

</template>

<script>

import loaction from "../components/loaction.vue";

export default {

    components: {

        loaction

    }

};

</script>

location.vue:

<template>

    <div>

        <h5>孙组件接受参数</h5>

        <div>祖父组件定义provide,孙组件inject接受:{{location}}</div>

    </div>

</template>

<script>

export default {

    inject: ["location", "geolocation"]

};

</script>

点击fn,不能改变location.vue的值,就是没有响应的效果

没有办法 双向绑定

2. 组合api  (重点)

<template>

    <div>

        <div>祖父组件:{{location}}</div>

        <button @click="fn">改变location的值</button>

        <br />

        <br />

        <div>双向数据绑定:</div>

        姓名 {{username}}:

        <input v-model="username" />

        <provides></provides>

    </div>

</template>

 

<script>

import { ref, provide, reactive, toRefs } from "vue";

 

import provides from "@/views/provide.vue";

export default {

    name: "App",

    components: {

        provides

    },

    setup() {

        let location = ref("传递祖父的参数");

        var userInfos = reactive({

            username: "张三",

            age: 20

        });

        let fn = () => {

            location.value = "改变值";

        };

        provide("location", location);

        provide("userInfos", userInfos);

        return {

            location,

            fn,

            ...toRefs(userInfos)

        };

    }

};

</script>

provides:

<template>

    <div>

        <h2>Provide / Inject</h2>

        <loaction></loaction>

    </div>

</template>

 

<script>

import loaction from "../components/loaction.vue";

export default {

    components: {

        loaction

    }

};

</script>

 

<style>

</style>

location.vue:

<template>

    <div>

        <h5>孙组件接受参数</h5>

        <div>1.祖父组件定义provide,孙组件inject接受:{{location}}</div>

        <p>用户信息: {{userInfos.username}}</p>

        <br />

        <br />

        <div>2.provide inject实现父子组件传值的时候,子组件改变数据也会影响父组件</div>

        <br />姓名:

        <input v-model="userInfos.username" />

    </div>

</template>

<script>

import { ref, inject } from "vue";

export default {

    setup() {

        let location = inject("location");

        let userInfos = inject("userInfos");

        return {

            location,

            userInfos

        };

    }

};

</script>

 

3. 总结:

1.祖父组件定义provide,孙组件inject接受

2.provide inject实现父子组件传值的时候,子组件改变数据也会影响父组件
 

4. 不想子组件改变父组件的数据

最后,如果要确保通过 provide 传递的数据不会被 inject 的组件更改,我们建议对提供者的 property 使用 readonly

provide("userInfos", readonly(userInfos));

二.响应性

(1)比较vue2 和 vue3 响应式

1. vue2 的响应式:

核心:

对象:通过defineProperty对对象的已有属性值的读取和修改进行劫持(监视、拦截)

数组:通过重写数组更新数组一系列更新元素的方法实现元素修改的劫持【简单的理解:普通数组变成响应数组,对一个数组的元素进行更改的话,它会对这个更改的方法进行重新编写】

object.defineProperty(data,'count',{

    get(){},

    set(){}

})

问题:

1). 对象直接新添加的属性或删除已有属性,界面不会自动更新

2). 直接通过下标替换元素或更新length,界面不会自动更新 arr[1] ={}

所以后面才有$set,去响应数据

  

  <div>

        <div v-for="(key,val,index) in user" :key="index">{{key}}:{{val}}</div>

        <button @click="add">修改数据</button>

    </div>

 

    //因为vue2 是通过object.defineProperty 来操作数据,所以不能检测数据的变动(虽然打印出来的数据是更新的,但是界面的数据没更新)

    export default {

        data() {

            return {

                user: {

                    name: "王一博",

                    age: 20

                }

            };

        },

        methods: {

            add() {

                this.user.sex = "男";

                console.log( this.user);

            }

        }

    };

  注意同样的代码在vue3 里面就可以。不旦数据更新,界面也更新。原因是vue3使用prory

2.vue3 的响应式:

核心:

1).通过proxy(代理):拦截对data任意属性的任意(13种)操作,包括属性值的读写,属性的添加,属性的删除等

2).通过reflect(反射):动态对被代理对象的相应属性进行特定的操作

(2) 什么是响应式

    响应性是一种允许我们以声明式的方式去适应变化的一种编程范例。

简单的理解:对对象进行修改,对象数据会改变,界面上也会发生改变

(3)深入vue3响应性原理

就是把目标对象变成代理对象(prory),然后通过代理对象对数据进行操作,通过reflect在反射回来。

let user = {

            name: "王一博",

            age: 20,

            words: {

                adds: "g区18号",

                tell: "1727283848744",

                cars: ["宝马", "奥迪", "本田"]

            }

        };

        // 把目标对象变成代理 对象

        // 使用prory 从new Proxy开始接受2个参数

        // 参数1:target目标对象----》 user

        // 参数2:Handel 处理器对象,用来监视数据及数据操作----》{}

        const proxyUser = new Proxy(user, {

            // 获取目标对象的某个属性值

            //target目标对象。property被获取的属性名。

            get(target, prop) {

                console.log("get方法调用了");

                return Reflect.get(target, prop);

            },

            // 修改、添加目标对象的属性

            //target目标对象。property被获取的属性名 value 值

            set(target, prop, value) {

                console.log("set方法调用了");

                return Reflect.set(target, prop, value);

            },

            // 删除目标对象的某个属性值

            //target目标对象。property被获取的属性名

            deleteProperty(target, prop) {

                console.log("delete方法调用了");

                return Reflect.deleteProperty(target, prop);

            }

        });

        // 通过代理对象获取目标对象中的某个属性值

        console.log(proxyUser.name);

        // 通过代理对象更新目标对象上的某个属性值

        proxyUser.name = "肖战";

        console.log("修改属性值:", user);

        //通过代理对象向目标对象添加一个新的属性

        proxyUser.sex = "男";

        console.log("添加新属性:", user);

        //通过代理对象删除目标对象的某个属性值

        delete proxyUser.age;

        console.log("删除age 后:", user);

        //深度的添加属性值

        proxyUser.words.name = "航天信息";

        console.log("深度的添加属性值:", user);

(4)什么是prory

proxy 是一个对象,可以代理一个对象或函数,允许拦截被代理的对象或函数

(5) Reflect 

reflect

三.有意思的Teleport

官网

teleport 是vue3 内置组件,接受2个函数(to:指定将在其中移动 <teleport> 内容的目标元素 如:body,.home ,#home;disabled :禁止使用该功能)

请注意,这将移动实际的 DOM 节点,而不是被销毁和重新创建,并且它还将保持任何组件实例的活动状态。所有有状态的 HTML 元素 (即播放的视频) 都将保持其状态。

核心就是to的操作

<template>
	<div style="position: relative;">
		<h3>Tooltips with Vue 3 Teleport</h3>
		<div>
			<modal-button></modal-button>
		</div>
	</div>
</template>

<script>
import Vue from "vue";
var modalButton = {
	template: `
                <button @click="modalOpen = true">
                    打开弹窗
                </button>
				<teleport to="body">
                <div v-if="modalOpen" class="modal">
                <div>
                    I'm a modal!
                    <button @click="modalOpen = false">
                    Close
                    </button>
                </div>
				</div>
				</teleport>
            `,
	data() {
		return {
			modalOpen: false
		};
	}
};
export default {
	components: {
		"modal-button": modalButton
	},
	created() {}
};
</script>

<style>
.modal {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	background-color: rgba(0, 0, 0, 0.5);
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.modal div {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	background-color: white;
	width: 300px;
	height: 300px;
	padding: 5px;
}
</style>

四.VueConf 2021 

1.视频

2.尤雨溪:做技术哪有什么两全之策,都是取舍和平衡

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值