Vue3 语法

Vue3 语法

<template> 中使用的语法,Vue3 和 Vue2 几乎没有差别。但是在 <script> 中使用的语法,Vue3 有比较大的变化。

一、template 根节点

在 Vue3 中,<template> 不再需要根节点。

<template>
    <div></div>
    <h1></h1>
</template>

二、子组件渲染

在 Vue3 中,父组件中如果要渲染子组件,只需要“引入”和“渲染”两个步骤。

<template>
    <HelloWorld />
</template>

<script setup>
    import HelloWorld from './components/HelloWorld.vue';
</script>

三、setup

Vue3 从最早的测试版,然后到正式版,以及正式版后续的新提案,每一个版本的 setup 的语法都不太一样。目前我们采用最新版的语法:

<script setup>

</script>

在 VSCode 中,可以通过快捷键 v3 来自动生成该版本的组件基本代码。

四、组件的数据

1、ref

<template>
    <h1>计数器:{{ count }}</h1>
</template>

<script setup lang="ts">
import { ref } from 'vue';
const count = ref(0);
console.log(count.value);
</script>

语法说明:

  1. Vue3 的组件中可以通过 ref() 来定义组件内部数据;
  2. 每个组件中使用 ref 时,都需要先引入;
  3. 在调用 ref() 方法,可以传递一个参数来作为组件内部数据的初始值;
  4. ref() 定义的数据,在 template 中使用时,可以直接通过变量名来访问;
  5. ref() 定义的数据,在 script 中使用时,必须通过 变量名.value 来访问;

2、reactive

<template>
    <h1>计数器:{{ state.count }}</h1>
</template>

<script setup lang="ts">
    import { reactive } from 'vue';
    const state = reactive({
        count: 0
    });
    console.log(state.count);
</script>

语法说明:

  1. Vue3 的组件中可以通过 reactive() 来定义组件内部数据;
  2. 每个组件中使用 reactive 时,都需要先引入;
  3. 在调用 reactive() 方法,需要传递一个数组或对象来作为组件数据的初始值;
  4. reactive() 定义的数据,在 templatescript 中的访问方式是一样的;
  5. 通过 reactive() 定义的数组或对象,在修改时不能修改数组或对象的地址

五、组件的事件

<template>
    <button @click="increment">+1</button>
</template>

<script setup lang="ts">
const increment = () => {
    console.log("事件方法");
}
</script>

六、计算属性

<script setup lang="ts">
    import { computed } from 'vue';
    const 变量 = computed(() => {
        return 计算结果;
    })
</script>

七、侦听器

<script setup lang="ts">
import { ref, watch } from 'vue';
const count = ref(0);
watch(() => count.value, (newValue, oldValue) => {
    console.log('count.value 发生变化了', newValue, oldValue);
});
</script>

https://blog.csdn.net/m0_49515138/article/details/128250061

语法说明:

  1. watch() 在使用前需要先引入;
  2. watch() 接收两个函数作为参数,第一个函数的返回值就是需要侦听的数据,当侦听的数据发生变化时,会执行第二个函数;

深度侦听和立即侦听

watch(() => count.value, (newValue, oldValue) => {
    console.log('count.value 发生变化了', newValue, oldValue);
}, {
    immediate: true,
    deep: true
});

八、watchEffect

<script setup lang="ts">
import { ref, watchEffect } from 'vue';
const count = ref(0);
watchEffect(() => {
    console.log('你好', count.value);
})
</script>

语法说明:

  1. watchEffect() 在使用前需要先引入;
  2. watchEffect() 需要接收一个函数作为参数;
  3. watchEffect() 会自动监听函数中用到的所有数据,当函数中任意数据发生改变时,watchEffect() 都会重新执行;

watch 和 watchEffect 的区别

  1. 默认情况下,watchEffect 在页面首次刷新时会执行一次,而 watch 不会;
  2. watch 可以接收到数据变化前后的值,而 watchEffect 没有;
  3. watch 需要指定侦听的数据,watchEffect 是自动侦听函数中用到的数据;

