3

在 Vue 3 中定义组件的 5 种方法

 1 year ago
source link: https://www.fly63.com/article/detial/12452
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

vue 正在不断发展,目前在版本 3 中有多种定义组件的方法。从选项到组合再到类 api,情况大不相同,如果您刚刚开始,可能会感到困惑。让我们定义一个简单的组件并使用所有可用的方法重构它。

1. Options API

这是在 Vue 中声明组件的最常见方式。从版本 1 开始可用,您很可能已经熟悉它。一切都在对象内声明,数据在幕后由 Vue 响应。它不是那么灵活,因为它使用 mixin 来共享行为。

<script>
import TheComponent from './components/TheComponent.vue'
import componentMixin from './mixins/componentMixin.js'

export default {
name: 'OptionsAPI',
components: {
TheComponent,
AsyncComponent: () => import('./components/AsyncComponent.vue'),
},
mixins: [componentMixin],
props: {
elements: {
type: Array,
},
counter: {
type: Number,
default: 0,
},
},
data() {
return {
object: {
variable: true,
},
}
},
computed: {
isEmpty() {
return this.counter === 0
},
},
watch: {
counter() {
console.log('Counter value changed')
},
},
created() {
console.log('Created hook called')
},
mounted() {
console.log('Mounted hook called')
},
methods: {
getParam(param) {
return param
},
emitEvent() {
this.$emit('event-name')
},
},
}
</script>
<template>
<div class="wrapper">
<TheComponent />
<AsyncComponent v-if="object.variable" />
<div class="static-class-name" :class="{ 'dynamic-class-name': object.variable }">
Dynamic attributes example
</div>
<button @click="emitEvent">Emit event</button>
</div>
</template>

<style lang="scss" scoped>
.wrapper {
font-size: 20px;
}
</style>

2. Composition API

经过多次讨论、来自社区的反馈,以及令人惊讶的是,在这个 RFC中,有很多戏剧性的内容,在 Vue 3 中引入了 Composition API 。动机是提供更灵活的 API 和更好的 TypeScript 支持。这种方法在很大程度上依赖于设置生命周期挂钩。

<script>
import {
ref,
reactive,
defineComponent,
computed,
watch,
} from 'vue'

import useMixin from './mixins/componentMixin.js'
import TheComponent from './components/TheComponent.vue'

export default defineComponent({
name: 'CompositionAPI',
components: {
TheComponent,
AsyncComponent: () => import('./components/AsyncComponent.vue'),
},
props: {
elements: Array,
counter: {
type: Number,
default: 0,
},
},
setup(props, { emit }) {
console.log('Equivalent to created hook')

const enabled = ref(true)
const object = reactive({ variable: false })

const { mixinData, mixinMethod } = useMixin()

const isEmpty = computed(() => {
return props.counter === 0
})

watch(
() => props.counter,
() => {
console.log('Counter value changed')
}
)

function emitEvent() {
emit('event-name')
}
function getParam(param) {
return param
}

return {
object,
getParam,
emitEvent,
isEmpty
}
},
mounted() {
console.log('Mounted hook called')
},
})
</script>

<template>
<div class="wrapper">
<TheComponent />
<AsyncComponent v-if="object.variable" />
<div class="static-class-name" :class="{ 'dynamic-class-name': object.variable }">
Dynamic attributes example
</div>
<button @click="emitEvent">Emit event</button>
</div>
</template>

<style scoped>
.wrapper {
font-size: 20px;
}
</style>

如您所知,使用这种混合方法需要大量样板代码,而且设置函数很快就会失控。在迁移到 Vue 3 时,这可能是一个很好的中间步骤,但是语法糖可以让一切变得更干净。

3.Script setup

在 Vue 3.2 中引入了一种更简洁的语法。通过在脚本元素中添加设置属性,脚本部分中的所有内容都会自动暴露给模板。通过这种方式可以删除很多样板文件。

<script setup>
import {
ref,
reactive,
defineAsyncComponent,
computed,
watch,
onMounted,
} from "vue";

