百科狗-知识改变命运!
--

组件基础 - defineProps()、defineEmits() - vue 组件

乐乐1年前 (2023-11-21)阅读数 22#技术干货
文章标签组件

组件基础

组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的编写。在实际应用中,组件常常被组织成层层嵌套的树状结构:

这和我们嵌套 HTML 元素的方式类似,Vue 实现了自己的组件模型,使我们可以,在每个组件内,封装自定义内容与逻辑。Vue 同样也能很好地配合原生 Web Component。

定义一个组件

当使用构建步骤时,我们一般会将 Vue 组件定义在一个单独的.vue文件中,这被叫做单文件组件(Single-File Component,简称 SFC):

 点击了 {{ count }} 次 

当不使用构建步骤时,一个 Vue 组件,以一个包含 Vue 特定选项的 JavaScript 对象,来定义:

import { ref } from 'vue'

export default { setup() {
    const count = ref(0)
    return { count }
  }, template: `
    
      You clicked me {{ count }} times.
    `
  // 或者 `template: '#my-template-element'`
}

这里的模板 template 是一个内联的 JavaScript 字符串,Vue 将会在运行时编译它。你也可以使用ID选择器,来指向一个元素(通常是原生的元素),Vue 将会使用其内容作为模板来源。

上面的例子中定义了一个组件,并在一个.js文件里默认导出了它自己。但你也可以在一个指定名称的文件中,导出多个组件。


使用组件

要使用一个子组件,我们需要在父组件中导入它。假设我们把计数器组件放在了一个叫做ButtonCounter.vue的文件中,这个组件将会以默认导出的形式被暴露给外部。

 

这里是一个子组件!

通过


传递 props

如果我们正在构建一个博客,我们可能需要一个表示博客文章的组件。我们希望所有的博客文章分享相同的视觉布局,但有不同的内容。要实现这样的效果自然必须向组件中传递数据,例如每篇文章标题和内容,这就会使用到props。

props是一种特别的 attributes,你可以在组件上声明注册。要传递给博客文章组件一个标题,我们必须在组件的props列表上,使用defineProps宏,声明它:

 

{{ title }}

defineProps是一个仅

这记录了一个组件发出的所有事件,并可选择对其进行验证。这还使得 Vue 避免了将它们作为原生事件监听器隐式地应用于子组件的根元素。

defineProps类似,defineEmits仅可用于


通过插槽来分配内容

和 HTML 元素一样,像这样能够向组件中传递内容是非常有用的:

 发生了一些错误。 

这会渲染成这样:

这可以通过 Vue 的自定义元素来实现:

 
Error!
.alert-box { /* ... */ }

正如你上面所看到的,我们使用作为一个占位符,之后的内容就会放在这里。


动态组件

有的需求会想要在两个组件间来回切换,比如 Tab 界面:

 
{{ tab }}


上面的例子是通过 Vue 的元素和特殊的is attribute 实现的:

在上面的例子中,被传给:is的值可以是以下几种:

  • 被注册的组件名
  • 导入的组件对象

你也可以使用is attribute 来创建一般的 HTML 元素。

当使用来在多个组件间作切换时,组件会在被切换掉后卸载。我们可以通过组件强制不活跃的组件仍然保持“存活”的状态。

 


DOM 模板解析注意事项

字符串模板来源:
  • 单文件组件。以.vue后缀结尾的文件。
  • 内联模板字符串,例如template:'...'。
DOM 模板来源:以.html后缀结尾的文件。

如果你想在 DOM 中直接书写 Vue 模板,Vue 则必须从 DOM 中获取模板字符串。因为浏览器的原生 HTML 解析行为,因此有一些需要注意的事项。

大小写区分

HTML 标签和属性名称是不分大小写的,所以浏览器会把任何大写的字符解释为小写。这意味着当你使用 DOM 内的模板时,无论是PascalCase形式的组件名称、camelCase形式的prop名称还是v-on的事件名称,都需要转换为相应等价的kebab-case(短横线连字符)形式:

// JavaScript 中的 camelCase
const BlogPost = {
  props: ['postTitle'],
  emits: ['updatePost']
  template: ` 

{{ postTitle }}

` }


闭合标签

我们在上面的例子中已经使用过了闭合标签(self-closing tag):

这是因为 Vue 的模板解析器将/>作为标签关闭的标志,无关其类型。

然而在 DOM 模板中,我们必须显式地写出关闭标签:

这是由于 HTML 只允许一小部分特殊的元素省略其关闭标签,最常见的就是。对于其他的元素来说,如果你省略了关闭标签,原生的 HTML 解析器会认为开启的标签永远没有结束,用下面这个代码片段举个例子:

 hello

将被解析为:

 hello 


元素位置限制

组件基础 - defineProps()、defineEmits() - vue 组件

