Vue 组件化开发

怼烎@ 2023-02-26 12:29 120阅读 0赞

在这里插入图片描述

1.1 组件化简介

1.1.1 概述

  将实现页面某一部分功能的结构、样式和逻辑封装成为一个整体,使其高内聚,低耦合,达到分治与复用的目的。在前端范畴,我们可以用下面的这张图来简单地理解组件化:

在这里插入图片描述

  这样看起来,组件化前端开发就像造一辆车,我们将轮子、发动机、悬挂、车身车门等等各部分组装成一辆车,轮子、发动机就是组件,车就是最终产品。我们将页头、侧边栏、页脚、内容区等等组件拼装起来组成了我们的页面。

1.1.2 意义

  在谈到组件化的意义时,很多人的看法都是组件化的目的是复用。在某一篇博客看到另一种想法,分而治之,我比较这一种想法,良好地组件化以后的组件,会表现出高内聚低耦合的特征,这会给我们带来好处;组件之间不会相互影响,能有效减少出现问题时定位和解决问题的时间;组件化程度高的页面,具有清晰的页面组织和高可读性的 HTML 结构代码,组件之间的关系一目了然;组件化会强迫开发人员划清各个组件的功能边界,使得开发出的功能更加健壮;所以分而治之才是组件化的意义所在,复用只是它的副作用。同时我们还有很多其他方式都可以做到复用,这并不是组件化的专利。

在这里插入图片描述

1.1.3 组件化与模块化

  模块化是一种处理复杂系统分解成为更好的可管理模块的方式。它可以通过在不同组件设定不同的功能,把一个问题分解成多个小的独立、互相作用的组件,来处理复杂、大型的软件。似乎在后端领域,组件化和模块化说的是同一件事。但在我的理解中,前端领域的组件化和模块化是两个概念。先说结论:组件化是从产品功能角度进行分割,模块化是从代码实现角度进行分割,模块化是组件化的前提和基础。
  当我们将一段代码写成一个模块的时候,它有可能是一个函数、一个对象或者其他什么做了一件单一事情的东西,我们将它做成模块是因为它完成了一个单一的功能,并且这个功能很多地方都可能用得到。而当一个组件被从产品中抽象出来,它有时候就只是一个模块,但有时候却有相对复杂的实现,它就可能会有多个模块。我们说一个日期选择器是一个组件,但实现它的时候,我们分成了计算模块、渲染模块、用户输入响应模块等等模块来实现。一个单一产品功能的实现,可能是由多个模块来实现的。这样理解起来,其实可以说组件化是更粗粒度的模块化,它是在产品功能上的模块化。

在这里插入图片描述

1.2 组件注册

