Vue3.0 VCA语法糖 <script setup> :VCA模式

简介:

<script setup> 是在单文件组件(SFC)中使用组合式 API 的编译时语法糖。相比于普通的<script>语法,它具有更多优势:

  • 更少更简洁的代码,不需要使用 return{} 暴露变量和方法了,使用组件时不需要主动注册了

  • 更好的 Typescript 支持,使用纯 Typescript 声明 props 和抛出事件

  • 更好的运行时性能 (其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理)。

  • 更好的 IDE 类型推断性能 (减少语言服务器从代码中抽离类型的工作)。

<script setup>语法糖用法

基本语法:

要使用这个语法,在script 中添加setup属性即可。

<script setup></script>

在<script setup>语法糖中以下代码都省略掉了

//在<script setup>语法糖中省略了export default导出,及注册组件,和setup钩子函数
export default {  
  components:
  {
    Child
  },
  setup() {
    return {  }
  }
}

案列:

app.vue父组件

<template>
  <div>
    <button @click="myClick">App.Vue点我改名</button>

    <div>{{ user.name }}--{{ user.age }}--{{ user.email }}</div>

    <!-- toRefs的使用 -->
    <div>{{ name }}--{{ age }}--{{ email }}</div>

    <div v-mydir="user">计算属性包装后的name:{{ computedNmae }}</div>

    <div v-if="isShow">我根据isShow对象值来决定是否加载</div>

    <!-- 自定义组件 -->
    <Child :mytitle="title" state="error" @myevent="childHandelClick" @myevent2="childHandelClick2"></Child>

  </div>
</template>
<script setup>
import { ref, provide, toRef, toRefs, reactive, computed, markRaw, shallowRef, watch, onMounted } from 'vue';

//导入模板即注册:注册的名字就是你导入用的名称Child
import Child from "./components/Child.vue" //导入Child组件:
import BChild from "./components/BChild.vue" //导入Child组件:

//在<script setup> 中定义好对象,在Dom中就直接可以用了,不需要再return{ title,isShow ,user }出去才能用了
const title = ref("我是标题")
const isShow = ref(true);


const user = ref({
  name: "张三",
  age: 18,
  email: "123@qq.com"

})

//toRefs的使用:将响应式对象user中的所有属性转换为单独的响应式数据暴露出去:相当于 const name=ref(user.name); const age=ref(user.age);const email=ref(user.email)
const { name, age, email } = { ...toRefs(user.value) }


//函数的使用
const myClick = () => {
  user.value.name = "王五"
}


//监听事件1:用于子组件的回调
const childHandelClick = (name, age) => {
  console.log(name)
  console.log(age);
}

//监听事件2:用于子组件的回调
const childHandelClick2 = (data) => {
  console.log(data.email);
  console.log(data.url)
  console.log(data.port)
}

//计算属性的使用
const computedNmae = computed(() => {
  return "中华人民共和国:" + user.value.name
})

const myFun = () => {
  user.value.name = "李世民"
}

//依赖注入的使用:provide是提供者:向后代组件提供数据
provide("isShow", isShow);
provide("myFun", myFun, true); //向后代组件提供一个函数,如果提供的是一个函数,第三个参数必须为true  在注入的时候用法:const myfun=inject("myFun"); 然后可以直接执行函数:myfun()


// watch 侦听器的使用:侦听一个数据源
watch(title, (newValue, oldValue) => {
  console.log(`title发生了变化,老值为:${oldValue},--新值为:${newValue}`)
}, { immediate: true, deep: false })


// watch 侦听器的使用:侦听多个数据源
// watch([mytext,myselect], (newValue, oldValue)=>{console.log("新的值",newValue); console.log("老的值",oldValue)}):这段代码可以用如下解构的形式来写
watch([title, isShow], ([newTitle, newIsShow], [oldTitle, oldIsShow]) => {
  console.log(`title或者isShow变化了`);
  console.log("newTitle", newTitle)
  console.log("oldTitle", oldTitle)
  console.log("newIsShow", newIsShow)
  console.log("oldIsShow", oldIsShow)
})

//钩子函数的使用
onMounted(() => {
  // 自定义逻辑
})

//自定义指令:有created,beforeMount,mounted,beforeUpdate,updated,beforeUnmount,unmounted这些钩子函数
//自定义指令:必须以小写字母v开头的小驼峰 的格式来命名本地自定义指令:指令中有多个钩子函数,我们常用就以下两种
//举列:名字为vHostKey的指令 Dom中的写法应该是:v-host-key 或者v-hostKey 或者v-HostKey
const vMydir = {
  //el表示指令所绑定组件的元素
  //binding表示指令所传递的值:例如:<div v-mydir="user">  这指令传递的值就是user对象
  mounted: (el, binding, vnode) => {
    el.style.background = 'red'
    console.log(binding.value.name); //输出:张三
    console.log(binding.value.age);  //输出:18
    console.log(binding.value.email);  //输出:123@qq.com
  },
  updated: (el, binding, vnode) => {
  }
}

</script>

Child.vue子组件