九、生命周期函数

Vue2Vue3
beforeCreate
created
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyonBeforeUnmount
destroyedonUnmounted

示例代码:

import { onMounted } from 'vue';
onMounted(() => {
    console.log('组件挂载完成')
})

十、组件传值

1、父传子:prop

Vue3 中,和 Vue2 一样,也是通过 prop 来实现父组件给子组件传值。

父组件传递数据和 Vue2 的语法没有区别,但是子组件在接收 props 数据时,Vue3 的语法如下:

<template>
    <div>
        <h1>接收父组件传递的数据:{{ count }}</h1>
    </div>
</template>

<script setup lang="ts">
    const props = defineProps({
        count: Number
    });
    console.log(props.count);
</script>

2、子组件接受值

通过defineProps 来接受, defineProps是无须引入的直接使用即可

这是TS特有的:

<template>
    <div class="menu">
        菜单区域 {{ title }}
        <div>{{ data }}</div>
    </div>
</template>
 
<script setup lang="ts">
defineProps<{
    title:string,
    data:number[],
    obj:{
        type:Object,
        default(){
            return {}
        }
    }
}>()
</script>

3、TS 特有的默认值方式

withDefaults是个函数也是无须引入开箱即用,接受一个props函数第二个参数是一个对象设置默认值

type Props = {
    title?: string,
    data?: number[]
}
withDefaults(defineProps<Props>(), {
    title: "张三",
    data: () => [1, 2, 3]
})

4、子传父:自定义事件 defineEmits

Vue3 中,和 Vue2 一样,也是通过自定义事件来实现子组件给父组件传值。

父组件绑定自定义事件和 Vue2 的语法没有区别,但是子组件中触发自定义事件时,Vue3 的语法如下:

<template>
    <button @click="toFather">按钮</button>
</template>

<script setup lang="ts">
    const emit = defineEmits(['getData'])
    const toFather = () => {
        // 调用自定义事件,并传值
        emit('getData', 100);
    }
</script>
<template>
    <div class="menu">
        <button @click="clickTap">派发给父组件</button>
    </div>
</template>
 
<script setup lang="ts">
import { reactive } from 'vue'
const list = reactive<number[]>([4, 5, 6])
 
const emit = defineEmits(['on-click'])
const clickTap = () => {
    emit('on-click', list)
}
</script>

5、父组件接受子组件的事件

<template>
    <div class="layout">
        <Menu @on-click="getList"></Menu>
        <div class="layout-right">
            <Header></Header>
            <Content></Content>
        </div>
    </div>
</template>
 
<script setup lang="ts">
import Menu from './Menu/index.vue'
import Header from './Header/index.vue'
import Content from './Content/index.vue'
import { reactive } from 'vue';
 
const data = reactive<number[]>([1, 2, 3])
 
const getList = (list: number[]) => {
    console.log(list,'父组件接受子组件');
}
</script>

6、子组件暴露给父组件内部属性

通过defineExpose

我们从父组件获取子组件实例通过ref

 <Menu ref="menus"></Menu>
  const menus = ref(null)

这时候父组件想要读到子组件的属性可以通过 defineExpose暴露

const list = reactive<number[]>([4, 5, 6])
 
defineExpose({
    list
})

十一、ref、toRef、toRefs的区别

toRefs(obj):作用是将响应式对象中的所有属性转换为单独的响应式数据,原始数据变为普通对象,值是关联的

响应式数据展开后会失去响应式{}

<script lang="ts">
    import { reactive } from "vue";
    export default{
        setup(){
            const user = reactive<any>({
                name: "张三",
                age: 23,
                addr: {
                    province: "河南",
                    city: "郑州"
                }
            })
            return {
                ...toRefs(user);
                let name = toRef(user, "name")
            }
        }
    }
 </script>

