vue3笔记

vue3笔记

vue3官网
尚硅谷视频
黑马视频


在这里插入图片描述


## vue3的main.js
1.vue3
import { createApp } from 'vue' // 引入createApp方法
import App from './App.vue' // 引入App根组件
createApp(App).mount('#app')  // 创建一个 Vue 实例,并将其挂载到 id 为 "app" 的 DOM 元素上2.vue2
import Vue from 'vue' // 引入vue
import App from './App.vue' // 引入App根组件
// 创建一个 Vue 实例,并在创建时指定根组件的渲染函数,然后将该实例挂载到 id 为 "app" 的 DOM 元素上
new Vue({render: h => h(App),
}).$mount('#app')3.render函数
render: function (createElement) {return createElement(App);
}
↓ 对象的增强写法render (createElement) {return createElement(App);
}
↓ createElement 简写成 h
render (h){return h(App);
}
↓ 箭头函数
render: h => h(App);createElement 函数是 Vue.js 的渲染函数中常用的一个函数,用于创建虚拟 DOM 元素,要有return返回值。
/ createElement 函数的第一个参数:标签名或组件选项,可以是 HTML 标签名字符串,表示创建普通的 HTML 元素,也可以是组件的选项对象,表示创建一个组件实例。/import App from './App'
new Vue({el: '#app',render: h => h(App)
})
↓ 等价与
import App from './App'
new Vue({el: '#app',template: '<App></App>',components: {App 
}
})
上面两种的效果是一样的,可以看出 h(App)函数 的作用是:使用App作为这个Vue实例的template,同时一并了注册App组件;

在这里插入图片描述
Vue3 模板结构可以不使用根标签

<template><img alt="Vue logo" src="./assets/logo.png"><HelloWorld msg="Welcome to Your Vue.js App"/><div> hello vue3 </div>
</template>

Vue3 引入组件后,可以再模板中直接使用

<template><ReactiveDemo /><ComputedDemo />
</template><script setup>
import ReactiveDemo from '@/components/ReactiveDemo.vue'
import ComputedDemo from '@/components/ComputedDemo.vue'
</script>

Composition API (组合式api)

选项式API和组合式API的区别:

