Vue——组件基础

目录

定义一个组件​

使用组件​

传递 props​

监听事件​

通过插槽来分配内容​

动态组件​

DOM 模板解析注意事项​

大小写区分​

闭合标签​

元素位置限制​


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

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

定义一个组件​

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

<script>
export default {
  data() {
    return {
      count: 0
    }
  }
}
</script>

<template>
  <button @click="count++">You clicked me {{ count }} times.</button>
</template>

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

export default {
  data() {
    return {
      count: 0
    }
  },
  template: `
    <button @click="count++">
      You clicked me {{ count }} times.
    </button>`
}

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

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

使用组件​

TIP

我们会在接下来的指引中使用 SFC 语法,无论你是否使用构建步骤,组件相关的概念都是相同的。

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

<script>
import ButtonCounter from './ButtonCounter.vue'

export default {
  components: {
    ButtonCounter
  }
}
</script>

<template>
  <h1>Here is a child component!</h1>
  <ButtonCounter />
</template>

若要将导入的组件暴露给模板,我们需要在 components 选项上注册它。这个组件将会以其注册时的名字作为模板中的标签名。

当然,你也可以全局地注册一个组件,使得它在当前应用中的任何组件上都可以使用,而不需要额外再导入。

组件可以被重用任意多次:

<h1>Here is a child component!</h1>
<ButtonCounter />
<ButtonCounter />
<ButtonCounter />

 

你会注意到,每当点击这些按钮时,每一个组件都维护着自己的状态,是不同的 count。这是因为每当你使用一个组件,就创建了一个新的实例

在单文件组件中,推荐为子组件使用 PascalCase 的标签名,以此来和原生的 HTML 元素作区分。虽然原生 HTML 标签名是不区分大小写的,但 Vue 单文件组件是可以在编译中区分大小写的。我们也可以使用 /> 来关闭一个标签。

如果你是直接在 DOM 中书写模板 (例如原生 <template> 元素的内容),模板的编译需要遵从浏览器中 HTML 的解析行为。在这种情况下,你应该需要使用 kebab-case 形式并显式地关闭这些组件的标签。

<!-- 如果是在 DOM 中书写该模板 -->
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>

传递 props​

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

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

<!-- BlogPost.vue -->
<script>
export default {
  props: ['title']
}
</script>

<template>
  <h4>{{ title }}</h4>
</template>

当一个值被传递给 prop 时,它将成为该组件实例上的一个属性。该属性的值可以像其他组件属性一样,在模板和组件的 this 上下文中访问。

一个组件可以有任意多的 props,默认情况下,所有 prop 都接受任意类型的值。

当一个 prop 被注册后,可以像这样以自定义 attribute 的形式传递数据给它:

<BlogPost title="My journey with Vue" />
<BlogPost title="Blogging with Vue" />
<BlogPost title="Why Vue is so fun" />

 在实际应用中,我们可能在父组件中会有如下的一个博客文章数组:

export default {
  // ...
  data() {
    return {
      posts: [
        { id: 1, title: 'My journey with Vue' },
        { id: 2, title: 'Blogging with Vue' },
        { id: 3, title: 'Why Vue is so fun' }
      ]
    }
  }
}

这种情况下,我们可以使用 v-for 来渲染它们:

<BlogPost
  v-for="post in posts"
  :key="post.id"
  :title="post.title"
 />

 

留意我们是如何使用 v-bind 来传递动态 prop 值的。当事先不知道要渲染的确切内容时,这一点特别有用。

监听事件​

让我们继续关注我们的 <BlogPost> 组件。我们会发现有时候它需要与父组件进行交互。例如,要在此处实现 A11y 的需求,将博客文章的文字能够放大,而页面的其余部分仍使用默认字号。

在父组件中,我们可以添加一个 postFontSize 数据属性来实现这个效果:

data() {
  return {
    posts: [
      /* ... */
    ],
    postFontSize: 1
  }
}

 在模板中用它来控制所有博客文章的字体大小:

