VUE官方文档学习---组件基础


title: VUE官方文档学习—组件基础
date: 2021-6-3 17:13:48
author: Xilong88
tags: Vue

基本示例

// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
new Vue({ el: '#components-demo' })
<div id="components-demo">
  <button-counter></button-counter>
</div>

组件是可以复用的Vue实例,所以可以接受与Vue相同的选项,如data,computed,watch,methods等,还有生命周期函数,除了根实例el。

组件的复用

组件的data需要写成一个方法,因为我们需要每个组件单独维护一个data所指的对象,所以我们可以用一个函数,返回一个对象,这样每个组件就单独维护自己的data了。

data: function () {
  return {
    count: 0
  }
}

假如直接写成data:{…}这种形式的话,就会导致所有的组件都指向一个data。

组件的组织

Vue的组件是通过树形组织的,组件要使用必须先注册,注册有两种,局部注册和全局注册,前面用Vue.component注册是全局注册,后续文档还会细讲,先不慌。

全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。

树状组织
通过 Prop 向子组件传递数据

可以通过配置props属性来给组件传递数据:

Vue.component('blog-post', {
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})

一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop

一个 prop 被注册之后,你就可以像这样把数据作为一个自定义 attribute 传入:

<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>

可以用v-for来渲染:

new Vue({
  el: '#blog-post-demo',
  data: {
    posts: [
      { id: 1, title: 'My journey with Vue' },
      { id: 2, title: 'Blogging with Vue' },
      { id: 3, title: 'Why Vue is so fun' }
    ]
  }
})
<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
></blog-post>

Vue根实例就可以把数据传给组件了。

单个根元素

模板应该被包裹在一个根元素里面:

<h3>{{ title }}</h3>
<div v-html="content"></div>

上面会报错:every component must have a single root element

应该像下面这样包裹在一个元素中,这里是div:

<div class="blog-post">
  <h3>{{ title }}</h3>
  <div v-html="content"></div>
</div>

假如一个组件有太多的属性,而这些属性其实都是一个对象的属性,那么我们可以绑定这个对象,而不是单独绑定属性。

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
  v-bind:content="post.content"
  v-bind:publishedAt="post.publishedAt"
  v-bind:comments="post.comments"
></blog-post>

这样就很复杂,其实有很多属性都是post的属性,改成这样:

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:post="post"
></blog-post>
Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <div v-html="post.content"></div>
      <div v-html="post.publishedAt"></div>
      <div v-html="post.comments"></div>
    </div>
  `
})

这样我们要在template里面去使用post的属性都是可以访问的了,不用单独绑定。

这里template使用了模板字符串,之前的JavaScript的教程中谈到过,它会保留换行,而IE不支持,想要IE支持需要用转义字符。

监听子组件事件

通过 $emit 方法来进行事件交互:

new Vue({
  el: '#blog-posts-events-demo',
  data: {
    posts: [/* ... */],
    postFontSize: 1
  }
})
<div id="blog-posts-events-demo">
  <div :style="{ fontSize: postFontSize + 'em' }">
    <blog-post
      v-for="post in posts"
      v-bind:key="post.id"
      v-bind:post="post"
    ></blog-post>
  </div>
</div>
Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <button>
        Enlarge text
      </button>
      <div v-html="post.content"></div>
    </div>
  `
})

这里的button不会触发任何事件,我们需要用$emit 方法

在父组件里面用v-on来绑定一个监听自定义事件:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += 0.1"
></blog-post>

在button里面加入$emit方法,触发这个事件:

<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button>

就可以了

使用事件抛出一个值

$emit是可以传值的:

<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>
<blog-post
  ...
  v-on:enlarge-text="postFontSize += $event"
></blog-post>

传递过去的值,通过$event访问

如果事件处理函数里面是一个方法,那么$event会作为第一个参数传给这个方法:

<blog-post
  ...
  v-on:enlarge-text="onEnlargeText"
></blog-post>
methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}

在组件上使用 v-model

v-model实际是一个语法糖:

<input v-model="searchText">

等价于:

<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

再看看在组件上使用:

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"

></custom-input>

如果我们要正常使用组件内的input标签,需要:

将其 value attribute 绑定到一个名叫 value 的 prop 上
在其 input 事件被触发时,将新的值通过自定义的input 事件抛出

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"

></custom-input>
Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})

这里,template里面的input标签会先触发自己的input事件,然后去调用后面的 e m i t , 接 下 来 e m i t 会 去 调 用 组 件 的 自 定 义 事 件 i n p u t , 然 后 这 里 的 自 定 义 事 件 i n p u t 再 让 s e a r c h T e x t 赋 值 为 传 来 的 参 数 emit,接下来emit会去调用组件的自定义事件input,然后这里的自定义事件input再让searchText赋值为传来的参数 emitemitinputinputsearchTextevent.target.value,而这个是input标签的事件。

改一下上面的代码,在里面加入打印方法就可以验证这个顺序:

<custom-input
  v-bind:value="searchText"
  v-on:input="log(e);searchText = $event"

></custom-input>
Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="log(e);$emit('input', $event.target.value)"
    >
  `,
  method:{
	log(e){
		console.log(e);
	}
}
})

这里的两个log方法要分别在Vue实例和组件的method中定义,这里Vue实例就不展示了,结果如下:

在这里插入图片描述
在这里插入图片描述

默认的input事件先触发了,然后传入input的值1

通过插槽分发内容

我们要在模板中传入一些默认html的节点,就要用插槽,slot标签,这和影子DOM有点像。

<alert-box>
  Something bad happened.
</alert-box>
Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box">
      <strong>Error!</strong>
      <slot></slot>
    </div>
  `
})

文本节点被放入到slot中了。

动态组件

可以通过is属性来动态切换组件:

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>

传入的currentTabComponent 可以包括

已注册组件的名字,
或
一个组件的选项对象

然后就可以动态的切换组件,这里还有很多内容,需要后续再看,
动态和异步组件

特殊属性,如is可以用在常规HTML元素上,但是像value这样的属性,可能需要 .prop修饰才能正常使用,可以看

解析 DOM 模板时的注意事项

有些元素的内部元素是有规定的,比如<ul><ol><table><select>

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

以上<blog-post-row>会被提升到外部导致渲染有问题

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

这样就可以用了

这些限制条件在下面三种情况是不存在的:
以下来源使用模板:

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

但是我不知道还有其他什么来源,后面可能会讲。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值