Vue官方文档学习-组件

组件基础

1.定义

  • 组件是可复用的Vue实例,与new Vue接收相同的选项,包括data、computed、watch、methods以及生命周期钩子。
  • el是根实例特有的选项.
  • 【注意】:data属性必须是一个函数,以让每个实例都可以独立维护一份被返回对象的独立的拷贝。否则,多次使用同一个组件,若某个实例改变了data中的属性值,会导致其余实例也被修改。
  • 举例
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  // 1.data为一个函数,各个按钮的count是互相独立的
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

Vue.component('button-counter', {
  // 2.data为一个对象,点击第一个按钮,其余按钮的count也会随之变化
  data:  {
      count: 0
    },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
<!-- 3.多次使用同一个组件 -->
<div id="components-demo">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>

2.组件的全局注册

  • 通过Vue.component进行全局注册;
  • 全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建 Vue 根实例,也包括其组件树中的所有子组件的模板中;
Vue.component('my-component-name', {
  // ... options ...
})
  • 注册组件的名字
    (1) 使用kebab-case
    Vue.component('my-component-name', { /* ... */ })
    
    <my-component-name></my-component-name>
    

3.模块系统中注册

(1) 场景

在开发中,通常会创建一个components目录用于专门放置组件,在该目录下,通常将每个组件放置在其各自的文件夹中。若某个组件需要使用其他组件,通常使用import / require模块系统.

(2) 使用

// 导入组件
import ComponentA from './ComponentA'
import ComponentC from './ComponentC'
// 在模块系统中局部注册
export default {
  components: {
    ComponentA,
    ComponentC
  },
  // ...
}

(3) 基础组件的自动化全局注册

某些组件是相对通用的,会被作为基础组件,在各个组件中被频繁使用,会导致很多组件里都会有一个包含基础组件的长列表:

import BaseButton from './BaseButton.vue'
import BaseIcon from './BaseIcon.vue'
import BaseInput from './BaseInput.vue'

export default {
  components: {
    BaseButton,
    BaseIcon,
    BaseInput
  }
}
<BaseInput
  v-model="searchText"
  @keydown.enter="search"
/>
<BaseButton @click="search">
  <BaseIcon name="search"/>
</BaseButton>

因此,若使用了webpack(或在内部使用了webpack的Vue cli 3+),就可以考虑在应用入口文件(src/main.js)中全局导入基础组件(全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生):

import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

// 参数:组件目录的相对路径,是否查询其子目录,匹配基础组件文件名的正则表达式
const requireComponent = require.context('./components',false,/Base[A-Z]\w+\.(vue|js)$/)

// 遍历components目录下的文件
requireComponent.keys().forEach(fileName => {
  const componentConfig = requireComponent(fileName)  // 获取组件配置
  // 先获取和目录深度无关的文件名,再获取组件的 PascalCase 命名
  const componentName = upperFirst(camelCase(fileName.split('/').pop().replace(/\.\w+$/, '')))
  // 全局注册组件
  Vue.component(
    componentName,
    // 如果这个组件选项是通过 `export default` 导出的,
    // 那么就会优先使用 `.default`,
    // 否则回退到使用模块的根。
    componentConfig.default || componentConfig
  )
})

4.通过Prop向子组件传递数据(父->子)

  • 使用场景:在当前组件中引入了某个组件,需要向该组件传递一些数据;父组件向子组件传值
  • Prop 是可以在组件上注册的一些自定义 attribute,当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property;
  • 在组件中使用props属性接受父组件传递的数据;
  • 一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop;、
  • 示例1:传递字符串等单一数值变量
// 1.注册子组件
Vue.component('blog-post', { 
  // 2.接收父组件参数
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})
<!-- 3.在父组件中使用 -->
<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>
  • 示例2:传递对象
// 1.注册子组件
Vue.component('blog-post', {
  // 2.接收父组件参数
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <div v-html="post.content"></div>
    </div>
  `
})
<!-- 3.在父组件中使用 -->
<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:post="post"
></blog-post>

5.监听子组件事件(子->父)

  • 使用场景:子组件向父组件传递值
  • 子组件通过调用$emit方法并传入事件名称来出发事件,父组件通过监听事件从而获取子组件传递的数据;
  • 举例:子组件中有一个放大字体的功能,用户点击后,希望让页面中所有元素的字体都被放大,因此需要把子组件中改变的字体大小传递回父组件;
// 1.子组件定义
Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>   
      //通过$emit向父组件提交事件
      <button v-on:click="$emit('enlarge-text',0.1)">Enlarge text</button>
      <div v-html="post.content"></div>
    </div>
  `
})
<!-- 2.父组件 -->
<div id="blog-posts-events-demo">
  <div :style="{ fontSize: postFontSize + 'em' }">
  <!-- 通过v-on监听子组件提交的事件和数据 -->
    <blog-post
      v-for="post in posts" v-bind:key="post.id"
      v-bind:post="post" v-on:enlarge-text="onEnlargeText"
      v-on:enlarge-text="postFontSize += 0.1">
    </blog-post>
  </div>
</div>
new Vue({
  el: '#blog-posts-events-demo',
  data: {
    posts: [/* ... */],
    postFontSize: 1
  },
  methods: {
	  onEnlargeText: function (enlargeAmount) {
	    this.postFontSize += enlargeAmount
	  }
   }
})

6.在组件上使用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>
<!-- 等价于 -- >
<custom-input v-model="searchText"></custom-input>
  • 【重要】为了自定义组件的v-model正常工作,组件内的input必须满足:
  1. 将其 value attribute 绑定到一个名叫 value 的 prop 上;
  2. 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出;
Vue.component('custom-input', {
  props: ['value'],
  template: `<input v-bind:value="value" v-on:input="$emit('input', $event.target.value)">`
})

7.动态组件

(1)基础知识
  • 作用:用于在不同组件之间进行动态切换
  • 使用:在组件上加入is属性;
  • 绑定的is属性可以包括已注册组件的名字一个组件的选项对象;
  • 【注意】当is用于常规HTML元素,这些元素将被视为组件,所有的属性都会作为DOM attribute被绑定。对于像 value 这样的 property,若想让其如预期般工作,需要使用 .prop 修饰器
<component v-bind:is="currentTabComponent"></component>
(2)用于解析DOM模板
  • 场景:有些 HTML 元素,诸如<ul>、<ol>、<table> 和<select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>、<tr> 和<option>,只能出现在其它某些特定的元素内部。这会导致我们使用这些有约束条件的元素时遇到一些问题,如:
<!-- 自定义组件 <blog-post-row> 会被作为无效的内容提升到外部,
    并导致最终渲染结果出错 -->
<table>
  <blog-post-row></blog-post-row>
</table>

<!-- 使用is -->
<table>
  <tr is="blog-post-row"></tr>
</table>
  • 使用以下方式使用模板,不存在该限制:
  1. 字符串 (例如:template: ‘…’)
  2. 单文件组件 (.vue)
  3. <script type=“text/x-template”>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值