文档教程前端【免费下载链接】Web千古前端图文教程超详细的前端入门到进阶知识库。从零开始学前端做一名精致优雅的前端工程师。项目地址https://gitcode.com/gh_mirrors/we/Web点击查看免费下载导读本文以「千古前端图文教程」12-Vue基础 章节的《Vue 组件的定义和注册》一文为主体系统讲解 Vue 2 组件从概念、定义、注册到使用、切换的完整链路包括Vue.extend、Vue.component、template标签三种全局组件注册写法components私有组件的定义方式组件data必须为函数的原因以及通过v-if/v-else、component :is实现组件切换并配合transition添加过渡动画的完整方案。学完本文你将能够独立写出可复用、数据隔离、可动态切换的前端组件代码并理解组件化开发的底层设计动机。一、认识组件为什么要拆分 Vue 实例1.1 什么是组件组件Component是 Vue.js 最强大的功能之一组件的出现就是为了拆分 Vue 实例的代码量让我们能够以不同的组件来划分不同的功能模块。将来需要什么样的功能就可以去调用对应的组件即可。组件可以扩展 HTML 元素封装可重用的代码。可以把组件理解成页面上的积木块登录框是一个组件、注册表单是一个组件、评论列表是一个组件。每一个组件都自带自己的模板template、数据data和行为methods组装起来就是一个完整的页面。1.2 模块化和组件化的区别两者虽然都叫化但划分的视角完全不同维度模块化组件化划分角度从代码逻辑的角度划分从UI 界面的角度划分目的方便代码分层开发保证每个功能模块的职能单一方便 UI 组件的重用举例工具函数模块、网络请求模块登录组件、注册组件、轮播图组件简单说模块化解决的是代码怎么组织的问题组件化解决的是界面怎么复用的问题。两者相辅相成共同降低大型应用的维护成本。二、全局组件的定义和注册全局组件通过Vue.component()注册注册后所有的 Vue 实例都可以直接使用。本文档给出了三种典型写法下面逐一展开。2.1 写法一Vue.extend 定义 Vue.component 注册这种写法把定义组件和注册组件分成两步第一步使用Vue.extend方法定义组件得到组件模板对象第二步使用Vue.component方法注册组件。!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head body div idapp !-- 如果要使用组件直接把组件的名称以 HTML 标签的形式引入到页面中即可 -- account /account /div script //第一步使用 Vue.extend 定义组件 var myAccount Vue.extend({ template: divh2登录页面/h2 h3注册页面/h3/div // 通过 template 属性指定了组件要展示的HTML结构。template 是 Vue 中的关键字不能改。 }); //第二步使用 Vue.component 注册组件 // Vue.component(组件的名称, 创建出来的组件模板对象) Vue.component(account, myAccount); //第一个参数是组件的名称标签名第二个参数是模板对象 new Vue({ el: #app }); /script /body /html上方代码中在注册组件时第一个参数是标签名account第二个参数是组件的定义myAccount。2.2 写法二Vue.component 一步到位写法二不再单独调用Vue.extend而是直接把组件定义对象作为Vue.component的第二个参数传入一步完成定义 注册!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head body div idapp account /account /div script //定义、注册组件第一个参数是组件的名称标签名第二个参数是组件的定义 Vue.component(account, { template: divh2登录页面/h2 h3注册页面/h3/div // template 是 Vue 中的关键字不能改。 }); new Vue({ el: #app }); /script /body /html2.3 写法三【推荐】将组件内容定义到 template 标签中写法一、写法二并不算智能因为模板是以字符串形式写在 JavaScript 里的没有智能提示和高亮写长了容易出错。写法三的改进是把组件的 HTML 结构写进页面上的template idxxx标签中然后在注册组件时通过template: #id引用它。!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head body !-- 定义模板 -- template idmyAccount div h2登录页面/h2 h3注册页面/h3 /div /template div idapp !-- 使用组件 -- account /account /div script //定义、注册组件 Vue.component(account, { template: #myAccount // template 是 Vue 中的关键字不能改。 }); new Vue({ el: #app }); /script /body /html写法三其实和方法二差不多无非是把模板内容单独放在了template标签中而已这样有利于 HTML 标签的书写、缩进和语法高亮。在实际开发中强烈推荐这种写法。2.4 注册组件时的命名规范驼峰与短横线的对应关系注册组件时组件名支持驼峰命名camelCase例如Vue.component(myComponent, myAccount); //第一个参数是组件的名称标签名第二个参数是模板对象那么在使用时标签写法不能直接写myComponent而是需要把大写的驼峰改为小写字母并在两个单词之间使用-连接my-component /my-component所以为了避免注册名与使用名不一致的问题注册组件时可以直接把名称写成短横线分隔形式kebab-case例如Vue.component(my-component, myAccount);这样写标签使用时就完全一致了不会出现驼峰转换的坑。2.5 模板必须有一个根元素包裹无论用哪种写法template中的内容必须由一个大的根元素例如div包裹起来。写成下面这样是没有预期效果的template: h2登录页面/h2 h3注册页面/h3原因在于 Vue 的模板编译器要求模板拥有唯一的根节点多个并列的顶层节点无法被正确挂载到虚拟 DOM 的单一根结构上。正确写法是把它们包进同一个divtemplate: divh2登录页面/h2 h3注册页面/h3/div三、使用 components 定义私有组件前面定义的是全局组件多个 Vue 实例都可以使用。我们还可以在一个 Vue 实例内部定义私有组件只有当前这个 Vue 实例才可以使用这个组件。3.1 私有组件的基本写法在创建 Vue 实例时通过components选项注意components是关键字不能改注册!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head body div idapp !-- 使用Vue实例内部的私有组件 -- my-login/my-login /div script new Vue({ el: #app, data: {}, components: { // 定义、注册Vue实例内部的私有组件 myLogin: { template: h3这是私有的login组件/h3 } } }); /script /body /html3.2 私有组件 template 标签【推荐】同样地私有组件的模板也可以存放在template标签中让 HTML 标签获得智能提示和高亮!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head body !-- 定义模板 -- template idloginTmp h3这是私有的login组件/h3 /template div idapp !-- 调用Vue实例内部的私有组件 -- my-login/my-login /div script new Vue({ el: #app, data: {}, components: { // 定义、注册Vue实例内部的私有组件 myLogin: { template: #loginTmp } } }); /script /body /html3.3 私有组件的命名同样要注意驼峰问题私有组件也遵循同样的命名规则。如果注册名是驼峰命名components: { // 定义、注册Vue实例内部的私有组件 myLogin: { template: #loginTmp } }那么使用时同样要转成小写加短横线my-login/my-login为了避免不一致注册名可以直接写成短横线形式kebab-casecomponents: { // 定义、注册Vue实例内部的私有组件 my-login: { template: #loginTmp } }补充在仓库的姊妹篇 Vue组件.md 中还讲解了在父组件内部继续嵌套子组件的用法——父组件通过自己的components选项注册子组件后子组件只能在父组件的template模板中调用其他组件乃至根组件都无法使用。这与私有组件作用域是同一设计思想。四、为组件添加 data 和 methods组件既然是一个页面就可能有需要动态展示的功能。因此有必要为组件添加data和methods。4.1 在组件中添加 data 和 methods!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head body !-- 定义组件的模板 -- template idmyAccount div !-- 在组件的模板中调用本组件中的data -- {{myData}} a href# v-on:clicklogin登录1/a h2登录页面/h2 h3注册页面/h3 /div /template div idapp !-- 第一次调用组件 -- account /account !-- 第二次调用组件 -- account /account /div script //定义、注册组件 Vue.component(account, { template: #myAccount, //组件中的 data //【注意】组件中的data不再是对象而是一个方法否则报错而且这个方法内部还必须返回一个对象才行 // 组件中 的data 数据,使用方式,和实例中的 data 使用方式完全一样!!! data: function () { return { myData: smyhvae } }, //组件中的 method methods: { login: function () { alert(login操作); } } }); new Vue({ el: #app }); /script /body /html上方代码所示我们在account组件中添加的data和methods其作用域只限于account组件里保证独立性。注意为组件添加数据时data不再是对象而是function而且必须通过return的形式返回一个对象否则页面无法看到效果。通过函数返回对象的形式来定义data其作用是上方代码中组件account被调用了两次不像根组件那样只能调用一次但每个组件里的数据myData是各自独立的不产生冲突换而言之通过函数返回对象的目的是为了让每个组件都有自己独立的数据存储而不应该共享一套数据。4.2 为什么组件的 data 必须是一个 function我们先用一个反面案例来直观理解。下面这个计数器组件被调用了两次但data函数返回的是全局对象dataObj!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head body div idapp !-- 第一次调用组件 -- counter/counter hr !-- 第二次调用组件 -- counter/counter /div !-- 定义模板 -- template idtmpl div input typebutton value让count加1 clickincrement h3{{count}}/h3 /div /template script var dataObj { count: 0 } // 这是一个计数器的组件, 身上有个按钮,每当点击按钮,让 data 中的 count 值 1 Vue.component(counter, { template: #tmpl, data: function () { return dataObj //当我们return全局的dataObj的时候子组件们会共享这个dataObj }, methods: { increment() { this.count } } }) // 创建 Vue 实例得到 ViewModel var vm new Vue({ el: #app, data: {}, methods: {} }); /script /body /html运行效果将组件counter调用了两次由于dataObj是全局对象两个组件实例都可以共享这个dataObj数据。于是点击任何一个组件实例的按钮都会让count数据加 1——两个计数器互相干扰无法单独计数。现在问题来了如果想让组件counter的两个实例单独操作count数据应该怎么做答案是修改data中return出去的内容——返回一个新开辟的对象!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head body div idapp counter/counter hr counter/counter hr counter/counter /div template idtmpl div input typebutton value让count加1 clickincrement h3{{count}}/h3 /div /template script var dataObj { count: 0 } // 这是一个计数器的组件, 身上有个按钮,每当点击按钮,让 data 中的 count 值 1 Vue.component(counter, { template: #tmpl, data: function () { // return dataObj //当我们return全局的dataObj的时候这个dataObj是共享的 return { count: 0 } // 【重要】return一个**新开辟**的对象数据 }, methods: { increment() { this.count } } }) // 创建 Vue 实例得到 ViewModel var vm new Vue({ el: #app, data: {}, methods: {} }); /script /body /html运行效果每当创建一个新的组件实例时就会调用data函数data函数里会return一个新开辟的对象数据。这样做就可以保证每个组件实例有独立的数据存储。结论组件data必须是函数本质上是利用每次调用函数都新建一个对象的机制让每个组件实例都拥有属于自己的数据副本避免多个实例共享同一份数据而互相污染。五、组件的切换实际页面中经常需要在多个组件之间切换显示本文档提供了两种主流方案。5.1 使用 v-if 和 v-else 结合 flag 进行切换适合二选一的场景例如登录组件 / 注册组件!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head body div idapp !-- 温馨提示.prevent可以阻止超链接的默认事件 -- a href click.preventflagtrue登录/a a href click.preventflagfalse注册/a !-- 登录组件/注册组件同时只显示一个 -- login v-ifflag/login register v-elseflag/register /div script Vue.component(login, { template: h3登录组件/h3 }) Vue.component(register, { template: h3注册组件/h3 }) // 创建 Vue 实例得到 ViewModel var vm new Vue({ el: #app, data: { flag: false }, methods: {} }); /script /body /html关于v-if/v-else的具体指令行为可进一步阅读仓库中的 02-Vue的系统指令.md。5.2 使用component标签 :is属性实现多组件切换上面的方案中flag的值只可能有两种情况也就是说v-if和v-else只能进行两个组件之间的切换。那如何实现三个甚至三个以上的组件切换可以用 Vue 提供的component标签。component是一个占位符它的:is属性用来指定当前要展示的组件名称。先看基础用法——让login组件显示出来!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcVue2.5.16.js/script /head body div idapp !-- Vue提供了 component ,来展示对应名称的组件 -- !-- 【重要】component 是一个占位符, :is 属性,可以用来指定要展示的组件名称。这里我们让 login 组件显示出来 -- component :islogin/component /div script // 组件名称是 字符串 Vue.component(login, { template: h3登录组件/h3 }) Vue.component(register, { template: h3注册组件/h3 }) // 创建 Vue 实例得到 ViewModel var vm new Vue({ el: #app, data: { comName: login // 当前 component 中的 :is 绑定的组件的名称 }, methods: {} }); /script /body /html上方代码中提取关键代码如下component :islogin/component要让register组件显示出来只需把:is的值改为registercomponent :isregister/component因此要实现组件之间的切换只需把component标签里:is的属性值设置为变量即可。实现组件切换的完整代码如下!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head body div idapp !-- 点击按钮后设置变量comName为不同的值代表着后面的component里显示不同的组件 -- a href click.preventcomNamelogin登录/a a href click.preventcomNameregister注册/a !-- Vue提供了 component ,来展示对应名称的组件 -- !-- component 是一个占位符, :is 属性,可以用来指定要展示的组件的名称 -- !-- 此处的comName是变量变量值为组件名称 -- component :iscomName/component /div script // 组件名称是 字符串 Vue.component(login, { template: h3登录组件/h3 }) Vue.component(register, { template: h3注册组件/h3 }) // 创建 Vue 实例得到 ViewModel var vm new Vue({ el: #app, data: { comName: login // 当前 component 中的 :is 绑定的组件的名称 }, methods: {} }); /script /body /html这样点击登录就把comName置为login点击注册就置为registercomponent占位符随之渲染对应的组件实现了登录/注册组件之间的动态切换。六、多个组件切换时通过 mode 属性添加过渡动画直接切换组件会显得生硬。Vue 提供了transition标签把组件包裹起来后就可以为切换过程添加过渡动画。!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script style .v-enter, .v-leave-to { opacity: 0; transform: translateX(150px); } .v-enter-active, .v-leave-active { transition: all 0.5s ease; } /style /head body div idapp a href click.preventcomNamelogin登录/a a href click.preventcomNameregister注册/a !-- 通过 mode 属性,设置组件切换时候的 过渡动画 -- !-- 【重点】亮点是 modeout-in 这句话 -- transition modeout-in component :iscomName/component /transition /div script // 组件名称是 字符串 Vue.component(login, { template: h3登录组件/h3 }) Vue.component(register, { template: h3注册组件/h3 }) // 创建 Vue 实例得到 ViewModel var vm new Vue({ el: #app, data: { comName: login // 当前 component 中的 :is 绑定的组件的名称 }, methods: {} }); /script /body /html上方代码中两个关键点transition包裹用transition把component占位符包起来Vue 会在组件切换时自动应用进入/离开过渡。modeout-in是关键它表示第一个组件完全消失之后第二个组件才会出现。如果没有这个mode属性第一个组件刚开始消失时第二个组件就马上出现新旧组件同时存在动画会重叠、跳动不是我们想要的效果。样式部分用到的是 Vue 内置的过渡类名.v-enter动画进入之前的初始状态配合.v-leave-to使用两者状态通常一致.v-leave-to动画离开之后的结束状态.v-enter-active、.v-leave-active进入/离开的时间段用来声明过渡时长与动画曲线如transition: all 0.5s ease;。关于过渡类名v-enter、v-enter-to、v-enter-active、v-leave、v-leave-to、v-leave-active的完整定义、前缀修改transition namemy对应.my-enter等以及 JS 钩子过渡可进一步阅读仓库中的 10-Vue动画.md。七、延伸组件定义之后的通信能力掌握了组件的定义与注册接下来自然是组件之间的数据传递。仓库的下一篇文档 12-Vue组件之间的传值.md 给出了完整的通信方案这里先做要点速览便于衔接父组件向子组件传值通过props属性。在子组件中用props: [parentMsg]声明接收的属性父组件在引用子组件时通过属性绑定v-bind:简写:传入。注意props中的数据是只读的子组件不要直接修改父组件传入的数据。子组件向父组件传值通过事件触发。子组件在方法内调用this.$emit(事件名, 参数)父组件在标签上通过事件名父组件方法监听即可收到子组件带出来的数据。父组件访问子组件通过ref属性给子组件起别名父组件用this.$refs.xxx拿到整个子组件实例进而读取其data或调用其methods。组件定义 → 注册 → 传值 → 复用正是 Vue 组件化开发的核心闭环。结语本文完整梳理了 Vue 2 组件从定义、注册到切换使用的全流程三种全局组件注册写法、私有组件定义、组件data必须为函数背后的数据隔离原理、v-if/v-else与component :is两种切换方案以及transition modeout-in的切换动画配置。建议读者逐个示例动手运行并结合仓库中 12-Vue组件之间的传值.md、10-Vue动画.md、Vue组件.md 继续深入即可快速打通 Vue 组件化开发的主干知识。赞分享文档教程前端【免费下载链接】Web千古前端图文教程超详细的前端入门到进阶知识库。从零开始学前端做一名精致优雅的前端工程师。项目地址https://gitcode.com/gh_mirrors/we/Web点击查看免费下载相关推荐WeChatMsg 快速上手指南10 分钟免费导出微信聊天记录WeChatMsg 快速上手指南10 分钟免费导出微信聊天记录 想找去年在群里说过的一句话结果被上万条新消息埋了底想把项目群的对话打印出来留档却只能一张人工智能AI AgentAI 应用前端后端MCP 服务TanStack Table 的 Octane 组件注册表类型 TableComponentType类型定义与 createTableHook 组件注册机制详解TanStack Table 的 Octane 组件注册表类型 TableComponentType类型定义与 createTableHook 组件注册机制详前端UI组件FAST 组件库 fastAnchor 变量详解从 DesignSystem 注册到自定义 Anchor 组件FAST 组件库 fastAnchor 变量详解从 DesignSystem 注册到自定义 Anchor 组件 fastAnchor 是 microsoft前端UI组件上一篇HP-Socket社区行为准则执行指南违规处理与申诉流程完整解析下一篇ART框架商标政策正确使用项目名称与Logo的规范创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考