1.vue2 选项式API(Options API)
<script>
export default {// data() 返回的属性将会成为响应式的状态,并且暴露在this上data() {return {count: 0}},// methods 是一些用来更改状态与触发更新的函数
,它们可以在模板中作为事件监听器绑定methods: {increment() {this.count++}},// 生命周期钩子会在组件生命周期的各个不同阶段被调用mounted() {console.log('通常项目中初始化在这里调接口')}
}
</script>2.vue3 组合式API(Composition API)
<script>
import { ref, computed, onMounted } from 'vue'
export default {setup () {// 定义变量const count = ref(1)// 定义计算属性const doubleCount = computed(() => {return count.value * 2})// 定义方法const changeCount = () => {count.value = 100}// 生命周期函数onMounted(() => {console.log(count.value, 'onMounted')})// 统一将变量和方法等暴露出去return {count, doubleCount, changeCount}},
}
</script>
  • 选项式 API可以用包含多个选项的对象来描述组件的逻辑,例如 data、methods 和 mounted。
  • 选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例;
  • 选项式 API 以“组件实例”的概念为中心 (即 this);
  • 组合式 API可以使用导入的 API 函数来描述组件逻辑; <script setup>中的导入和顶层变量/函数都能够在模板中直接使用;
  • 组合式 API 的核心思想是直接在函数作用域内定义响应式状态变量,并将从多个函数中得到的状态组合起来处理复杂问题;

setup函数

<template><div id="app"><p>名字:{{ name }}</p><p>年龄:{{ age }}</p><p><button @click="sayHello">弹框</button></p></div>
</template><script>
export default {name: "App",// setup是一个函数,有返回值setup() {// 定义数据let name = "张三";let age = 18;// 定义方法function sayHello() {alert(`我是${name},我今年${age},你好啊!`); // 使用不需要用this,因为this是undefined,函数作用域;}/ setup函数的返回值是一个对象, 返回值可以直接在模板中使用,不需要点;/return { name, age, sayHello }}
};
</script>
  • setup是一个函数,有返回值,返回值是一个对象可以直接在模板中使用;
  • 在setup函数中定义的东西,一定要return出去,才能被使用;
  • 组件中所用到的:数据、方法等等,均要配置在setup函数中;
  • setup 中不能使用 this;
  • setup 默认情况下不能使用async/await;
  • 在beforcreatd前执行, 所以this是undefined,所以vue3中没有this;

setup函数的参数

在这里插入图片描述
props对象:

  • 父组件传递过来的所有prop数据,要在组件中的props中接收;
  • 不接收,则存在context对象的attrs中;
  • 它是响应式的,它不能解构,一但解构,结构出的变量会丢失响应式;
1.解构了 props 对象,解构出的变量将会丢失响应性,推荐通过 props.xxx 的形式来使用其中的 props。
export default {props: {title: String},setup(props) {  // 通过 props.xxx 的形式来使用其中的 props。  console.log(props.title)}
}
2.必须解构 props 对象,或者需要将某个 prop 传到一个外部函数中并保持响应性,那么可以使用 toRefs()toRef() 这两个工具函数。
import { toRefs, toRef } from 'vue'export default {setup(props) {// 将 `props` 转为一个其中全是 ref 的对象,然后解构const { title } = toRefs(props)// `title` 是一个追踪着 `props.title` 的 refconsole.log(title.value)// 或者,将 `props` 的单个属性转为一个 refconst title = toRef(props, 'title')}
}
contex上下文对象:
包含了attrs,slots,emit,expose;
emit可以触发自定义事件的执行从而完成子传父通信;
该上下文对象是非响应式的,可以安全地解构;
attrs:一个对象,父组件传递给过来的非 props 属性对象,即未在props中接收的属性。
slots:一个函数,用于访问组件的插槽内容。
emit:一个用于触发自定义事件的函数。
expose:一个用于暴露组件的公共 API 的函数。
export default {setup(props, context) {// 透传 Attributes(非响应式的对象,等价于 $attrs)console.log(context.attrs)// 插槽(非响应式的对象,等价于 $slots)console.log(context.slots)// 触发事件(函数,等价于 $emit),子传父通信;console.log(context.emit)// 暴露公共属性(函数)console.log(context.expose)}
}

contex上下文对象:

  • 包含了attrs,slots,emit,expose;
  • emit可以触发自定义事件的执行从而完成子传父通信;
  • 该上下文对象是非响应式的,可以安全地解构;
attrs:一个对象,父组件传递给过来的非 props 属性对象,即未在props中接收的属性。
slots:一个函数,用于访问组件的插槽内容。
emit:一个用于触发自定义事件的函数。
expose:一个用于暴露组件的公共 API 的函数。
export default {setup(props, context) {// 透传 Attributes(非响应式的对象,等价于 $attrs)console.log(context.attrs)// 插槽(非响应式的对象,等价于 $slots)console.log(context.slots)// 触发事件(函数,等价于 $emit),子传父通信;console.log(context.emit)// 暴露公共属性(函数)console.log(context.expose)}
}

expose

  • 通过expose方法,可以将数据和方法从组件的内部暴露给组件的使用者。这样,外部的组件就可以直接访问该组件的实例时,访问这些数据或调用这些方法。
  • 要使用expose方法,你需要在expose函数中调用它,并传入一个对象作为参数。该对象中的键值对定义了要暴露的属性或方法。
setup() {// 定义要暴露的属性和方法const myValue = ref(42);const myMethod = () => {console.log("Hello from myMethod!");};// 让组件实例处于`关闭状态`,即不向父组件暴露任何东西expose()// 让组件实例处于`开启状态`,可以有选择性的向父组件暴露,本组件的属性或方法expose({myMethod});}

setup语法糖

在这里插入图片描述

<script setup>
import { ref, onMounted } from 'vue'// 响应式状态
const count = ref(0)// 用来修改状态、触发更新的函数
function increment() {count.value++
}// 生命周期钩子
onMounted(() => {console.log(`计数器初始值为 ${count.value}`)
})
</script>

- setup语法糖,不用在return变量和函数了,在模板中可以直接使用;
- script标签添加setup, 省略 export default{ };


ref函数

  • import { ref } from “vue”; 从vue中引入ref函数;
  • 作用:定义响应式的数据; (多用于基本数据类型)
  • 语法: const xxx = ref (数据)
  • 创建一个包含响应式数据的引用对象,(reference对象,简称ref对象)
  • 模板中使用不需要 .value;
  • js操作需要 .value;
  • 接收的数据可以是:基本类型、也可以是对象类型。
  • 基本类型的数据:响应式依然是靠Object.defineProperty()的get与set完成的数据劫持。
  • 对象类型的数据:内部通过reactive函数实现的。
    在这里插入图片描述
    在这里插入图片描述
<template><div id="app"><p>名字:{{ name }}</p><p>年龄:{{ age }}</p><p>工作: {{job.type}}</p> //模板中使用不需要.value<p><button @click="changeInfo">改变</button></p></div>
</template><script>
import { ref } from "vue"; // 引入ref函数
export default {name: "App",setup() {// 定义基本数据类型let name = ref("张三");let age = ref(18);// 定义引用数据类型let job = ref({ type: "前端工程师" });// 定义修改ref定义的响应式数据的方法function changeInfo() {// 基本数据类型name.value = "李四";age.value = 28;// 引用数据类型job.value.type = "后端工程师";}return { name, age, job, changeInfo};},
};
</script>

reactive函数

  • import { reactive } from “vue”; 从vue中引入reactive函数;
  • 作用: 定义一个对象或数组类型的响应式数据;(基本类型不要用它,要用ref函数);
    - 语法:const xxx = reactive(源对象);
    接收一个对象或数组,返回一个代理对象(Proxy的实例对象,简称proxy对象);
  • reactive定义的响应式数据是“深层次的”。
  • 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。
  • js和html中不需要 .value
    在这里插入图片描述
<template><div id="app"><p>名字:{{ person.name }}</p><p>工作: {{ person.job.type }}</p><p><button @click="changeInfo">改变</button></p></div>
</template><script>
import { reactive } from "vue"; // 引入reactive函数
export default {name: "App",setup() {// 通过reactive函数定义对象或数组;let person = reactive({name: "张三",job: {type: "前端工程师",},});// 定义方法function changeInfo() {// 修改不需要.valueperson.name = "赵四";person.job.type = "后端工程师";}return { person, changeInfo }},
};
</script>

ref与reactive对比

在这里插入图片描述
reactive和ref的区别:

  • reactive和ref都是vue3中提供的响应式API,都用于定义响应式数据的;
  • reactive通常用于定义引用数据类型,其本质是基于 Proxy 实现对象代理,所以reactive不能用于定义基本类型数据;
  • ref通常是用于定义基本数据类型,其本质是基于 Object.defineProperty() 重新定义属性的方式实现;

vue2、vue3响应式

  • Proxy
  • Reflect
  • vue3中使用proxy 实现的数据响应式,避免了vue2中不能检测到,对象添加、删除属性和数组通过下标修改元素而无法被检测的问题;
    在这里插入图片描述
    在这里插入图片描述

computed函数

  • computed(箭头函数) ,只获取,参数是一个函数,依靠返回值;
  • computed( { } ),获取和设置,get(){ },set(){ },依靠返回值;set方法的参数是要设置的新属性值;
<!-- 只读取计算属性 -->
<template><div id="app"><p>: <input type="text" v-model="person.xing" /> </p><p>: <input type="text" v-model="person.ming" /> </p><p>姓名: {{ fullName }}</p> // 使用计算属性<p>姓名: {{ person.fullName }}</p> // 计算属性直接追加到person对象上使用</div>
</template><script>
import { reactive, computed } from "vue";
export default {name: "App",setup() {// reactive函数;let person = reactive({xing: "",ming: "",});// 计算属性 fullName, computed函数的参数可以是一个函数, 依靠返回值let fullName = computed(() => {return person.xing + person.ming;});
/直接把计算属性追加到person响应式对象上,直接返回person对象  person.fullName = computed(() => person.xing + person.ming ) /// 返回值return {person,fullName, // 返回计算属性};},
};
</script>

修改计算属性

    <!-- 获取和修改计算属性 --><p>姓名: <input type="text" v-model="fullName" /></p>import { reactive, computed } from "vue"; //引入computed函数// 完整的计算属性, 获取和修改, get+setperson.fullName = computed({get(){return person.firstName + '-' + person.lastName},set(value){ // value是input输入框的新值const nameArr = value.split('-')person.firstName = nameArr[0]person.lastName = nameArr[1]}
})

watch函数

  • watch(参数1,参数2,参数3);
  • wantch( 监视的属性, 处理函数, { immediate:true, deep:true } );
  • 参数1:一个变量,监视单个数据;一个数组,监视多个数据 [ xx, xxx ];一个箭头函数,依靠返回值,精确监视对象某个属性
  • 参数2:一个函数,对监视数据的处理函数;
  • 参数3:一个对象,是否开启深度监视,是否一进入页面就监视 ( 默认immediate:false);
  • 监视reactive定义的响应式数据,1. 不能获取oldValue,oldValue和newValue一致;2. 强制开启了deep:true,设置deep:false无效;
  • ref定义的值类型, 监视不需要.value;
  • ref定义的引用数据类型, 监视需要.value,等价与监视reactive定义的对象(情况三):1.无法获取oldvalue;2.
    newvalue和oldvalue一致;3. 强制开启了deep:true;4. 设置deep:false也无效。
  • ref定义的引用数据类型, 监视不使用 .value,可以使用 deep:true;1.无法获取oldvalue;2.
    newvalue和oldvalue一致;
/ 情况一:监视ref定义的一个响应式数据 /
watch(sum, (newValue, oldValue) => {console.log('sum变化了', newValue, oldValue)
}, { immediate:true })/ 情况二:监视多个ref定义的响应式数据 /
监视的数据都放到一个数组中;newVal和oldVal返回的也是数组形式。watch([sum,msg],(newValue,oldValue)=>{console.log('sum或msg变化了',newValue,oldValue)
}) / 情况三:监视reactive定义的响应式数据 /1. 无法正确获得oldValue;2. oldValue和newValue一致;3. 
强制开启了深度监视deep:true4. 设置deep:false也无效;watch(person, (newValue, oldValue)=>{console.log('person变化了', newValue, oldValue)     // newValue === oldValue;  true
}, { immediate:true, deep:false }) //此处的deep配置不再奏效/  情况四:监视reactive定义的响应式数据中的某一个属性 /1. 箭头函数,依靠返回值;2. 可以获取新值,旧值; 3. 设置deep有效;watch(() => person.job, (newValue,oldValue) => {console.log('person的job变化了', newValue, oldValue)
}, { immediate:true, deep:true }) / 情况五:监视reactive定义的响应式数据中的多个属性 /1. 放到一个数组中, 箭头函数依靠返回值;2. 可以获取新值,旧值; 3. 设置deep有效; 4.newVal和oldVal返回的也是数组形式。watch([ () => person.job, () => person.name ], (newValue,oldValue) => {console.log('person的job变化了', newValue,oldVal ue)
}, { immediate:true,deep:true })/ 特殊情况:监视的是reactive定义的对象中的某个对象,即对象嵌套的比较深 /1. 开启deep:true才能监测到变化;2. 可以设置deep:false3. 无法获取oldVal,newVal和oldValue一致;
const person = reactive({name: '张三',age: 18,obj: {salaray: {money: 10000}}
})watch(() => person.job, (newValue,oldValue) => {console.log('person的job变化了', newValue, oldValue)  // newValue === oldValue;  true}, { deep:true }) // 设置deep:tue或false有效;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

watchEffect函数

  • watchEffect ( 监视的回调函数 )
  • 不需要指定监视某个属性, 回调函数中用到那个属性就会监视那个属性;
watch:既要指明监视的属性,也要指明监视的回调。
watchEffect:不用指明监视哪个属性,监视的回调函数中用到哪个属性,那就监视哪个属性。
watchEffect有点类似于computed:但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。watchEffect(()=>{const x1 = sum.value // 用到了sum,就监视person;const x2 = person.age // 用到了person,就监视person;console.log('watchEffect配置的回调执行了')
})

Vue3生命周期

在这里插入图片描述
在这里插入图片描述
vue3.0的生命周期:

  • 除了setup,其他的要加on;
  • beforeDestroy 改名为 beforeUnmount;;
  • destroyed 改名为 unmounted;
  • beforeCreate和created 改为 setup;
  • 其他的生命周期以组合式API的形式写在setup函数中;
  • 写成调用函数的形式,参数是一个箭头函数;
  • 从vue中引入的生命周期是一个函数,传入一个函数代表执行函数;

父子生命周期执行顺序:

  • 挂载阶段

父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted

  • 更新阶段

父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated

  • 销毁阶段

父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

Vue3生命周期
beforeCreate  -> setup()
created       -> setup() 开始创建组件之前,在beforeCreate和created之前执行,创建的是data和method。
beforeMount   -> onBeforeMount() 组件挂载到节点上之前执行的函数。
mounted       -> onMounted() 组件挂载完成后执行的函数。
beforeUpdate  -> onBeforeUpdate() 组件更新之前执行的函数。
updated       -> onUpdated() 组件更新完成之后执行的函数。
beforeUnmount -> onBeforeUnmount() 组件卸载之前执行的函数。
unmounted     -> onUnmounted() 组件卸载完成后执行的函数keepalive专属 - 被包含在<keep-alive>中的组件,因为生命周期函数不再执行,会多出两个生命周期钩子函数。
activated     -> onActivated() 被激活时执行,刚进入页面时执行。
deactivated   -> onDeactivated() 失活时执行,比如从 A 组件,切换到 B 组件,A 组件消失时执行。捕获异常 - 用于捕获组件中未处理的 JavaScript 错误
errorCaptured -> onErrorCaptured(error,vm) 当捕获一个来自子孙组件的异常时激活钩子函数。
当组件中出现 JavaScript 错误时,这个错误会沿着组件树向上冒泡直到根组件,如果任何一个组件中定义了 onErrorCaptured 钩子函数,则会调用该函数来捕获错误。
这个钩子函数接收两个参数:error 和 vm。
error: 表示捕获到的 JavaScript 错误对象。
vm: 传递给该钩子函数的组件实例对象,可以通过它来访问到组件的状态和属性。在 DOM 更新之后执行回调函数 - 作用是等待当前 DOM 更新队列中的所有同步和异步更新完成后,再执行传入的回调函数。1.等待当前 DOM 更新队列中的所有同步和异步更新完成后执行回调函数。2.用于确保在 DOM 更新之后执行操作,例如获取更新后的 DOM 元素。
await nextTick()
DOM 更新后执行的操作xxx

hook函数

  • 本质是一个函数,把setup函数中使用的Composition API进行了封装。
  • 类似于vue2.x中的mixin。
  • 自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。

toRef、toRefs函数

toRef: 将一个响应式状态或其他可响应式对象转换为一个只读的 ref 对象。

  • toRef( 对象 , '属性名' )
  • 语法:const refObj = toRef( sourceObj, key )
  • sourceObj 是一个响应式状态对象或其他可响应式对象。
  • key 是sourceObj 中一个已存在的属性名,指定要创建引用的属性。
  • toRef 返回一个 ref 对象,该对象具有以下特性:
    1. 当sourceObj的ke属性发生变化时,ref 对象也会相应地变化。
    2. refObj引用对象是只读的,无法直接修改其值。如果需要修改,可以通过修改 sourceObj 中的对应属性来实现。
    torefs:将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。
    toRefs( '对象' )
    语法:toRefs(person)
  • 可以解构使用,不会失去响应式;
  • 通过使用toRefs,可以将响应式对象的属性解构为独立的普通变量,并在模板或其他逻辑中使用它们,同时保持其响应式特性。
  • 扩展:toRefs 与toRef功能一致,但可以批量创建多个 ref 对象。
<template><div><p>person:{{ person }}</p><p>姓名: {{ name }}</p><p>年龄: {{ age }}</p><p>工资: {{ salary }}</p><button @click="name += '三'">姓名++</button><button @click="age++">年龄++</button><button @click="salary++">工资++</button></div>
</template><script>
import { reactive, toRef, toRefs } from "vue"; // 引入 toRef, toRefs函数
export default {name: "App",setup() {let person = reactive({name: "张三",age: 18,job: {type: "前端程序员",salary: 15,},});return {person, // 响应式的person对象name: toRef(person, "name"), // 将响应式对象中的某个属性单独提供给外部使用时。age: toRef(person, "age"),salary: toRef(person.job, "salary"),/ ...toRefs(person)    解构toRefs函数处理的数据,name,age,job;把整个响应式的person对象解构出来的属性,都暴露给外边使用,也不会失去响应式; /};},
};
</script>

shallowReactive函数 与 shallowRef 函数

shallow:浅的,浅层次的;

  • shallowReactive:只处理对象第一层属性的响应式(浅响应式)。
  • shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。
  • 什么时候使用?
    1. 如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive。
    2. 如果有一个对象数据,只读它的属性,或后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef。

eadonly函数 与 shallowReadonly函数

  • readonly:让一个响应式数据变为只读的(深只读)。
  • shallowReadonly:让一个响应式数据变为只读的(浅只读, 只有第一层可读, 深层次的可以修改)。
  • 应用场景: 不希望数据被修改时。
    let person = reactive({name: "张三",age: 18,job: {type: "前端程序员",salary: 15,},});person = readonly(person) // 整个person对象只读person = shallowReadonly(person) // 只有person对象第一层只读name,age;深层次job对象中的数据可以修改

toRaw函数 与 markRaw函数

raw:未加工的,原始的;mark:标记,记号;
toRaw:

  • 作用:将一个由reactive生成的响应式对象转为普通对象。
  • 使用 toRaw,可以获取到原始的非响应式对象,使其不受代理的影响。
  • 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。

markRaw:

  • 作用:标记一个响应式的对象,使其永远失去响应式。
  • 使用 markRaw 可以将对象标记为非响应式,从而避免其被 Vue 的响应式系统追踪和观察。 应用场景:
    1. 有些值不应被设置为响应式的,例如复杂的第三方类库等。
    2. 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。

customRef函数

custom:自定义;track:追踪;trigger:触发;delay:延迟;

  • 自定义ref函数,返回的ref对象是响应式的;
  • customRef( 箭头函数 );
  • 箭头函数的参数:参数1:track函数;参数2:trigger函数;
    1. track( ):追踪依赖数据的变化;
    2. trigger( ):触发更新;
  • 箭头函数需要返回 get函数和set函数;
    1. get函数,用于获取 ref 的当前值。在读取 ref.value 时会调用该函数。
    2. set函数,用于设置 ref 的新值。在给 ref.value 赋值时会调用该函数。
  • customRef 允许我们创建一个定制化的 ref,可以自定义其读取和修改的行为。
  • 作用:创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。
import { customRef } from 'vue'const myCustomRef = customRef((track, trigger) => {// 定义初始值let value = 0// 定义增加初始值的方法const increment = () => {value++trigger() // 触发更新}// 定义减少初始值的方法const decrement = () => {value--trigger() // 触发更新}// 返回get和set方法,返回increment方法和decrement方法;return {get() {track() // 追踪依赖的数据,value;return value},set(newValue) {value = newValuetrigger() // 触发更新},increment,decrement}
})const count = myCustomRef.valueconsole.log(count) // 0myCustomRef.increment()
console.log(count) // 1myCustomRef.decrement()
console.log(count) // 0myCustomRef.value = 5
console.log(count) // 5

vue3父子通信

defineProps 和 defineEmits 都是只能在 <script setup> 中使用的编译器宏;
不需要导入,且会随着 <script setup> 的处理过程一同被编译掉。

// 父组件
<template><div>父组件:{{ count }}</div><hr /><Son :count="count" @cutomFn="Fn" /> // 传递自定义属性,传递自定义事件;
</template><script setup>
import { ref } from 'vue'
import Son from '@/components/Son.vue'
const count = ref(100)
// 自定义事件的处理函数,val参数就是子组件传递过来的值;
const Fn = (val) => {count.value = val
}
---------------------------------------------------------------------------
// 子组件
<template><div>子组件:{{ count }}</div><button @click="emitCustomFn">改变</button>
</template><script setup>
// 接收父组件传递过来的自定义属性; { }
const props = defineProps({count: {type: Number,}
})
// 接收父组件传递过来的,要触发的自定义事件;[ '要触发的自定义事件名' ]
const emit = defineEmits(['cutomFn']) 
// 触发自定义事件,并传值
const emitCustomFn = () => {emit('cutomFn', props.count + 1) // props.xxx
}
</script>
  • 父传子

    • 通过defineProps()函数来配置props选项,接收父组件传递的数据;
    • const props = defineProps( { } )
    • props接收到传递过来的值后,可以再模板中直接使用;但是再js中使用需要 props.xxx ;
      在这里插入图片描述
  • 子传父

    • 通过defineEmits()函数来配置props选项,接收父组件传递的数据;
    • const emit = defineEmits( [ '自定义事件名' ] ) // 数组内,事件名加引号;
      在这里插入图片描述

provide和inject 依赖注入

在这里插入图片描述

  • 实现祖孙组件间的通信;
  • provide 提供数据;==> provide( “数据名”, 传递的数据);
  • inject 接收数据;inject( “数据名” );

作用:实现祖孙组件之间通信 (跨级通信)
过程:祖先组件有一个 provide 选项来提供数据,后代组件有一个 inject 选项来开始接收数据。

祖先组件中:
import { provide } from 'vuesetup(){......let car = reactive({name:'奔驰',price:'40万'})provide('car',car)......
}后代组件中:
import { inject } from 'vue
setup(props,context){......const car = inject('car')return {car}......
}

模板引用ref

  • 通过ref标识获取真实dom对象或组件实例对象;
  • 要mounted中使用;
    • 调用ref函数生成一个ref对象;
    • 通过ref标识绑定ref对象到标签;

给dom绑定ref

<template><div ref="divRef">App</div>  // 3. 给dom绑定ref
</template><script setup>
import { ref } from 'vue' // 1. 引入ref函数
const divRef = ref(null) // 2. 创建divRef变量,并赋值为null
</script>

给组件绑定ref

/ 父组件 / 
<template><Ref ref="sonRef" /> //  3. 给组件绑定ref
</template><script setup>
import Ref from './components/ref.vue' // 引入组件
import { ref, onMounted } from 'vue' // 1. 引入ref和onMounted函数
const sonRef = ref(null) // 2. 创建sonRef变量,赋值为null
// 5. 在父组件的mounted中使用子组件的属性和方法
onMounted(() => {console.log(sonRef.value.count)sonRef.value.sayHello()
})
</script>/ 子组件 /
<template><div>Son组件</div>
</template><script setup>
import { ref } from 'vue'
const count = ref(100)
const sayHello = () => {console.log('hello')
}
// 4. 通过defineExpose方法暴露出去该组件的属性和方法
defineExpose({count,sayHello
})
</script>

defineExpose()

  • defineExpose( { } );
  • 默认情况下在<script setup>语法糖下组件内部的属性和方法是不开放给父组件访问的,是关闭的;
  • 可以通过defineExpose编译宏指定哪些属性和方法允许访问;
  • 作用:用于暴露组件的内部方法和属性给父组件使用。

defineOptions

  • 用来定义 Options API 的选项;
  • 用来直接在 <script setup> 中声明组件选项,而不必使用单独的 <script> 块;
  • 仅支持vue3.3+;
defineOptions({name: 'Son' // 组件名
})

判断响应式数据的方法

  • import { isRef,isReactive,isReadonly,isProxy } from ‘vue’
  • 返回的都是布尔值;
  • isRef:检查一个值是否为一个 ref 对象;
  • isReactive:检查一个对象是否是由 reactive 创建的响应式代理;
  • isReadonly:检查一个对象是否是由 readonly 创建的只读代理;
  • isProxy:检查一个对象是否是由 reactive 或者 readonly 方法创建的代理;

新组件

Fragment 标签

fragment:碎片,片段;

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

Teleport 标签

fragment:传送;

  • 将组件的内容渲染到指定的位置;
  • to属性: 选择器;
  • 在组件的模板中定义的某个位置,将内容渲染到 DOM 中的其他位置。
  • 在遵循组件嵌套规则的情况下,将内容渲染到组件树之外的地方,例如 <body> 元素之下。
<button @click="isShow = true">点击弹窗</button>
<teleport to="body"><div v-if="isShow" class="mask"><div class="dialog"><h3>我是一个弹窗</h3><button @click="isShow = false">关闭弹窗</button></div></div>
</teleport>

Suspense标签

suspense:悬念;

  • 异步依赖。
  • <Suspense> 组件有两个插槽:#default 和 #fallback。
  • 用于处理异步组件的加载状态和错误处理;
  • 等待异步组件时渲染一些额外内容,让应用有更好的用户体验。
方法1通过defineAsyncComponent(() => import('路径'))import {defineAsyncComponent} from 'vue' // 引入定义异步组件的函数
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
import() // 异步引入方法2:使用Suspense包裹组件,通过插槽,配置好 #default 与 #fallback;
<template>    	<Suspense><template #default><h1>这是异步组件的内容...</h1>	</template><template #fallback><h1>异步组件正在加载中...</h1>	    </template></Suspense></template>#default 插槽用于显示异步组件加载完成后的内容,即 <h1>这是异步组件的内容</h1>。
#fallback 插槽用于显示异步组件加载过程中的占位符,即 <h1>异步组件正在加载中...</h1>/ 当异步组件加载过程中,<Suspense> 组件会显示 #fallback 插槽中的内容,待异步组件加载完成后,会切换到显示 #default 插槽中的内容。/

其他

全局API的转移

  • Vue 2.x 有许多全局 API 和配置
    • 例如:注册全局组件、注册全局指令等;
//注册全局组件
Vue.component('MyButton', {data: () => ({count: 0}),template: '<button @click="count++">Clicked {{ count }} times.</button>'
})//注册全局指令
Vue.directive('focus', {inserted: el => el.focus()
}
  • Vue3.0中对这些API做出了调整:
    • 将Vue.xxx调整到应用实例(app)上;
      在这里插入图片描述

其他改变

  • data选项应始终被声明为一个函数。
  • 移除键盘事件的keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes;
  • 移除v-on.native修饰符,可以直接给组件绑定原生事件;
  • 移除过滤器 filter;
    • 过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设!
    • 建议用方法调用或计算属性去替换过滤器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/128050.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

静态工厂模式,抽象工厂模式,建造者模式

静态工厂模式 ublic class FruitFactory {public static Fruit getFruit(String name) {Fruit fnull;switch (name){case "APPLE":{fnew Apple();}case "BANANA":{fnew Banana();}default :{System.out.println("Unknown Fruit");}}return f;} …

RabbitMQ 知识点解读

1、AMQP 协议 1.1、AMQP 生产者的流转过程 当客户端与Broker 建立连接的时候&#xff0c;会调用factory .newConnection 方法&#xff0c;这个方法会进一步封装成Protocol Header 0-9-1 的报文头发送给Broker &#xff0c;以此通知Broker 本次交互采用的是AMQPO-9-1 协议&…

算法:数组中的最大差值---“打擂台法“

文章来源&#xff1a; https://blog.csdn.net/weixin_45630258/article/details/132737088 欢迎各位大佬指点、三连 1、题目&#xff1a; 给定一个整数数组 nums&#xff0c;找出给定数组中两个数字之间的最大差值。要求&#xff0c;第二个数字必须大于第一个数字。 2、分析特…

【Docker】容器化应用程序的配置管理策略与实践

一、引言 1.1 Docker的背景和优势 Docker是一种开源的容器化平台&#xff0c;简化应用程序的打包、交付和运行过程。基于Linux容器技术&#xff0c;通过提供一个轻量级、可移植和自包含的容器来实现应用程序的隔离和部署。 在传统的应用程序开发和部署中&#xff0c;往往需要…

Vue2项目练手——通用后台管理项目第七节

Vue2项目练手——通用后台管理项目 用户管理分页使用的组件Users.vuemock.js 关键字搜索区Users.vue 权限管理登录页面样式修改Login.vue 登录权限使用token对用户鉴&#xff0c;使用cookie对当前信息保存&#xff08;类似localstorage&#xff09;Login.vuerouter/index.js 登…

pyqt5设置背景图片

PyQt5设置背景图片 1、打开QTDesigner 创建一个UI&#xff0c;camera.ui。 2、创建一个pictures.qrc文件 在ui文件同级目录下先创建一个pictures.txt&#xff0c;填写内容&#xff1a; <RCC><qresource prefix"media"><file>1.jpg</file>…

【Python】conda虚拟环境下使用pyinstaller打包程序为exe

文章目录 一、为什么要用conda虚拟环境二、pyinstaller用法2.1 安装 PyInstaller2.2 基本用法打包一个 Python 脚本2.21 打包一个 Python 项目2.22 打包选项 2.3 打包依赖项2.31 导出依赖项列表2.32 配置依赖项 2.4 自定义打包选项2.5 打包完成后的文件2.6 注意事项 三、打包示…

解决外接显示器后Edge浏览器地址栏等变得很大的问题

解决外接显示器后Edge浏览器地址栏等变得很大的问题 edge设置里外观——触控模式&#xff0c;把触控模式关了

Kafka详解

目录 一、消息系统 1、点对点的消息系统 2、发布-订阅消息系统 二、Apache Kafka 简介 三、Apache Kafka基本原理 3.1 分布式和分区&#xff08;distributed、partitioned&#xff09; 3.2 副本&#xff08;replicated &#xff09; 3.3 整体数据流程 3.4 消息传送机制…

高忆管理:六连板捷荣技术或难扛“华为概念股”大旗

在本钱商场上名不见经传的捷荣技术&#xff08;002855.SZ&#xff09;正扛起“华为概念股”大旗。 9月6日&#xff0c;捷荣技术已拿下第六个连续涨停板&#xff0c;短短七个生意日&#xff0c;股价累积涨幅逾越90%。公司已连发两份股票生意异动公告。 是炒作&#xff0c;还是…

kubernetes常见面试问题详解

在面试的时候&#xff0c;面试官常常会问一些问题&#xff1a; k8s是什么&#xff1f;有什么用?k8s由哪些组件组成&#xff1f;pod的启动流程&#xff1f;k8s里有哪些控制器&#xff1f;k8s的调度器里有哪些调度算法&#xff1f;pod和pod之间的通信过程&#xff1f;外面用户访…

3D视觉测量:形位公差 平面度测量(附源码)

文章目录 0. 测试效果1. 基本内容2. 实现方法3. 代码实现4. 参考文章目录:形位公差测量关键内容:通过视觉方法实现GD&T中的平面度计算0. 测试效果 1. 基本内容 平面度是一个表达平面平整程度的度量指标,它描述了一个表面与一个理想平面之间的偏差程度。在工程和制造领域…

C++之红黑树

红黑树 红黑树的概念红黑树的性质红黑树结点的定义红黑树的插入红黑树的验证红黑树与AVL树的比较 红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上…

[SUCTF2019]SignIn 题解

是一个64位的文件 使用了RSA加密算法 N是103461035900816914121390101299049044413950405173712170434161686539878160984549 使用在线网站分离得到p&#xff0c;q 然后编写脚本进行解密 import gmpy2 import binasciip 282164587459512124844245113950593348271 q 366669…

AI伦理:科技发展中的人性之声

文章目录 AI伦理的关键问题1. 隐私问题2. 公平性问题3. 自主性问题4. 伦理教育问题 隐私问题的拓展分析数据收集和滥用隐私泄露和数据安全 公平性问题的拓展分析历史偏见和算法模型可解释性 自主性问题的拓展分析自主AI决策伦理框架 伦理教育的拓展分析伦理培训 结论 &#x1f…

windows11安装docker时,修改默认安装到C盘

1、修改默认安装到C盘 2、如果之前安装过docker&#xff0c;请删除如下目录&#xff1a;C:\Program Files\Docker 3、在D盘新建目录&#xff1a;D:\Program Files\Docker 4、winr&#xff0c;以管理员权限运行cmd 5、在cmd中执行如下命令&#xff0c;建立软联接&#xff1a; m…

JVM 内存结构

一、程序计数器 1.1 定义 当前线程所执行的字节码的行号指示器&#xff0c;用于记住下一条 jvm 的执行地址。 1.2 特点 1、线程私有 2、不存在内存溢出 二、虚拟机栈 2.1 定义 每个线程运行时所需要的内存&#xff0c;称为虚拟机栈。 2.2 特点 1、每个栈由多个栈帧&#x…

OceanBase 里的 schema 是什么?

李博洋 OceanBase 技术部研发工程师。 OceanBase 开源社区里经常会看到一些类似于 “ schema 是什么” 的疑问&#xff1a; 很多同学经常会误以为在 OceanBase 里&#xff0c;schema 只是 database 的同义词&#xff0c;这次分享就从 schema 是什么这个问题稍微展开聊一下。 首…

【4-5章】Spark编程基础(Python版)

课程资源&#xff1a;&#xff08;林子雨&#xff09;Spark编程基础(Python版)_哔哩哔哩_bilibili 第4章 RDD编程&#xff08;21节&#xff09; Spark生态系统&#xff1a; Spark Core&#xff1a;底层核心&#xff08;RDD编程是针对这个&#xff09;Spark SQL&#xff1a;…

Linux命令200例:mkfs用于创建文件系统

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0…