<div :style="{ fontSize: postFontSize + 'em' }">
  <BlogPost
    v-for="post in posts"
    :key="post.id"
    :title="post.title"
   />
</div>

 然后,给 <BlogPost> 组件添加一个按钮:

<!-- BlogPost.vue, 省略了 <script> -->
<template>
  <div class="blog-post">
    <h4>{{ title }}</h4>
    <button>Enlarge text</button>
  </div>
</template>

这个按钮目前还没有做任何事情,我们想要点击这个按钮来告诉父组件它应该放大所有博客文章的文字。要解决这个问题,组件实例提供了一个自定义事件系统。父组件可以通过 v-on 或 @ 来选择性地监听子组件上抛的事件,就像监听原生 DOM 事件那样:

<BlogPost
  ...
  @enlarge-text="postFontSize += 0.1"
 />

 子组件可以通过调用内置的 $emit 方法,通过传入事件名称来抛出一个事件:

<!-- BlogPost.vue, 省略了 <script> -->
<template>
  <div class="blog-post">
    <h4>{{ title }}</h4>
    <button @click="$emit('enlarge-text')">Enlarge text</button>
  </div>
</template>

因为有了 @enlarge-text="postFontSize += 0.1" 的监听,父组件会接收这一事件,从而更新 postFontSize 的值。

我们可以通过emits选项来声明需要抛出的事件:

<!-- BlogPost.vue -->
<script>
export default {
  props: ['title'],
  emits: ['enlarge-text']
}
</script>

                

这声明了一个组件可能触发的所有事件,还可以对事件的参数进行验证。同时,这还可以让 Vue 避免将它们作为原生事件监听器隐式地应用于子组件的根元素。          

通过插槽来分配内容​

一些情况下我们会希望能和 HTML 元素一样向组件中传递内容:

<AlertBox>
  Something bad happened.
</AlertBox>

我们期望能渲染成这样:

This is an Error for Demo Purposes

Something bad happened.

可以通过 Vue 的自定义 <slot> 元素来实现:

<template>
  <div class="alert-box">
    <strong>This is an Error for Demo Purposes</strong>
    <slot />
  </div>
</template>

<style scoped>
.alert-box {
  /* ... */
}
</style>

如上所示,我们使用 <slot> 作为一个占位符,父组件传递进来的内容就会渲染在这里。

 

动态组件​

有些场景会需要在两个组件间来回切换,比如 Tab 界面:

       

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

 

<!-- currentTab 改变时组件也改变 -->
<component :is="currentTab"></component>

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

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

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

当使用 <component :is="..."> 来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过<KeepAlive> 组件强制被切换掉的组件仍然保持“存活”的状态。

DOM 模板解析注意事项​

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

TIP

请注意下面讨论只适用于直接在 DOM 中编写模板的情况。如果你使用来自以下来源的字符串模板,就不需要顾虑这些限制了:

  • 单文件组件
  • 内联模板字符串 (例如 template: '...')
  • <script type="text/x-template">

大小写区分​

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

        

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

 

<!-- HTML 中的 kebab-case -->
<blog-post post-title="hello!" @update-post="onUpdatePost"></blog-post>

闭合标签​

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

<MyComponent />

这是因为 Vue 的模板解析器支持任意标签使用 /> 作为标签关闭的标志。

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

<my-component></my-component>

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

<my-component /> <!-- 我们想要在这里关闭标签... -->
<span>hello</span>

将被解析为:

<my-component>
  <span>hello</span>
</my-component> <!-- 但浏览器会在这里关闭标签 -->

元素位置限制​

某些 HTML 元素对于放在其中的元素类型有限制,例如 <ul><ol><table> 和 <select>,相应的,某些元素仅在放置于特定元素中时才会显示,例如 <li><tr> 和 <option>

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

<table>
  <blog-post-row></blog-post-row>
</table>

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

<table>
  <tr is="vue:blog-post-row"></tr>
</table>

