总结Vue3常见组件定义方式,我竟写出来了个bug……

本文详细介绍了Vue3中三种组件注册方式:全局组件注册、setup选项与<script setup>语法糖。通过实例解析了各方式的使用方法和特性,包括模板渲染、组合式API的运用、生命周期函数等,帮助开发者更好地理解和应用Vue3组件。

茶已备好,只待君来!感谢关注 前端点线面 (>‿<),本号定期推荐原创深度好文,帮助每一位在前端领域打拼的伙伴们走向前列,此外关注我获取最前沿知识点、海量学习资料、《前端百题斩》、大量大厂学习思维导图,并进前端划水交流群(小姐姐多多)。

想看bug的可以直接跳到第二段代码处!!!待大佬帮我解惑

相信很多同学都用过Vue开发项目,利用其开发项目时肯定都或多或少的定义过组件,总结下来主要有三种,下面一起来看看总结的这几种:

一、component方式

通过app.component(name, Component)可以注册全局组件,通过该方式注册的组件在任何子组件中可以直接调用,如下所示:

import {createApp, h} from 'vue'
app.component('test-component', {
    data() {
        return {
            count: 10
        }
    },
    render() {
        return h('h1', `测试${this.count}`);
    }
});

// 使用:直接在所需要调用的位置直接调用该组件即可
<test-component />

注意:此处有一个位置没有搞懂,文档中表示可以直接调用template选项,但是我按照规范书写后内容并没有正常渲染,希望对该部分有研究的老铁可以给我指点迷津。(测试代码如下所示)

app.component('test-error', {
    template: `
      <div>
        <strong>Error!</strong>
      </div>
    `
});

// 使用(未正常渲染出来,由于自己对源码部分研究较少,目前还未找到具体原因)
<test-error />

通过该种方式还可以将第三方组件注入到全局中,从而使该组件能够在别的位置直接使用,以导出Element Plus中的某些组件为例,注入到全局后可以在单文件组件中直接使用。

// 可以将该种方式定义为插件
import {ElButton} from "element-plus";

const components = [
    ElButton
];

export default {
    install: app => {
        components.forEach(component => {
            app.component(component.name, component);
        });
    }
};

// 使用该插件
app.use(插件名);

// 使用该组件
<ElButton>test</ElButton>

二、Vue3.x的setup选项方式

setup函数是一个新的组件选项,是组件内部使用组合式API的入口点,使用该方式就像使用Vue2.x一样简单,仅仅是增加了一个选项,下面来看看如何用该方式定义一个组件:

<template>
    <h1>这是组件二</h1>
    <button @click="a++">a is {{a}}</button>
</template>

<script>
import {ref, toRefs, onMounted} from 'vue';
export default {
    props: ['testProp1'],
    data() {
        return {
            a: 10
        }
    },
    // 将 setup 返回的所有内容都暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板
    setup(props) {
        // toRefs()函数的目的是延续响应式,防止丢失响应式(如果直接怼props解构会丢失响应式)
        const {testProp1} = toRefs(props);
        // ref()会接收内部值并返回一个响应式且可变的ref对象。
        const count = ref(0);
        console.log('setup');
        onMounted(() => {
            console.log('setup_mounted');
        });
        onMounted(() => {
            console.log('script中setup的mount被执行1');
        });

        onMounted(() => {
            console.log('script中setup的mount被执行2');
        });
    },
    mounted() {
        console.log('mounted');
    }
}
</script>

在使用过程中你会发现其有以下两个特点:

  1. setup中的生命周期函数可以重复多次,从而达到了将相关逻辑点聚合到一起的目的;

  2. 选项中的相同生命周期的执行时机晚于setup函数中的相同生命周期的时机,例如mouted执行时机比onMounted晚。

三、Vue3.x的<script setup>方式

是不是感觉用setup方式写起来跟Vue2.x的区别不是很大,外观上看支持增加了一个setup选项,下面来一起看看这个更牛气的东西——,其是使用组合式API的编译时的语法糖,其使内容更加简洁,下面来一起看看该方式定义的组件。

<template>
    <h1>这是组件一</h1>
    <ButtonCounter />
    <p>{{testProp1}}</p>
    <button @click="count++">count is {{count}}</button>
    <button @click="state.test++">测试{{state.test}}</button>
    <button @click="testRef++">测试{{testRef}}</button>
    <button @click="test1++">测试{{test1}}</button>
    <button @click="test2++">测试{{test2}}</button>
</template>

<script setup>
console.log('script setup 1执行了');
// 使用defineProps来声明props
defineProps({
    testProp1: String
});
// 使用defineEmits来声明emits,然后调用的时候通过emit(事件名, 参数)形式触发
const emit = defineEmits(['emit1', 'emit2']);

// https://juejin.cn/post/6976679225239535629
// ref:接收内部值并返回一个响应式且可变的ref对象。ref 对象仅有一个 .value property,指向该内部值;
// reactive: 为对象添加响应式状态,接收一个js对象作为参数,返回一个具有响应式状态的副本;
// toRef和toRefs主要目的是延续响应式,防止丢失响应式
import {ref, reactive, toRef, toRefs, onMounted, onBeforeMount, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, defineProps, defineEmits} from 'vue';

// ref让其具备响应式
const count = ref(0);

// 用reactive让该对象具备响应式
const state = reactive({
    test: 0
});

const testRef = toRef(state, 'test');

const {test: test1} = toRefs(state);
const {test: test2} = state; // 会丢失响应性

onBeforeMount(() => {
    console.log('beforeMount');
});
onMounted(() => {
    console.log('mount');
});
onBeforeUpdate(() => {
    console.log('beforeUpdate');
});
onUpdated(() => {
    console.log('updated');
});
onBeforeUnmount(() => {
    console.log('beforeUnmount');
});
onUnmounted(() => {
    console.log('unmounted');
});
</script>

<script>
// 普通script在模块范围下只执行一次(可以不添加该部分)
console.log('script执行了!!!!!!');
export default {
    // 当有script setup时,setup函数不会被执行
    mounted() {
        console.log('script 中 mount被执行!!!');
    }
};
</script>

<style lang="less" scoped>
</style>

················ 执鸢者简介 ·················

大家好,我是执鸢者,毕业于华中科技大学,新时代农民工,现在是百度前端研发工程师,著有《前端百题斩》、数十篇学习思维导图(go、React、Redux、Vue、Vuex、操作系统、Linux、设计模式、js、webpack、nginx)以及大量前端进阶文章,大量同学已通过号主的系列内容获取心仪的offer,关注我获取海量资料、交流工作心得并进卧虎藏龙交流群。

24ebc07eaa2e276a27bde502432012ac.png

识别方二维码加我微信、拉你进交流

ba33153083948912ab621e39b3b7546e.png

【1】前端有意思

【2】React系列

【3】Vue系列

【4】基础知识

【5】构建工具系列

【6】前端百题斩系列

【7】网络系列

【8】浏览器系列

【9】Node系列

【10】源码系列

【11】图解JavaScript系列

【12】手撕算法系列

【特别篇】个人总结

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值