1.2.1 全局组件

  使用 Vue.component("组件名称", { }) 进行组件注册,全局组件注册后,任何 Vue 实例都可以使用;组件其实也是一个 Vue 实例,因此它在定义时也有:data、methods、生命周期函数等。不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有 el 属性。但是组件渲染需要 html 模板,所以增加了 template 属性,值就是 HTML 模板,模板中只能有一个根标签。data 必须是一个函数,不再是一个对象。因此组件复用时各个组件之间互补影响。

  1. <div id="app">
  2. <first></first>
  3. </div>
  4. <script> Vue.component("first",{ // 使用 ` 将 HTML 代码包裹起来,可以不用加换行符,使用 " 需要加换行符 template: ` <div> <h1>China---{ {year}}---{ {msg}}</h1> </div> `, data() { return { msg: "大好河山", year: 2019 } } }); var app = new Vue({ el:"#app" }); </script>

在这里插入图片描述

1.2.3 局部组件

局部组件只有在当前注册它的 Vue 实例中使用

语法

  1. // 注册组件
  2. var component_name = {
  3. template:'',
  4. data(){
  5. return { }
  6. }
  7. };
  8. // 引用组件
  9. var app = new Vue({
  10. el:"#app",
  11. components:{
  12. component_name: first // 将定义的对象注册为组件
  13. component_name // 组件名与对象名一致时可以简写
  14. }
  15. })

示例

  1. <div id="app">
  2. <!-- 组件复用 -->
  3. <first></first>
  4. <first></first>
  5. <first></first>
  6. </div>
  7. <script> var first = { template:'<button v-on:click="count++">{ { count }} 次</button>', data(){ return { count:0 } } } var app = new Vue({ el:"#app", components: { first } }); </script>

在这里插入图片描述

1.3 单文件组件

1.3.1 概述

  显然,组件注册的两种写法都是在同一个页面完成的,而且没有 CSS 样式等,这样的组件是没有意义的,因此我们需要将“组件”抽离开来。Vue 单文件组件每个单文件组件的后缀名都是 .vue 优化了传统全局组件的一些弊端(模板缺乏高亮、没有 css 等) 每一个 Vue 单文件组件都由 template、script、style 三部分组成。

  1. <template>
  2. <!-- 组件代码区域 -->
  3. </template>
  4. <style scoped> /* 样式代码区域 */ </style>
  5. <script> // js 代码区域 </script>

1.3.2 编写一个组件

  由于每个组件都是独立的,要想被引用,需要将其暴露出来,使用 export default { } 导出默认成员,使用 export A 可以按需导出。引用组件的那一方需要使用 import 接收名称 from "模块路径" 将其到导入本页面。使用 import { A, B } from "模块路径" 可以按需导入。

  1. <template>
  2. <div>
  3. <span class="font">{
  4. {msg}}</span>
  5. <button @click="fun">组件中的按钮</button>
  6. </div>
  7. </template>
  8. <style scoped> .font { font-size: 24px; color: #42b983; } </style>
  9. <script> // 只能存在一个默认暴露,内容与 Vue 示例类似 export default { // 组件的名称 name: 'myComponent', // 数据,与 Vue 实例类似 data() { return { msg: "Hello World", } }, // 方法,与 Vue 实例类似 methods: { fun() { alert("我是组件的方法") } } } // 单独暴露方法 export function funC() { alert("这是组件中 funC() 方法") } </script>

  如上所示,一个简单的组件就写好了,export default {} 中可以有 Vue 实例中除 el 属性的所有类容。如果我们只想要抽取方法,不想要页面,此时我们虽然可以写在 Vue 单文件组件中,但是非常不方便,我们可以将其写到 JS 文件中。

  1. export function funA() {
  2. alert("这是 js 中 funA() 方法")
  3. }
  4. export function funB() {
  5. alert("这是 js 中 funB() 方法")
  6. }

  一般我们使用 Vue 进行开发需要抽取的东西就只有组件和方法了,下面我们就可以将 MyComponent.vue 组件和 Fun.js 引入到页面中。页面也不再是熟知的 HTML,而是之前用到的 Vue 单文件组件。因此我们称引用组件的那一方为父组件,被引用的那一方为子组件。下面我们在 views 新建 vue 单文件组件编写我们的代码。Vue 中路径有个新的写法 @/ 表示 src 目录下。

  1. <template>
  2. <div>
  3. <my-component></my-component>
  4. <button @click="onA">按钮A</button>
  5. <button @click="onB">按钮B</button>
  6. <button @click="onC">按钮C</button>
  7. </div>
  8. </template>
  9. <style scoped> </style>
  10. <script> // 引入文件 import MyComponent from "@/components/MyComponent"; import { funC} from "../components/MyComponent"; import { funA, funB} from "@/components/MyFun"; export default { // 局部注册组件 components: { myComponent: MyComponent, }, data() { return { } }, methods: { onA() { funA(); }, onB() { funB(); }, onC() { funC(); } } } </script>

  启动项目,打开 http://localhost:8080/#/test,哎?怎么啥也没有,难道是哪里写错了。发现在 views 文件夹中还有两个文件,我们来访问试试,发现http://localhost:8080/#/home 也没有东西而 http://localhost:8080/#/about 有东西。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  产生上述问题的原因是 Vue 通过路由来找页面,而我们没有配置路由,所以找不到页面,那为什么自带的 Home.vue 也找不到呢?这是因为该页面配置的路径并不是 /home,查看路由可以发现 Home.vue 配置的路径是 /,所以直接使用 http://localhost:8080/#/ 就可以找到了。路由这里后面后详细说,这里只需要在 /route/index.js 中配好就可以了。参考 About、Home 的配置,我们配置好 Test 的路由,就可以访问到页面了。

  1. import Vue from 'vue'
  2. import VueRouter from 'vue-router'
  3. import Home from '../views/Home.vue'
  4. Vue.use(VueRouter)
  5. const routes = [
  6. {
  7. path: '/',
  8. name: 'Home',
  9. component: Home
  10. },
  11. {
  12. path: '/about',
  13. name: 'About',
  14. // route level code-splitting
  15. // this generates a separate chunk (about.[hash].js) for this route
  16. // which is lazy-loaded when the route is visited.
  17. component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  18. },
  19. {
  20. path: '/test',
  21. name: 'Test',
  22. // route level code-splitting
  23. // this generates a separate chunk (about.[hash].js) for this route
  24. // which is lazy-loaded when the route is visited.
  25. component: () => import(/* webpackChunkName: "about" */ '@/views/Test')
  26. }
  27. ]
  28. const router = new VueRouter({
  29. routes
  30. })
  31. export default router

在这里插入图片描述

1.4 组件之间的通信

1.4.1 父向子通信

  父组件发送信息的形式是以属性的形式绑定值到子组件身上。 然后子组件用属性 props 接收,使用 props 向子组件传递数据,首先要在子组件中定义子组件能接受的 props,然后在父组件中子组件的自定义元素上将数据传递给它。

子组件(MyComponent.vue)

  1. <template>
  2. <div>
  3. <span class="font">{
  4. {msg}}</span>
  5. <h1 class="font">{
  6. {title}}</h1>
  7. <span class="font">{
  8. {text}}</span>
  9. </div>
  10. </template>
  11. <style scoped> .font { font-size: 24px; color: #42b983; } </style>
  12. <script> export default { // 一个 vue 中只能存在一个 name: 'myComponent', props: ['title', 'text'], data() { return { msg: "Hello World", } }, methods: { } } </script>

父组件(Test.vue)

  1. <template>
  2. <div>
  3. <my-component :title="title" :text="text"></my-component>
  4. </div>
  5. </template>
  6. <style scoped> </style>
  7. <script> import MyComponent from "@/components/MyComponent"; export default { components: { myComponent: MyComponent, }, data() { return { title: "中国", text: "Java 开发者", } }, methods: { } } </script>

在这里插入图片描述

1.4.2 子向父通信

  但是如果子组件需要向父组件传递数据,则不能通过 props,Vue 2 中强调“单项数据流”,所谓“单向数据流”,即是数据的变动只能由外向内传递,而不能由内向外传递。组件只能将从 props 传递进来的数据进行使用,不能对其进行修改。我们唯一能做的,就是在子组件想要修改数据时,发送事件通知父组件修改。父组件通过监听子组件发送的这个事件,来决定需要做什么。 即:子组件不能直接向父组件传值,我们可以通过操作父组件的方法来实现通信。子组件用 $emit() 触发事件,父组件使用 v-on 来监听事件。

子组件(MyComponent.vue)

  1. <template>
  2. <div>
  3. 子组件的数值:<span class="font">{ { num}}</span>
  4. <br/>
  5. <button @click="fun"></button>
  6. </div>
  7. </template>
  8. <style scoped>
  9. .font {
  10. font-size: 24px;
  11. color: #42b983;
  12. }
  13. </style>
  14. <script>
  15. export default {
  16. name: 'myComponent',
  17. props: ['num'],
  18. data() {
  19. return {
  20. }
  21. },
  22. methods: {
  23. fun() {
  24. this.$emit("add-num");
  25. }
  26. }
  27. }
  28. </script>

父组件(Test.vue)

  1. <template>
  2. <div>
  3. 父组件的数值:{ { num}}
  4. <br/>
  5. <my-component :num="num" @add-num="add"></my-component>
  6. </div>
  7. </template>
  8. <style scoped>
  9. </style>
  10. <script>
  11. import MyComponent from "@/components/MyComponent";
  12. export default {
  13. components: {
  14. myComponent: MyComponent,
  15. },
  16. data() {
  17. return {
  18. num: 10,
  19. }
  20. },
  21. methods: {
  22. add() {
  23. this.num++;
  24. }
  25. }
  26. }
  27. </script>

在这里插入图片描述

1.4.3 兄弟组件通信

  兄弟组件之间传递数据需要借助于中间桥梁,通过中间桥梁传递数据,中间桥梁一般是空的 Vue 实例。 传递数据方,通过 hub.$emit(方法名,参数) 触发事件。接收数据方,通过在 mounted 钩子中用 hub.$on(方法名,(参数) => {}) 监听事件。销毁事件通过 hub.$off(方法名) 进行销毁,销毁之后无法进行传递数据。

中间桥梁(hub.js)

  1. import Vue from "vue";
  2. export default new Vue();

组件1(MyComponent1.vue)

  1. <template>
  2. <div>
  3. 子组件1的数值:<span class="font">{ { numa}}</span>
  4.   
  5. <button @click="fun">让 2 号组件 + 1</button>
  6. </div>
  7. </template>
  8. <style scoped>
  9. .font {
  10. font-size: 24px;
  11. color: #42b983;
  12. }
  13. </style>
  14. <script>
  15. import hub from "@/components/hub";
  16. export default {
  17. name: 'myComponent1',
  18. data() {
  19. return {
  20. numa: 0,
  21. }
  22. },
  23. mounted () {
  24. // 此处需要使用箭头函数,否侧 this 不代表组件
  25. hub.$on("myComponent1",(value) => {
  26. this.numa += value;
  27. })
  28. },
  29. methods: {
  30. fun() {
  31. hub.$emit("myComponent2",1);
  32. }
  33. },
  34. }
  35. </script>

组件2(MyComponent2.vue)

  1. <template>
  2. <div>
  3. 子组件2的数值:<span class="font">{ { numb}}</span>
  4.   
  5. <button @click="fun">让 1 号组件 + 2</button>
  6. </div>
  7. </template>
  8. <style scoped>
  9. .font {
  10. font-size: 24px;
  11. color: #42b983;
  12. }
  13. </style>
  14. <script>
  15. import hub from "@/components/hub";
  16. export default {
  17. name: 'myComponent2',
  18. data() {
  19. return {
  20. numb: 0,
  21. }
  22. },
  23. mounted() {
  24. hub.$on("myComponent2",(value) => {
  25. this.numb += value;
  26. })
  27. },
  28. methods: {
  29. fun() {
  30. debugger
  31. hub.$emit("myComponent1",2);
  32. }
  33. },
  34. }
  35. </script>

父组件(Test.vue)

  1. <template>
  2. <div>
  3. <my-component1 ></my-component1>
  4. <my-component2 ></my-component2>
  5. </div>
  6. </template>
  7. <style scoped>
  8. </style>
  9. <script>
  10. import MyComponent1 from "@/components/MyComponent1";
  11. import MyComponent2 from "@/components/MyComponent2";
  12. export default {
  13. components: {
  14. myComponent1: MyComponent1,
  15. myComponent2: MyComponent2,
  16. },
  17. data() {
  18. return {
  19. }
  20. },
  21. methods: {
  22. }
  23. }
  24. </script>

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,120人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Vue 开发

    Vue 组件化开发 什么叫做组件化 实例 什么叫做组件化 所谓组件化,就是把页面拆分成多个组件然后可重复利用,每个组件依赖的 CSS、JS、模板、图片

    相关 VUE.JS 开发实践

      [前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。][Link 1] 前言 公司目前制作一个H5活动,特别是有一定统

    相关 Vue.js 开发

    三、组件化开发 1.1 组件化的实现和使用步骤 组件注册步骤解析 1.2 全局组件和局部组件 1.3 父组件和子组件 1.4 注册组件