TIP

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

 以上就是你需要了解的关于 DOM 模板解析的所有注意事项,同时也是 Vue 基础部分的所有内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/10674.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何用 YonBuilder 构建线索管理应用

加速企业数智营销&#xff1a;如何用 YonBuilder 构建线索管理应用 如何用 YonBuilder 低代码开发线索管理应用&#xff1f; 线索管理是指通过各种渠道收集、筛选、打分、分配、跟进和培育潜在客户的信息&#xff0c;以便将其转化为成交客户的过程。 通过数智化手段实现良好…

00后整顿职场,我直呼太卷了....

内卷的来源 内卷最早的“出处”是几张名校学霸的图片。 大学生们刷爆朋友圈的几张“内卷”图片是这样的&#xff1a;有的人骑在自行车上看书&#xff0c;有的人宿舍床上铺满了一摞摞的书&#xff0c;有的人甚至边骑车边端着电脑写论文。这些图片最早在清华北大的学霸之间流传。…

C++学习从基础到高阶(基于黑马程序员教程)

视频链接&#xff1a;黑马程序员匠心之作|C教程从0到1入门编程,学习编程不再难&#xff08;52个小时&#xff09; C语言中文网&#xff1a;http://c.biancheng.net/cplus/ Visual Studio 2022 下载地址&#xff1a;https://visualstudio.microsoft.com/zh-hans/downloads/ Visu…

JavaWeb - Web网站的组成,工作流程以及开发模式

一. Web Web&#xff1a;全球广域网&#xff0c;也称玩万维网(www Wrold Wide Web)&#xff0c;就是能够通过浏览器访问的网站学习Web开发&#xff0c;其实就是要使用Java这门语言来开发这样的Web网站&#xff0c;这也是现在Java语言最主流的企业级应用方式。使用Java语言开发…

PERSIANN 降雨数据使用教程

一、前言PERSIANN&#xff0c;“使用人工神经网络从遥感信息中估算降水”&#xff0c;是一种基于卫星的降水检索算法&#xff0c;可提供近乎实时的降雨信息。该算法使用来自全球地球同步卫星的红外 (IR) 卫星数据作为降水信息的主要来源。 红外图像的降水基于云顶温度和降水率之…

一位腾讯在职7年测试工程师的心声...

作为一个在腾讯工作7年的测试工程师&#xff0c;今天就来聊聊腾讯工作压力到底从何而来。 压力的开始&#xff1a;时间回到7年前&#xff0c;我人生中的第一份实习工作&#xff0c;是在腾讯公司做一个自动化测试工程师。当时的我可谓意气风发&#xff0c;想要大干一场&#xf…

工厂模式白话 - 3种都有哦

前言 工厂模式&#xff08;Factory Pattern&#xff09;里所谓的“工厂”和现实生活中的工厂一样 主要作用都是生产产品 像食品厂、服装厂、汽车厂生产吃的、穿的、开的 设计模式里的工厂则是生产对象 划分 工厂模式可分为简单工厂、工厂方法、抽象工厂3种 有啥不同呢&a…

PyTorch笔记

Tensor torch中的Tensor是一种数据结构&#xff0c;使用上与Python的list、numpy的array、ndarray等数据结构类似&#xff0c;可以当成一个多维数组来用。 数学上对张量有特定定义&#xff0c;但通常理解为多维数组即可。 生成Tensor&#xff1a;torch包中提供了直接生成Tens…

【微信小程序】初识微信小程序组件

作者简介&#xff1a;一名C站萌新&#xff0c;前来进行小程序的前进之路博主主页&#xff1a;大熊李子&#x1f43b; 一、组件的创建与引用 1.1 创建组件 在项目的根目录中&#xff0c;鼠标右键&#xff0c;创建 components -> test 文件夹在新建的 components -> test…

十分钟验证一个轻量化车联网解决方案

智能网联汽车在车联网的应用上&#xff0c;通常是以智能传感器、物联网、GIS技术为基础&#xff0c;结合大数据、人工智能技术&#xff0c;通过OT&#xff08;Operation tecnology&#xff09;和IT&#xff08;information tecnology&#xff09;融合的方式&#xff0c;实现智能…