import useMixin from "./mixins/componentMixin.js";
import TheComponent from "./components/TheComponent.vue";
const AsyncComponent = defineAsyncComponent(() =>
import("./components/AsyncComponent.vue")
);

console.log("Equivalent to created hook");
onMounted(() => {
console.log("Mounted hook called");
});

const enabled = ref(true);
const object = reactive({ variable: false });

const props = defineProps({
elements: Array,
counter: {
type: Number,
default: 0,
},
});

const { mixinData, mixinMethod } = useMixin();

const isEmpty = computed(() => {
return props.counter === 0;
});

watch(() => props.counter, () => {
console.log("Counter value changed");
});

const emit = defineEmits(["event-name"]);
function emitEvent() {
emit("event-name");
}
function getParam(param) {
return param;
}
</script>

<script>
export default {
name: "ComponentVue3",
};
</script>

<template>
<div class="wrapper">
<TheComponent />
<AsyncComponent v-if="object.variable" />
<div
class="static-class-name"
:class="{ 'dynamic-class-name': object.variable }"
>
Dynamic attributes example
</div>
<button @click="emitEvent">Emit event</button>
</div>
</template>

<style scoped>
.wrapper {
font-size: 20px;
}
</style>

4. Reactivity Transform

这是非常有争议的,被删除了!这使得脚本设置成为本文的明确答案。(26/1/2023 更新)

script setup以下代码段中演示的内容存在问题。

<script setup>
import { ref, computed } from 'vue'

const counter = ref(0)
counter.value++

function increase() {
counter.value++
}

const double = computed(() => {
return counter.value * 2
})
</script>


<template>
<div class="wrapper">
<button @click="increase">Increase</button>
{{ counter }}
{{ double }}
</div>
</template>

正如您所注意到的,访问响应式计数器感觉.value不自然,并且是混淆和错误输入的常见来源。有一个实验性解决方案利用编译时转换来解决此问题。反应性转换是一个可选的内置步骤,它会自动添加此后缀并使代码看起来更清晰。

<script setup>
import { computed } from 'vue'

let counter = $ref(0)
counter++

function increase() {
counter++
}

const double = computed(() => {
return counter * 2
})
</script>


<template>
<div class="wrapper">
<button @click="increase">Increase</button>
{{ counter }}
{{ double }}
</div>
</template>

$ref需要构建步骤,但无需.value访问变量。启用后它在全球范围内可用。

5.Class API

类 API 已经可用很长时间了。通常与 Typescript 搭配使用是 Vue 2 的可靠选择,并且被认真考虑为默认的 Vue 3 语法。但经过多次长时间的讨论后,它被放弃了,取而代之的是 Composition API。它在 Vue 3 中可用,但工具严重缺乏,官方建议远离它。无论如何,如果您真的喜欢使用类,您的组件将看起来像这样。

<script lang="ts">
import { Options, Vue } from 'vue-class-component';

import AnotherComponent from './components/AnotherComponent.vue'

@Options({
components: {
AnotherComponent
}
})
export default class Counter extends Vue {
counter = 0;

get double(): number {
return this.counter * 2;
}
increase(): void {
this.quantity++;
}
}
</script>


<template>
<div class="wrapper">
<button @click="increase">Increase</button>
{{ counter }}
{{ double }}
</div>
</template>

那哪个最好呢?这取决于典型的反应,尽管在这种情况下并非如此。从 Vue 2 迁移时,选项和类 API 可以用作中间步骤,但它们不应该是您的首选。如果您没有构建阶段,组合 API 设置是唯一的选择,但由于大多数项目都是使用 webpack 或 Vite 生成的,因此使用脚本设置既是可能的,也是鼓励的,因为大多数可访问的文档都使用这种方法。

翻译:https://fadamakis.com/the-5-ways-to-define-a-component-in-vue-3-aeb01ac6f39f

链接: https://www.fly63.com/article/detial/12452


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK