vue入门(四)组件components

一、基本介绍

组件是可复用的Vue实例,可以在一个通过new Vue创建的Vue根实例中,把这个组件作为自定义元素来使用。

组件也可以包含 datacomputedwatchmethods 以及生命周期钩子等,除了el。

1、一个组件的data必须是一个函数

    这样,每个实例可以维护自己独立的数据,而不是每个组件都使用同一个数据:

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

2、通过Prop向子组件传递数据

Prop 是你可以在组件上注册的一些自定义特性。一个Prop被注册后,可以把数据作为一个自定义特性传递到子组件中。

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

<blog-post title="My journey with Vue"></blog-post>    //通过title特性传递数据

若在data中有一组数据posts,并为每一个数据渲染一个组件,可以用v-bind来动态传递prop

当需要多个特性时,可以通过以下,此时不论何时为post对象添加一个新的属性,都会自动的在<blog-post>内可用

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:post="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>
  `
})

3、单个根元素

每个组件必须只有一个根元素。

4、监听子组件事件

在子组件中vm.$emit( eventName, data ) 事件,第二参数为子组件向父组件抛出的数据,当子组件中有事件触发时,会自动触发eventName。

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

父组件可以像处理native DOM事件一样,实现eventName,可以通过$event访问被抛出的值,通过v-on监听子组件实例的任何事件。若事件处理函数是一个方法,v-on:enlarge-text="onEnlargeText"  ,那么这个值会作为第一个参数传入此方法。

<blog-post  v-on:enlarge-text="postFontSize += $event">   </blog-post>

5、在组件上使用v-model

使用v-model可以使输入的数据实现双向绑定。在组件上用v-model时,组件内的input必须:

  • 将其 value 特性绑定到一个名叫 value 的 prop 上
  • 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})
<custom-input v-model="searchText"></custom-input>

6、通过插槽分发内容

    若要在组件内写内容,可能会渲染出错,此时通过加入slot元素,即写的内容会出现在相应slot位置上。

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

二、注册组件

1、组件名

    Vue.component('组件名',{    })

①全小写字母+至少一个连字符:引用时也必须使用此名

②大驼峰命名:引用时,可以是大驼峰,也可以是全小写+连字符

2、全局注册

全局注册:在注册之后可以用在任何新创建的Vue根实例中,在子组件各自内部也可以相互使用。

Vue.component('name-a',{ ... })
new Vue({el:'#app'})         //用在新创建的根实例中

3、局部注册

局部注册的组件在其子组件中不可用。通过普通的JS对象来定义组件,然后在components中定义想要使用的组件

var ComponentA ='{  }'
var ComponentB ='{  }'

var vm =new Vue({
    el:'#app',
    components:{
        'component-a' : ComponentA
})

若要在ComponentB中使用ComponentA,则要在定义ComponentB时,将B加入components。

4、模块系统

    创建一个components目录,并将每个组件放在各自的文件中。 在局部注册之前导入每一个想要使用的组件:

import ComponentA from './ComponentA'

export default {
  components: {
    ComponentA
  },}    //A可以在B中使用了

5、基础组件的自动化全局注册

    基础组件:相对通用的组件,被频繁使用,如输入框或按钮。全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生

代码详见:https://cn.vuejs.org/v2/guide/components-registration.html

三、Prop

1、Prop的大小写

在JS中,Props使用小驼峰命名,而在HTML中,需要使用kebab-case(短横线分隔)命名。

2、Prop类型

可以设置Prop各自的名称和类型

props:{
    title:String,
    lieks:Number}  

任何类型的值都可以传递给prop,Number,String等数据类型(Boolean类没有值时默认true),对象、数组等引用类型都可以。

3、单向数据流

    单向下行绑定:父级 prop 的更新会向下流动到子组件中,不能在一个子组件内部改变 prop,这样会在控制台发出警告。

4、Prop验证

可以为props中的值提供一个带有验证需求的对象。当验证失败时,会产生一个控制台的警告

Vue.component('my-component', {
  props: {
    propA: Number,    // 多个可能的类型
    propB: [String, Number],       // 必填的字符串
}})

这里的type可以是原生的类型,还可以是一个自定义的构造函数,来验证prop值是通过构造函数创建的

5、禁用特性继承

如果你希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false

四、自定义事件

1、事件名:

    始终使用 kebab-case 的事件名,触发的事件名需要完全匹配监听这个事件所用的名称

2、v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的event,输入的值会传入prop中。

3、将原生事件绑定到组件

在一个组件的根元素上直接监听一个原生事件,使用.native修饰符

<base-input v-on:focus.native="onFocus"></base-input>

Vue 提供了一个 $listeners 属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。

4、子向父传值.sync

子组件更新数据通过事件触发,父组件可以监听子组件更新数据,通过.sync修饰符实现这种模式

<text-document v-bind:title.sync="doc.title"></text-document>    //不能用表达式

五、插槽

在templ中写入<slot></slot>,可以插入任何模板代码,包括HTML、其他组件

1、编译作用域

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

2、后备内容:在没有提供内容的时候渲染,可以将默认内容放入<slot></slot>标签对内。

3、具名插槽

有时我们需要多个插槽<slot> 元素的特性:name可以用来定义额外的插槽:

<header>   <slot name="header"></slot>  </header>
<footer>   <slot name="footer"></slot>  </footer>

在向具名插槽写内容时,可以在一个 <template> 元素上使用 v-slot指令,参数为slot的名称:

<template v-slot:header> a page title  </template>

没有v-slot指令,则被视为默认插槽内容。v-slot 只能添加在一个 <template> 上

4、作用域插槽

让插槽内容能够访问子组件中才有的数据(假设user)可以将user作为<slot>元素的一个特性绑定上去。

<span>  
<slot v-bind:user="user">    {{ user.lastName }}  </slot>
</span>

此特性被称为插槽prop,在父级作用域中,给v-slot带一个值来定义插槽prop名字

<current-user v-slot:default="slotProps">
  {{ slotProps.user.firstName }}
</current-user>           //独占默认插槽的缩写语法,:default也可省略

注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确。

只要出现多个插槽,就始终为所有的插槽使用完整的基于 <template> 的语法。

5、解构插槽prop

v-slot 的值可以是任何能够作为函数定义中的参数的 JavaScript 表达式。

<current-user v-slot="{ user }">  </current-user>  //可以插入具体的插槽prop
<current-user v-slot="{ user: person }">  </current-user>  //可以prop重命名
<current-user v-slot="{ user = { firstName: 'Guest' } }">  </current-user> //可以定义后备内容

6、动态指令参数也可用在v-slot上,来定义动态的插槽名。

v-slot:可以缩写成#,该缩写只在其有参数的时候才可用,即必须始终以明确插槽名取而代之。如v-slot:header→#header

六、动态组件

1、在动态组件上使用keep-alive

<component v-bind:is="currentTabComponent"></component>

在一个多标签的界面上使用is特性来切换不同的组件。当在这些组件之间切换的时候,会反复重新渲染。

当你想保持这些组件的状态时,即标签的组件实例能够被在它们第一次被创建的时候缓存下来,可以使用<keep-alive>元素将其动态组件包裹起来。

<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

2、异步组件

   以下工厂函数方式定义的组件,只有在这个组件需要被渲染的时候才会触发该工厂函数。

Vue.component('async-webpack-example', function (resolve) {
  // 这个特殊的 `require` 语法将会告诉 webpack自动将你的构建代码切割成多个包,这些包会通过 Ajax 请求加载
  require(['./my-async-component'], resolve)
})

resolve 回调函数会在你从服务器得到组件定义的时候被调用。

七、处理边界情况

1、访问元素、组件

①访问根实例:在每个 new Vue 实例的子组件中,其根实例可以通过 $root 属性进行访问。

this.$root.foo = 2    //写入根组件数据

②访问父级组件实例:$parent 属性可以用来从一个子组件访问父组件的实例。

③在JS里直接访问一个子组件:通过 ref 特性为这个子组件赋予一个 ID 引用,例如输入聚焦

<base-input ref="usernameInput"></base-input>
this.$refs.usernameInput  //访问base-input实例

$refs 只会在组件渲染完成之后生效,并且它们不是响应式的,应避免在模板或计算属性中访问

2、依赖注入

依赖注入用到了两个新的实例选项:provide 和 inject

provide 选项允许我们指定我们想要提供给后代组件的数据/方法。

在任何后代组件里,都可以使用 inject 选项来接收想要添加在这个实例上的属性

3、事件侦听

  • 通过 $on(eventName, eventHandler) 侦听一个事件
  • 通过 $once(eventName, eventHandler) 一次性侦听一个事件
  • 通过 $off(eventName, eventHandler) 停止侦听一个事件

4、循环引用

①递归组件:组件在自己的模板中调用自身,通过name:‘组件名’ 来实现,注意确保递归调用是条件性的

②循环引用:当父引用子,子引用父时,通过Vue.component全局注册组件是没问题,但是若通过webpack则会出错

此时可以通过以下两种方式解决

beforeCreate: function () {
  this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
}               //等到生命周期钩子beforeCreate时去注册它
components: {
  TreeFolderContents: () => import('./tree-folder-contents.vue')
}    //在本地注册组件时使用 webpack 的异步 import

5、内联模板

当 inline-template 特性出现在一个子组件上时,这个组件将会使用其里面的内容作为模板。

内联模板需要定义在 Vue 所属的 DOM 元素内。

<my-component inline-template> ... </my-component>

6、X-Template

X-Template需要定义在 Vue 所属的 DOM 元素外。

在一个 <script> 元素中,并为其带上 text/x-template的类型,然后通过一个 id 将模板引用过去。

<script type="text/x-template" id="hello-world-template">
  <p>Hello hello hello</p>
</script>

Vue.component('hello-world', {
  template: '#hello-world-template'
})

7、通过v-once创建低开销的静态组件

组件包括了大量的静态内容,可以在根元素上添加v-once特性,确保这些内容只计算一次后缓存起来

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值