2.3 连续性随机变量

思维导图&#xff1a; 学习目标&#xff1a; 我会按照以下步骤学习连续型随机变量&#xff1a; 复习概率论的基础知识&#xff0c;包括概率、期望、方差等概念和公式&#xff0c;以及离散型随机变量的概率分布函数和概率质量函数的概念和性质。 学习连续型随机变量的概念和性…

学生信息管理系统(student information manage system, SIMS)

一、前言 本项目为学生信息管理系统&#xff0c;使用C语言编写。 ★★★项目详见本人gitee仓库&#xff0c;地址 https://gitee.com/omnipotent-brother/student-information-manage-system.git ★★★ 二、项目介绍 开发环境&#xff1a; 基于windows 11系统下的Visual Studio…

YC-A11(原创)基于springboot,vue网上商城

绪论 课题的开发背景 随着计算机和网络的快速发展&#xff0c;并且越来越普及&#xff0c;互联网日益成为人们收集信息常用渠道&#xff0c;电子商务开始流行&#xff0c;一种全新的理念不断形成并且快速发展&#xff0c;像国内电商巨头淘宝、京东、苏宁易购、唯品会等电商平台…

【JavaScript】2.JavaScript函数

JavaScript 函数 1. 函数的概念 函数&#xff1a;就是封装了一段可被重复调用执行的代码块 通过此代码块可以实现大量代码的重复使用 2. 函数的使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta na…

前馈PID控制(热交换器/反应釜温度控制)

如何利用PID进行温度控制请参看下面博客文章: 博途PID 1200/1500PLC PID_Compact比例作用权重b微分作用权重c解读(PI-D控制器 I-PD控制器)_RXXW_Dor的博客-CSDN博客很多人会问PLC自带的PID指令和我们自己设计的PID有什么区别,这个问题要看你和什么PID控制器作对比,PID负反…

NDK RTMP直播客户端二

在之前完成的实战项目【FFmpeg音视频播放器】属于拉流范畴&#xff0c;接下来将完成推流工作&#xff0c;通过RTMP实现推流&#xff0c;即直播客户端。简单的说&#xff0c;就是将手机采集的音频数据和视频数据&#xff0c;推到服务器端。 接下来的RTMP直播客户端系列&#xff…

Redis用于全局ID生成器、分布式锁的解决方案

全局ID生成器 每个店铺都可以发布优惠卷 当用户抢购时&#xff0c;就会生成订单并保存到tb_voucher_order这张表中&#xff0c;而订单表如果使用数据库自增id就存在一些问题&#xff1a; 1.id的规律性太明显 2.受单表数据量的限制 全局ID生成器&#xff0c;是一种在分布式系…

Atlassian后Server时代 | Server版vs.数据中心版,二者的区别在哪里?

2024年2月&#xff0c;也就是一年不到&#xff0c;Atlassian将终止对Server产品及插件的所有支持。 此公告发布后&#xff0c;许多用户需要了解怎样的前进方向才是最适合企业的。为此&#xff0c;Atlassian提供了本地部署的数据中心&#xff08;Data Center&#xff09;版以及云…

线段树笔记草稿

一个左节点u << 1和右节点u << 1 | 1 的证明 区间修改部分 1.批量等值修改 前提条件 是要区间修改&#xff0c;区间查询&#xff0c;且修改操作修改的值是相同的 情景 一般是要对一个数组执行k次操作&#xff0c;每次改变其中一个区间内所有元素的值&#x…

ChatGPT文本框再次升级,打造出新型操作系统

在ChatGPT到来之前&#xff0c;没有谁能够预见。但是&#xff0c;它最终还是来了&#xff0c;并引起了不小的轰动&#xff0c;甚至有可能颠覆整个行业。 从某种程度上说&#xff0c;ChatGPT可能是历史上增长最快的应用程序&#xff0c;仅在两个多月就拥有了1亿多活跃用户&…