某些 HTML 元素对于放在其中的元素类型有限制,例如

      ,相应的,某些元素仅在放置于特定元素中时才会显示,例如
    1. 组件基础 - defineProps()、defineEmits() - vue 组件

      这将导致在使用带有此类限制元素的组件时出现问题。例如:

      自定义的组件将作为无效的内容被忽略,因而在最终呈现的输出中造成错误。我们可以使用特殊的is attribute 作为一种解决方案:

      当使用在原生 HTML 元素上时,is的值必须加上前缀vue:才可以被解析为一个 Vue 组件。这一点是必要的,为了避免和原生的自定义内置元素相混淆。



      HTML attribute(特性)和 DOM property(属性)

      HTML attributeDOM property
      举例标准 attributeidclasstypetitledata

      非标准 attribute:自定义的data-*
      取值字符串或 null任意合法 js 数据类型
      大小写对大小写不敏感对大小写敏感
      不存在时返回值如果是标准属性,返回"";如果是非标准属性,返回 nullundefined
      对于 href返回 html 设置的值返回解析后的完整 URL
      更新 valueproperty也更新attribute值不更新
      • 当浏览器解析网页时,将 HTML attribute(特性)映射为 DOM property(属性)。attribute → property。只映射标准 attribute;非标准 HTML attribute 并不会自动映射为 DOM property。当我们使用data-开头的attribute时,会映射到 DOM 的dataset property。中划线格式会变成驼峰格式。
      • DOM 对象也提供了操作特性的 API,可以获取非标准的 attributes。DOM 操作 HTML attribute 方法主要有三个,分别是getAttribute()setAttribute()removeAttribute()


      映射

      编写一段HTML代码的时候,你可以在 HTML 标签上面定义attribute,当浏览器编译完 HTML 代码,会生成与之对应的一个个DOM节点,每个DOM节点是一个对象,所以它拥有很多property。例如以下代码:

      input标签有两个attribute,即typevalue。当浏览器编译完这段代码,一个HTMLInputElement对象会被创建,这个对象包含一系列的property,例如acceptaccessKeyalignaltattributesautofocusbaseURIcheckedchildElementCountchildNodeschildrenclassListclassNameclientHeight等。


      例解

      • 对于一个 DOM 节点对象,property就是这个对象上的属性;attribute是该对象对应的HTML标签元素上的特性。
      • 当一个HTML标签元素解析成一个 DOM 节点对象时,这个节点对象上有很多property属性名和HTML标签元素上的attribute存在映射关系,或相同或相似,但不是全部都一一映射关系。

      比如:

      对于上述HTML标签,其对应的DOM节点对象的property包括idtypevalue(当然还有别的):

      • id:DOM节点对象上的id property和HTML标签上的id attribute是映射关系。当读取DOM节点对象的id属性值时就是读取HTML标签上的id特性值,当给DOM节点对象的id属性写入值时就是往HTML标签上的id特性写入值。id是一个纯映射特性,映射过程中不会产生副作用,比如修改或者限制其值。
      • type:DOM节点对象上的type property和HTML标签上的type attribute是映射关系。当读取DOM节点对象的type属性值时就是读取HTML标签上的tyep特性值,当给DOM节点对象的type属性写入值时就是往HTML标签上的type特性写入值。但是,type属性是一个非纯映射特性,因为在映射过程中,它的值会被限制在已知类型中,比如 input 支持的有效 type类型。举个例子,对于这样一个HTML标签, Input.getAttribute('type')的返回值是foo,而Input.type的返回值为text
      • value:DOM节点对象上的value property和HTML标签上的value attribute不存在映射关系,它就是当前input输入框的值。当用户改变输入框中的值,DOM对象上的value属性会跟着变化。假如用户在输入框中输入'John',那么Input.value的返回值是John,而Input.getAttribute('value')的返回值是Name:。


      从上面可以看出,DOM节点对象上的value property是当前输入框内容的映射,而HTML标签上的value attribute是HTML标签元素上初始设置的值(或者代码设置)。

      如果你需要知道当前输入框的内容,就直接读取DOM节点对象的value property;如果你想知道输入框的初始值是什么,就直接读取 HTML 标签元素的 value attribute,或者使用DOM节点对象的 defaultValue 属性,它与HTML标签上的value attribute是纯映射关系:

      Input.value                 // returns "John"
      Input.getAttribute('value') // returns "Name:"
      Input.defaultValue          // returns "Name:"
      


      总结

      • 有些DOM节点对象上的property属性与 HTML 标签上的attribute特性一一映射(名字一样),比如relid
      • 有些名字稍微有些变化,比如 DOM节点对象htmlFor属性对应 HTML 标签上的for特性,DOM节点对象className属性对应 HTML标签上的class特性;
      • 更多的是两者虽然有映射关系,但是存在副作用,会限制或者修改属性值,比如srchrefdisabledmultiple等。

      鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com

      免责声明:我们致力于保护作者版权,注重分享,当前被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!邮箱:344225443@qq.com)

      图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

      内容声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。部分内容参考包括:(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供参考使用,不准确地方联系删除处理!本站为非盈利性质站点,本着为中国教育事业出一份力,发布内容不收取任何费用也不接任何广告!)