Appearance
Vue 核心概念
本文介绍Vue的核心概念,包括组件、Props、data、生命周期、事件处理、条件渲染、列表渲染、表单、插槽、Provide/Inject、组合式API等基础知识点。
什么是Vue?
Vue(Vue.js)是一个用于构建用户界面的渐进式JavaScript框架。它专注于视图层,易于上手,适合开发单页应用(SPA)和复杂前端项目。
Vue的特点
- 响应式数据绑定:数据变化会自动更新视图。
- 组件化开发:将UI拆分为独立、可复用的组件。
- 声明式渲染:使用模板语法声明UI结构。
- 轻量高效:体积小,性能优异。
- 易于集成:可逐步采用,灵活性高。
组件
组件是Vue应用的核心构建块。每个组件本质上是一个拥有自己选项的独立Vue实例。
选项式API组件
vue
<template>
<h1>Hello, {{ name }}</h1>
</template>
<script>
export default {
props: {
name: {
type: String,
default: 'Guest'
}
}
};
</script>组合式API组件
vue
<template>
<h1>Hello, {{ name }}</h1>
</template>
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
name: {
type: String,
default: 'Guest'
}
});
const name = props.name;
</script>组件组合
vue
<template>
<div>
<Welcome name="Alice" />
<Welcome name="Bob" />
<Welcome name="Charlie" />
</div>
</template>
<script setup>
import Welcome from './Welcome.vue';
</script>模板语法(类似JSX)
Vue使用模板语法声明UI结构,支持插值、指令等。
vue
<template>
<h1>Hello, {{ name }}!</h1>
<img :src="avatarUrl" alt="User avatar" />
<div>
<h1>Title</h1>
<p>Paragraph</p>
</div>
</template>
<script setup>
const name = 'John';
const avatarUrl = 'https://example.com/avatar.png';
</script>防注入攻击
Vue会自动对插值内容进行HTML转义,防止XSS攻击。
vue
<template>
<h1>{{ title }}</h1>
</template>
<script setup>
const title = "<script>alert('XSS');</script>";
</script>Props
Props用于父组件向子组件传递数据,子组件通过props选项声明接收。
vue
<!-- 父组件 -->
<template>
<Welcome name="Sara" :age="25" :is-admin="true" />
</template>
<!-- 子组件 Welcome.vue -->
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
name: String,
age: Number,
isAdmin: Boolean
});
</script>
<template>
<div>
<h1>Hello, {{ props.name }}</h1>
<p>Age: {{ props.age }}</p>
<p v-if="props.isAdmin">Admin user</p>
</div>
</template>Props的特点
- Props是单向数据流,子组件不应直接修改props。
- 可以设置默认值和类型校验。
data(响应式状态)
组件内部的响应式数据通过data选项(选项式API)或ref/reactive(组合式API)声明。
选项式API
vue
<script>
export default {
data() {
return {
count: 0
};
},
methods: {
increment() {
this.count++;
}
}
};
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>组合式API
vue
<script setup>
import { ref } from 'vue';
const count = ref(0);
const increment = () => count.value++;
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>生命周期
Vue组件有多个生命周期钩子。
vue
<script setup>
import { onMounted, onUpdated, onUnmounted } from 'vue';
onMounted(() => {
console.log('组件已挂载');
});
onUpdated(() => {
console.log('组件已更新');
});
onUnmounted(() => {
console.log('组件已卸载');
});
</script>选项式API:
js
export default {
mounted() {
console.log('组件已挂载');
},
updated() {
console.log('组件已更新');
},
unmounted() {
console.log('组件已卸载');
}
};事件处理
Vue事件使用v-on(简写为@)绑定。
vue
<template>
<button @click="handleClick">Click me</button>
</template>
<script setup>
function handleClick(e) {
e.preventDefault();
console.log('Button clicked');
}
</script>传递参数
vue
<template>
<button @click="() => handleClick(id)">Delete</button>
</template>
<script setup>
const id = 1;
function handleClick(id) {
console.log('Delete', id);
}
</script>条件渲染
使用v-if、v-else-if、v-else、v-show实现条件渲染。
vue
<template>
<h1 v-if="isLoggedIn">Welcome back!</h1>
<h1 v-else>Please sign up.</h1>
</template>
<script setup>
const isLoggedIn = true;
</script>列表渲染
使用v-for渲染列表。
vue
<template>
<ul>
<li v-for="number in numbers" :key="number">{{ number }}</li>
</ul>
</template>
<script setup>
const numbers = [1, 2, 3, 4, 5];
</script>表单
Vue通过v-model实现表单的双向绑定。
vue
<template>
<form @submit.prevent="handleSubmit">
<label>
Name:
<input v-model="name" type="text" />
</label>
<input type="submit" value="Submit" />
</form>
</template>
<script setup>
import { ref } from 'vue';
const name = ref('');
function handleSubmit() {
alert('A name was submitted: ' + name.value);
}
</script>处理多个输入
vue
<template>
<form>
<label>
Is going:
<input type="checkbox" v-model="isGoing" />
</label>
<br />
<label>
Number of guests:
<input type="number" v-model="numberOfGuests" />
</label>
</form>
</template>
<script setup>
import { ref } from 'vue';
const isGoing = ref(true);
const numberOfGuests = ref(2);
</script>非受控组件(ref获取DOM)
vue
<template>
<form @submit.prevent="handleSubmit">
<input type="file" ref="fileInput" />
<button type="submit">Submit</button>
</form>
</template>
<script setup>
import { ref } from 'vue';
const fileInput = ref(null);
function handleSubmit() {
if (fileInput.value && fileInput.value.files.length > 0) {
alert(`Selected file - ${fileInput.value.files[0].name}`);
}
}
</script>插槽(Slots)
插槽用于组件内容分发,实现灵活的组件组合。
vue
<!-- 父组件 -->
<FancyBorder color="blue">
<h1 class="Dialog-title">Welcome</h1>
<p class="Dialog-message">Thank you for visiting our spacecraft!</p>
</FancyBorder>
<!-- 子组件 FancyBorder.vue -->
<template>
<div :class="'FancyBorder FancyBorder-' + color">
<slot></slot>
</div>
</template>
<script setup>
const props = defineProps({ color: String });
</script>具名插槽
vue
<template>
<BaseLayout>
<template #header>
<h1>Header</h1>
</template>
<template #default>
<p>Main content</p>
</template>
<template #footer>
<p>Footer</p>
</template>
</BaseLayout>
</template>Provide/Inject
用于祖先组件向后代组件传递数据,无需逐层props传递。
vue
<!-- 祖先组件 -->
<script setup>
import { provide } from 'vue';
provide('theme', 'dark');
</script>
<!-- 后代组件 -->
<script setup>
import { inject } from 'vue';
const theme = inject('theme', 'light');
</script>组合式API(Composition API)
组合式API通过setup函数、ref、reactive、computed、watch等实现更灵活的逻辑复用。
vue
<script setup>
import { ref, computed, watch } from 'vue';
const count = ref(0);
const double = computed(() => count.value * 2);
watch(count, (newVal, oldVal) => {
console.log('count changed:', oldVal, '->', newVal);
});
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ double }}</p>
<button @click="count++">Increment</button>
</div>
</template>片段(Fragment)
Vue 3支持组件返回多个根节点,无需额外包裹元素。
vue
<template>
<td>Hello</td>
<td>World</td>
</template>严格模式
Vue本身没有React的StrictMode,但开发环境下会有警告和提示,推荐开启严格类型检查和lint工具。