<template>
    <div>
        {{ props.mytitle }} <!--或者直接用mytitle,不用props.mytitle也行-->
    </div>
    <div>
        {{ props.state }} <!--或者直接用mytitle,不用props.mytitle也行-->
    </div>
    <div><input type="text"></div>
    <button @click="handelClick">向父组件发起问候传递参数</button>
    <button @click="handelClick2">向父组件发起问候传递参数2</button>
    <button @click="handelClick3">调用祖组件提供的的myFun函数</button>
</template>
<script setup>
import { inject, ref, defineProps, defineEmits } from 'vue';

//父组件向子组件传值:具体可参阅:vue3.0中父组件与子组件的通信传值props与$emit :VOA模式文章
//这里接收父组件传递过来的state和mytitle值
//简写:const props = defineProps({state:String,mytitle:String})
const props = defineProps({
    state: {
        required: true, //true 表示属性必传;false 表示可以不传属性;
        type: String, //表示属性只能是String类型的。也可以指定多个类型如type:[String,Number]
        default() {// 如果该参数没用值则指定一个默认值abc ;也可以直接default: "abc" 
            return "abc"
        },
        //也可以写成:validator:value=>['success','warning','danger','error'].indexOf(value)>-1
        validator(val) {
            //检查参数的值是否是"success"或者"warning"或者"danger"或者"error",如果是则返回true,不是则返回false               
            return ["success", "warning", "danger", "error"].includes(val)
        }
    },
    mytitle: {
        type: String
    }
})

//注入:祖组件通过provide提供了isShow对象和myFun函数,这里接收
const isShow = inject("isShow");
const myFun = inject("myFun");

//获取父组件的监听,向父组件通信传递参数
const emits = defineEmits(["myevent", "myevent2"]); //获取父组件的"myevent","myevent2"监听事件

const handelClick = () => {
    emits("myevent", "王五", 19) //调用父组件的myevent监听事件,并传值
}
const handelClick2 = () => {
    emits("myevent2", { email: "woo@qq.com", url: "http://localhost:5173/", port: 8080 }) //调用父组件的myevent2监听事件,并传值
}

const handelClick3 = () => {
    isShow.value = !isShow.value;
    myFun(); //执行祖组件提供的函数
}

</script>
 

<script setup>中的动态组件使用

App.vue父组件

<template>
  <div>
    <button @click="switchComponent">App.Vue点我切换组件</button>

    <!-- 动态组件 -->
    <component :is="Child" :mytitle="title" state="error" />
    <component :is="isShow?Child:BChild" :mytitle="title" state="error" />

    <!-- keep-alive组件内不要使用注释,会被解析为子节点 -->
    <!-- include:包含:包含中的组件存在缓存,组件中录入的数据在组件切换走后再切换回来数据依然保留 -->
    <!-- exclude:排除:排除中的组件不存在缓存,除此之外都存在缓存 -->
    <KeepAlive include="Child,BChild">
      <component :is="componentName" :mytitle="title" state="error"></component>
    </KeepAlive>

  </div>
</template>
<script setup>
import { ref, provide, toRefs, reactive, computed, markRaw, shallowRef } from 'vue';

//导入模板即注册:注册的名字就是你导入用的名称Child
import Child from "./components/Child.vue" //导入Child组件:
import BChild from "./components/BChild.vue" //导入Child组件:


const title = ref("我是标题")
const isShow = ref(true);


// 使用<keep-alive>包裹动态组件的时候,动态组件的名称应该用shallowRef或者markRaw来进行包裹。
// 说明:
// 在 Vue 3 中,如果用 ref 或 reactive 将一个组件包装成响应式对象,可能会引发不必要的性能开销。因为这会使 Vue 尝试去追踪组件的变化,而实际上组件实例并不需要被追踪。组件本身不应该是响应式的,只有它的 props 和 state 才应该是响应式的。
// 所以,当需要引用一个组件时,应该使用 shallowRef或者 markRaw,这样可以避免将整个组件变成响应式的,只会跟踪引用的变化
const componentName = shallowRef(Child);

//切换组件
const switchComponent = () => {
  isShow.value = !isShow.value;

  switch (componentName.value) {
    case BChild:
      componentName.value = Child;
      break
    case Child:
      componentName.value = BChild;
      break
  }
}
//组件名称不要用ref对象,直接用字符串即可:如下代码
// let componentName = "Child";

// const switchComponent = () => {
//   isShow.value = !isShow.value;
//   switch (componentName) {
//     case "Child":
//       componentName = "BChild";
//       break
//     case "BChild":
//       componentName = "Child";
//       break
//   }
// }
</script>

Child.vue子组件

<template>
    <div>
        {{ props.mytitle }} <!--或者直接用mytitle,不用props.mytitle也行-->
    </div>
    <div>
        {{ state }} <!--或者直接用mytitle,不用props.mytitle也行-->
    </div>
    <div><input type="text"></div>
</template>
<script setup>
import { inject, ref, defineProps, defineEmits } from 'vue';

//父组件向子组件传值:具体可参阅:vue3.0中父组件与子组件的通信传值props与$emit :VOA模式文章
//这里接收父组件传递过来的state和mytitle值
const props = defineProps({ state: { type: String }, mytitle: { type: String } });

</script>

BChild.vue子组件

<template>
    <div>
        我是BChild.vue<input type="text">
    </div>
</template>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值