由于在日常开发中会有一部分前端的开发任务,会涉及到Vue的项目的搭建、迭代、构建发布等操作,所以想系统的学习一下Vue相关的知识点,本专题会依照Vue的搭建、开发基础实践、进阶用法、打包部署的顺序进行记录。
主要内容与历史文章链接如下:
从前面两篇的内容中我们已经知道了Vue3的基本语法使用,以及响应式的核心特性,通过这些知识已经可以完成一个简单的页面了。但是在实际的开发中,我们的项目是由很多个页面组成的,每个页面中又可能会有特别多的功能需要实现。
当代码越写越多之后,可能就会发现,不同的页面中有一些功能是重复的,此时我们就可以考虑将这些重复的功能抽取出来,写成一个个的组件来进行复用。
组件除了可以复用代码的作用以外,还可以形成功能的封装,使项目中的一个个功能点由一盘散沙变得内聚,我们在后续的迭代过程中,这种内聚的组件可以大大的提高我们修改、拓展的效率,同时也能降低改出bug的概率。
组件相关的内容将会分为两篇来编写,本篇主要讲述以下内容:
组件的定义是很宽泛的,我们任意打开一个页面,看到的每一个视图元素都可能是一个组件,例如在一个管理系统中,标题栏是一个组件,菜单栏是一个组件,Tab、列表、分页、表单甚至是一个简单的input输入框都可能是一个组件。
组件之间有父子关系、兄弟关系、祖孙关系等等,会像下图那样传递依赖:

我们需要做的,就是定义这一个一个的children,并处理它们的依赖关系以及组件之间的参数传递(通信)。接下来,我们先尝试定义一个组件。
如果创建一个和父组件没有通信关系的组件,其实就是创建一个普通.vue文件,我们在前面两篇中就已经使用过了。例如我现在创建一个计数器组件,提供一个按钮和一个展示数字的块,当点击按钮的时候数字块上的数字就+1。
{{ count }}
这样一个组件就写好了,接下来试试如何将这个组件注册到其他的组件中去。
局部注册组件有两个步骤:
import组件,并给组件命名中以组件的命名做为标签进行引入

在父组件上引入了两个Count效果如上图所示,两个引入的组件互不影响,各记各的数。这样就实现了组键功能的复用,而不需要到处复制一模一样的代码。
实际的开发中,我们很少会这么去使用组件,在某个父组件中引入子组件的时候,往往会建立通信关系,也就是组件之间会有属性、事件、字段值的传递。
全局注册就是在main.js中注册组件,这样注册的组件在任何一个组件中都可以使用,不再需要从块中引入。
import Count from "@/components/Count.vue";// 全局组件引入
app.component("Count", Count);
全局注册使用起来比较方便,但是没有明确的依赖关系,在日常的开发中更建议使用局部注册的方式。
组件除了共性以外,还会有一定的特性,这种特性展示可以通过父组件以props的形式传递到子组件中。还是以上面的计数器为例,我想给不同的计数器定义不同的名字。
要实现这个需求,可以在子组件中通过defineProps定义一个需要接收的变量,然后在父组件中通过定义的key将变量值传递到子组件中。
我们最子组件做一点小小的修改,在defineProps加入一个label: String,其中label就是定义的需要从父组件中接收的变量key,String表示的是这个变量的类型。通过defineProps定义的变量,可以在模板中直接使用{{ label }} 。
{{ label }}
在父组件的将label这个key作为属性写在标签中,如下所示两种方式,一种是直接在模板中写死计数器1,另一种是通过变量的方式来定义计数器2。

需要注意的是,通过props传入到子组件的变量值,不应该被子组件修改,这也是Vue的思想之一,在哪里定义的就在哪里修改,如果一定想要修改props的值,一般是通过定义一个由子组件触发的事件监听,触发父组件中的函数进行修改。
父子组件之间的时间监听就是定义一个事件,由子组件去触发,由父组件执行触发后的回调。通过事件监听,可以让子组件调用父组件中的函数,调用时可以传入形参,通过这种方式将子组件中的值传递到父组件中。如果说通过props是属性值由父到子,事件监听就可以实现由子到父。
对上面的计数器例子做一点小修改,显示计数的块放到父组件中,在每个子组件中点击了计数按钮后,父组件的计数值+1。
首先是子组件的修改,通过defineEmits定义并接收一个父组件传递过来的事件,例如就叫incrementCount,并通过一个add函数进行调用。
在父组件引用的标签中,通过@incrementCount="xxx"传递函数,此处的xxx值的是定义在父组件中的函数,可以是一个在script中显式定义的函数,也可以是一个匿名函数,如:@incrementCount="()=>xxx"。
父组件的计数:{{ count }}

此时不管点击哪一个,父组件的计数都会+1,大体流程图下图所示:

我们之前在单个组件中通过v-model建立了数据与视图的双向绑定,而父子组件的双向绑定,就是在父组件中定义一个变量,将它与子组件中的某个模板元素完成双向绑定。
例如现在有这么一个例子,在父组件中引入一个input子组件,将父组件中的inputValue变量与子组件中的输入框建立双向绑定关系。
首先需要定义子组件MyInput,通过defineProps定义需要接收的属性,通过defineEmits定义需要触发的函数。
这里有两个注意点:
v-model:xxx会提供一个@update:xxx的事件传递到子组件中,这里的xxx是一个标识,用于在一个子组件中有多个双向绑定的情况。props的值,如果在子组件中也需要通过v-model建立双向绑定关系,可以通过computed获取一个新的值。这里的属性计算多了一个setter属性,即在属性发生变化时,就通过emit触发父组件的事件。
在父组件中的使用就比较简单了,只需要添加v-model:xxx属性,并绑定一个变量就可以了。
{{ inputValue }}

这样就实现了父子组件的双向绑定。
通过一个实际的项目需求来综合使用一下上面提到的语法。
例如现在有一个消息系统的表单,这个表单中有一个文本域用以填写需要发送的短信模板,由于短信模板需要遵守一定的规则,所以不能让用户简单的自由填写,这个时候就可以通过子组件选择短信的开头签名与结尾,在选择后通过触发事件将短信模板的内容填充到父组件中。
这里我引入了Element Plus组件,不太清楚这个组件的可以通过《Element Plus安装文档》安装配置。
下面是实现代码:
是 否 确定 取消
模板填写
在弹窗子组件中安装操作流程进行操作:

点击确定之后,就可以在父组件中生成符合规范的短信模板了:

本篇主要讲述的是组件的通用功能抽取以及在其他组件中的引入使用,需要注意以下的细节点:
.vue文件APP对象进行引入,全局注册的组件,在组件中都可以直接使用import,只有当前组件可以使用html标签中传入实际的属性、函数、事件等,类似于实参defineProps定义需要接收的参数名及参数类型:参数名="属性值"的方式传递到子组件中defineEmits定义需要接收的事件名,并通过$emit或函数调用的方式触发@事件名="函数"的方式将实际需要执行的函数传递到子组件中defineProps(['xxx'])和defineEmits(['update:xxx'])定义需要接收的双向绑定的值。computed生成一个新的属性,通过v-model将这个新的属性与DOM绑定,在computed的getter方法中,获取props的值,在setter方法中,通过emit触发事件的调用v-model:xxx="待绑定属性"的方式,将自己的属性与子组件的DOM进行双向绑定。
上一篇:ZIP64压缩扩展的兼容性问题