一、父组件向子组件传值 ref、props
// 父组件
<Son :showDialogVisible="showDialogVisible" />
<script>
import {defineComponent,ref} from 'Vue';
setup(){
const showDialogVisible=ref(true);
return {showDialogVisible}
}
</script>
<script>
// 子组件
import {defineComponent,ref} from 'Vue';
export default defineComponent({
name:"",
props:{showDialogVisible:Boolean},
setup(props){
return {props}
}
})
</script>
二、子组件向父组件传值 emit
子组件中:
由于Vue数据传递时单向数据流,子组件没有权利修改父组件传递过来的数据,只能用emit通知父组件去修改。
<script>
// 子组件
setup(props,context){
context.emit('setShow',false)
return;
}
...或者...
setup(props,{emit}){
emit('setShow',false)
return;
}
</script>
// 父组件
<Son :showDialogVisible="showDialogVisible"
@setShow="setShowDialogVisible" />
<script>
import {defineComponent,ref} from 'Vue';
setup(){
const showDialogVisible=ref(true);
const setShowDialogVisible=(bool)=>{
showDialogVisible=bool;
}
return {showDialogVisible,setShowDialogVisible}
}
三、子组件向父组件传值 v-model
如果子组件向父组件传的值正好是父组件向子组件传的值,可以直接在该属性上进行双向绑定。
// 子组件
// 直接修改从props中拿到的数据;
context.emit('update:showDialogVisible',false)
</script>
// 父组件
<Son v-model:showDialogVisible="showDialogVisible"/>
<script>
四、setup语法糖
在vue2.0时期,组件里定义的各类变量,方法,计算属性等是分别放到data,methods,computed选项里。
setup是vue3.0后推出的语法糖,按需引入computed,watch,directive等,一个业务逻辑可以编写在一起,让代码更加简洁便于浏览。
1、基本用法
<script setup>
console.log('Hello World');
</script>
只需在 < script > 里添加一个setup属性,编译时会把 < script setup> < / script >里的代码编译成一个setup函数。
普通的 < script > 只会在组件被首次引入的时候执行一次,< script setup> 里的代码会在每次组件实例被创建的时候执行。
2、data和methods
< script setup> 里声明的变量和函数,不需要return暴露出去,就可以直接在template使用。
<script setup>
import {ref,reactive} from 'vue';
const msg = "Hello World";//普通变量
// 响应式变量
let num = ref(11); //ref 声明基本变量类型
const obj = reactive({//reactive 声明对象类型变量:Object,Array,Date
key:"this is a object"
})
function getName(){}
</script>
3、计算属性 computed
<script setup>
import {ref,computed} from 'vue';
let num = ref(0);
const countPlus = computed(()=>{
return num.value+1;
})
</script>
4、监听器 watch、watchEffect
// watch
<script setup>
import {ref,reactive,watch} from 'vue';
// 监听ref
let num = ref(0);
watch(num,(newval,oldval)={
// ...
})
// 监听reactive
const obj = reactive({
key:"this is a object"
})
watch(obj.key,(newval,oldval)={
// ...
},{
immediate:true,// 立即执行,默认false
deep:true,//深度监听,默认false
})
const onChange = function () {
num.value++;
obj.key="this change"
}
</script>
watchEffect :Vue3.0新增的监听属性的方法,与watch的区别在于,watchEffect不需要指定监听对象,回调函数里可直接获取到修改后的属性的值。
<script setup>
import {ref,reactive,watchEffect} from 'vue';
let num = ref(0);
const obj = reactive({
key:"this is a object"
})
setTimeout( ()=> {
num.value++;
obj.key="this change"
})
watchEffect((newval,oldval)=>{
console.log("修改后的count",count.value);
console.log("修改后的obj",obj.key);
})
</script>
5、自定义指令 directive
以vNameDirective的形式来命名本地自定义指令,可以直接在模板中使用。
<template>
<h1 v-my-directive>今天的日记</h1>
</template>
<script setup>
// 导入指令可重命名
// import {myDirective as vMyDirective} from './MyDirective.js'
// 自定义指令
const vMyDirective={
beforeMount:(el)=>{
// 元素上做一些操作
}
}
</script>
6、import导入的内容可以直接使用
导入的模快内容,不需要通过method来暴露它;
导入外部组件,不需要通过components注册使用;
7、声明props和emit
// Child.vue
<template>
<h1>信息:{{info}}</h1>
<el-button @click="onChange">点击</el-button>
</template>
<script setup>
import {defineProps,defineEmits} from 'vue';
// 声明Props
const props =defineProps({
info:{type:String,default:""}
})
// 声明Emits
const $emit = defineEmits(['changeInfo']);
const onChange=function(){
$emit('changeInfo','child返回值')
}
</script>
// Parent.vue
<template>
<Child :info="msg" @changeInfo="onAction"></Child>
</template>
<script setup>
import {ref} from 'vue';
import Child from './Child.vue'
const onAction=function(event){
console.log(event);
}
</script>
8、父组件获得子组件的数据(等同于Vue2.0中的$ref)
父组件想要通过ref获取子组件的变量或函数,子组件须使用defineExpose暴露出去。
// Child.vue
<script setup>
import {ref,define} from 'vue';
const info = ref('I am child');
const onChange = function(){console.log('')};
defineExpose({info,onChange})
</script>
// Parent.vue
<template>
<Child ref="childRef"></Child>
<el-button @click="onAction">点击</el-button>
</template>
<script setup>
import {ref} from 'vue';
import Child from './Child.vue'
const childRef = ref();
const onAction = function(){
console.log(childRef.value.info)
console.log(childRef.value.onChange());
};
</script>
9、provide和inject传值
无论组件层次结构有多深,父组件都可以通过provide选项来为其所有子组件提供数据。
// Parent.vue
<template>
<Child></Child>
</template>
<script setup>
import {ref,provide} from 'vue';
import Child from './Child.vue'
const msg = ref('Hello,my son');
const onShow = function(){...};
provide('myprovide',{msg,onShow})
</script>
// Child.vue
<template>
<el-button @click="getDate">点击获取父组件的值</el-button>
</template>
<script setup>
import {inject} from 'vue';
const provideState = inject('myProvide');
const getDate = function(){
console.log(provideState.msg);
console.log(provideState.onShow());
}
</script>
10、对await异步支持
< script setup>中可以使用顶层await,结果代码会被编译成async setup()。例子:
<script setup>
const post = await fetch('/api/post/tabledata').then(res=>{
})
</script>
11、nextTick
//方式一
<script setup>
import {nextTick} from 'vue';
nextTick(()=>{});// Dom已更新
</script>
//方式二
<script setup>
import {nextTick} from 'vue';
await nextTick();// nextTick是一个异步函数,返回一个Promise实例
</script>
12、全局属性 globalProperties
// main.js
import {createApp} from 'vue';
import App from './App.vue';
const app = createApp(App);
// 定义一个全局属性
app.config.globalProperties.global="全局属性";
app.$mount("#app");
<script setup>
//组件内使用
import {getCurrentInstance} from 'vue';
const { proxy } = getCurrentInstance();//获取Vue实例
console.log(proxy.$global);//输出
</script>
13、与普通< script >标签一起使用
可以与普通< script>标签一起使用,但是以下一些情况不会使用到:
①无法在<script setup>声明的选项 ,例如inheritAttrs 或通过插件启用的自定义的选项;
②声明命名导出,< script setup >定义的组件果默认以文件各作为组件名.
③运行副作用或者创建只需要执行一次的对象
< script >
//普通< script >,在模块范围下执行(只执行一次)
runSideEffectOnce();
// 声明额外的选项
export default {
name :'ComponentName ',//组件重命名
inberitAttrs:false ,
customOptons:{}
}
</ script >
<script setup )
//在 setup ()作用域中执行(对每个实例皆如此)
<script)
14、v-memo新指令
该指令与 v - once 类似, v - once 是只渲染一次之后的更新不再渲染,而 v - memo 是根据条件来渲染。该指令接收一个固定长度的数组作为依赖值进行记忆对比,如果数组中的每个值都和上次渲染的时候相同,则该元素(含子元素)不刷新。
①应用于普通元素或组件
< template >
< div v-meno ="[valueA ,valueB]">…</ div >//普通元素
< component v-memo ="[valueA , valueB]"></ component >//组件
< /template >
< script setup )
import component from ".../components/component.vne "
< /script >```
当组件重新渲染的时候,如果 valueA 与 valueB 都维持不变,那么对这个< div >以及它的所有子节点的更新都将被跳过。
②结合 v - for 使用
v - memo 仅供性能敏感场景的针对性优化,会用到的场景应该很少。渲染 v - for 长列表(长度大于1000)可能它是最有用的场景:
< template >
< div v-for =" item in list " :key =" item.id " v-memo ="[ item.id == selected ]">
< p > ID : {{item.id}}-selected : {{item.id == selected}}< /p >
< / div>
</ template >
当 selected 发生变化时,只有 item . id === selected 的该项重新渲染,其余不刷新。