toRef(obj, key):作用是将响应式对象中的某一个属性转换为响应式数据,接受两个参数,第一个是哪个对象,第二个是哪个属性

十二、isref() unref()

isref()检查一个值是否为ref对象
unref()如果参数是一个ref则返回它的value,否则返回参数本身
unref():是 val = isRef(val) ? val.value : val 的语法糖。


const valueRef = ref('');
const value = unref(valueRef);
if (!value) {
   console.warning('请输入要拷贝的内容!');
   return;
}

十三、defineExpose()

defineExpose():使用<script setup>的组件默认是关闭的,可以通过模板引用或者$parent链获取到组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定

可以通过defineExpose()编译器宏来显示指定在<script setup>组件中要暴露出去的属性

<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)

defineExpose({a, b})
</script>

十四、defineComponent()

在定义Vue组件时提供类型推导的辅助函数

十五、获取节点的原生dom对象

 <infoCard v-show='showInfoWindow' :ref="(el) => infoWindow = el"  />

 <script setup lang="ts">
     import { ref,  getCurrentInstance  } from "vue";
// 获取页面的实例对象
// const pageInstance = getCurrentInstance();

// 定义信息窗口
      window.infoWindow = new AMap.InfoWindow({
        // 使用自定义窗体
        isCustom: true,
        // 只有当组件渲染完毕后,拿到原生的dom对象
        content: infoWindow.value.$el, 
       // 只有当组件渲染完毕后,通过pageInstance才能拿到原生的dom对象
       //  content: pageInstance?.refs.infoWindow, 
        anchor: "bottom-left",
        offset: new AMap.Pixel(30, 0),
      });
 </script>

十六、toRaw获取原始对象

使用vue3.0时,因为底层是使用proxy进行代理的所以当我们打印一些值得时候是proxy代理之后的是Proxy
对象,Proxy对象里边的[[Target]]才是真实的对象。

1、通过vue中的响应式对象可使用 toRaw() 方法获取原始对象
//第一种获取target值的方式,通过vue中的响应式对象可使用toRaw()方法获取原始对象
import { toRaw } from 'vue'
let obj=toRaw(props.formAllValue)
2、通过json序列化之后可获取值
//第二种获取target值的方式,通过json序列化之后可获取值
JSON.parse(JSON.stringify(store.getters.menuList))

十七、getCurrentInstance

// 此段代码写入main.js中
app.config.globalProperties.$t = i18n.global.t;

import { getCurrentInstance  } from "vue";
const _this = getCurrentInstance()?.appContext.config.globalProperties ;

console.log(_this)

十八、h() createVNode()

h()函数和createVNode()函数都是创建dom节点,他们的作用是一样的,但是在VUE3中createVNode()函数的功能比h()函数要多且做了性能优化,渲染节点的速度也更快

h(标签, {属性},内容)
h(标签, {属性},[可以继续嵌套h()])
createVNode(标签, {属性},内容)
createVNode(标签, {属性},[可以继续嵌套createVNode()])
createVNode() 或者 h()中 设置ref

开发环境下可以正常使用,生产环境中报错Cannot read properties of null (reading 'refs')

解决方案:使用函数包含返回

<template>
  <el-button :plain="true" @click="openVn">VNode</el-button>
</template>
<script lang="ts" setup>
import { ref, h } from 'vue'
import { ElMessage } from 'element-plus'
const messageRef = ref()
const openVn = () => {
  ElMessage({
    message: () => h('div', { ref: messageRef }, [
      h('span', null, 'Message can be '),
      h('i', { style: 'color: teal' }, 'VNode'),
    ]),
  })
}
</script>

十九、markRaw()/shallowRef()/shallowReactive()

markRow():标记一个对象,使其永远不会变成一个响应式对象,跳过proxy代理;

toRaw():将一个由reactive生成的响应式对象转换为普通对象;

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

shallowReactive():只处理对象最外层属性的响应式(浅响应式);

二十、 UnwrapRef()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值