python tortoise-orm
2026/5/3 20:52:29
Vue 的组件可以按两种不同的风格书写 :组合式 API和选项式 API 。
通过组合式 API,可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与
<script setup>import{ref,onMounted}from'vue'// 响应式状态constcount=ref(0)// 用来修改状态、触发更新的函数functionincrement(){count.value++}// 生命周期钩子onMounted(()=>{console.log(`The initial count is${count.value}.`)})</script><template><button @click="increment">Count is:{{count}}</button></template>使用选项式 API,可以用包含多个选项的对象来描述组件的逻辑,例如data、methods和mounted。选项所定义的属性都会暴露在函数内部的this上,它会指向当前的组件实例。
<script>exportdefault{name:'',//`name` 属性标识组件名称components:{//使用 `components` 选项注册子组件}// data() 返回的属性将会成为响应式的状态// 并且暴露在 `this` 上data(){return{// 所有响应式数据在这里定义count:0};},// methods 是一些用来更改状态与触发更新的函数// 它们可以在模板中作为事件处理器绑定methods:{// 所有组件方法在这里定义},// 生命周期钩子会在组件生命周期的各个不同阶段被调用created(){/* 实例创建后 */},mounted(){/* DOM挂载后 */},updated(){/* 数据更新后 */},destroyed(){/* 实例销毁前 */},// 组件注册components:{// 子组件注册}}<script>export default是 ES6 模块系统的语法,用于导出模块的默认内容。在 Vue 中,它用于导出一个 Vue 组件配置对象
exportdefault{// 组件配置选项}当在另一个文件中使用import时,导入的就是这个默认导出的对象。
data(){return{newUser:{name:'',email:''},// 创建新用户时的表单数据users:[],// 存储从API获取的用户列表editingUser:null// 当前正在编辑的用户};}created(){this.fetchUsers();// 组件创建时自动获取用户列表}methods:{// 异步获取用户列表asyncfetchUsers(){try{constresponse=awaitaxios.get('https://api.example.com/users');this.users=response.data;// 更新响应式数据}catch(error){console.error('获取用户列表失败:',error);}}}组合式 API 的核心思想是直接在函数作用域内定义响应式状态变量,并将从多个函数中得到的状态组合起来处理复杂问题。这种形式更加自由,也需要对 Vue 的响应式系统有更深的理解才能高效使用。相应的,它的灵活性也使得组织和重用逻辑的模式变得更加强大。
选项式 API 是在组合式 API 的基础上实现的。选项式 API 以“组件实例”的概念为中心 (即上述例子中的this),基于面向对象概念实现。同时,它将响应性相关的细节抽象出来,并强制按照选项来组织代码。
以下是官方给出的建议:
export default定义的组件 有几种方式导入组件
<template> <div> <!-- 使用导入的组件 --> <ArticleList /> </div> </template> // 选项式 <script> // 导入组件 import ArticleList from '@/components/ArticleList.vue' export default { name: 'ParentComponent', components: { // 注册导入的组件 ArticleList } } </script>方法一:使用 ref 引用
<template> <div> <button @click="refreshArticles">刷新文章</button> <button @click="createNewArticle">创建文章</button> <!-- 给组件添加 ref 属性 --> <ArticleList ref="articleListRef" /> </div> </template> <script> import ArticleList from '@/components/ArticleList.vue' export default { name: 'ParentComponent', components: { ArticleList }, methods: { refreshArticles() { // 调用子组件的 fetchArticles 方法 this.$refs.articleListRef.fetchArticles() }, createNewArticle() { // 调用子组件的 handleCreateArticle 方法 this.$refs.articleListRef.handleCreateArticle() } } } </script>方法二:通过 props 传递回调函数
父组件:
<template> <div> <ArticleList :onRefresh="handleRefresh" :onCreate="handleCreate" /> </div> </template> <script> import ArticleList from '@/components/ArticleList.vue' export default { components: { ArticleList }, methods: { handleRefresh() { console.log('父组件处理刷新逻辑') }, handleCreate(articleData) { console.log('父组件处理创建逻辑', articleData) } } } </script>子组件 (ArticleList.vue):
<script> export default { name: 'ArticleList', props: { onRefresh: Function, onCreate: Function }, methods: { fetchArticles() { // 原有的获取文章逻辑 fetch('http://localhost:8000/posts') .then(r => r.json()) .then(data => { this.articles = data // 如果有传递回调函数,则调用 if (this.onRefresh) { this.onRefresh(data) } }) }, handleCreateArticle() { // 原有的创建逻辑... // 如果有传递回调函数,则调用 if (this.onCreate) { this.onCreate(this.newArticle) } } } } </script>父组件
<template> <div class="parent"> <h1>博客管理</h1> <div class="controls"> <button @click="triggerRefresh" :disabled="isLoading"> {{ isLoading ? '加载中...' : '刷新文章' }} </button> <button @click="showCreateForm = true">新建文章</button> </div> <!-- 使用子组件 --> <ArticleList ref="articleList" :externalCreateData="createFormData" @articles-loaded="onArticlesLoaded" @article-created="onArticleCreated" /> <!-- 父组件的创建表单 --> <div v-if="showCreateForm" class="modal"> <h3>创建新文章</h3> <input v-model="createFormData.title" placeholder="标题"> <textarea v-model="createFormData.content" placeholder="内容"></textarea> <button @click="submitCreateForm">提交</button> <button @click="cancelCreate">取消</button> </div> </div> </template> <script> import ArticleList from '@/components/ArticleList.vue' export default { name: 'BlogManagement', components: { ArticleList }, data() { return { isLoading: false, showCreateForm: false, createFormData: { title: '', content: '' } } }, methods: { // 触发子组件的刷新方法 triggerRefresh() { this.isLoading = true this.$refs.articleList.fetchArticles() }, // 触发子组件的创建方法 submitCreateForm() { this.$refs.articleList.handleCreateArticle(this.createFormData) this.showCreateForm = false }, cancelCreate() { this.showCreateForm = false this.createFormData = { title: '', content: '' } }, // 监听子组件的事件 onArticlesLoaded(articles) { this.isLoading = false console.log('文章加载完成:', articles) }, onArticleCreated(newArticle) { console.log('新文章创建:', newArticle) this.createFormData = { title: '', content: '' } } } } </script>子组件 (ArticleList.vue)
<template> <div class="article-list"> <div v-if="articles.length === 0" class="empty">暂无文章</div> <ArticleCard v-for="article in articles" :key="article.id" :article="article" /> </div> </template> <script> import ArticleCard from './ArticleCard.vue' export default { name: 'ArticleList', components: { ArticleCard }, props: { // 从父组件接收创建数据 externalCreateData: { type: Object, default: () => ({ title: '', content: '' }) } }, data() { return { articles: [], newArticle: { title: '', content: '', author: '左越' } } }, watch: { // 监听外部创建数据的变化 externalCreateData: { handler(newData) { if (newData.title || newData.content) { this.newArticle = { ...newData, author: '左越' } this.handleCreateArticle() } }, deep: true } }, created() { this.fetchArticles() }, methods: { async fetchArticles() { try { const response = await fetch('http://localhost:8000/posts') const data = await response.json() this.articles = data // 触发事件通知父组件 this.$emit('articles-loaded', data) } catch (err) { console.log('error', err) this.$emit('articles-loaded', []) } }, async handleCreateArticle(externalData = null) { const articleData = externalData || this.newArticle if (!articleData.title.trim() || !articleData.content.trim()) { alert('请填写所有字段') return } try { const response = await fetch('http://localhost:8000/posts', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(articleData) }) const newArticle = await response.json() this.articles.unshift(newArticle) // 触发事件通知父组件 this.$emit('article-created', newArticle) // 重置表单 this.resetForm() } catch (err) { console.error('error: ', err) } }, resetForm() { this.newArticle = { title: '', content: '', author: '左越' } } } } </script>import ComponentName from 'path/to/component'components选项中注册this.$refs.refName.methodName()调用子组件方法this.$emit('event-name', data),父组件使用@event-name="handler"选择哪种方式取决于具体需求:
refprops和events这种结构让 Vue 能够自动处理数据与视图的同步,大大简化了前端开发的复杂度。
愿你我都能在各自的领域里不断成长,勇敢追求梦想,同时也保持对世界的好奇与善意!