美文网首页
Vue 学习笔记之入门2

Vue 学习笔记之入门2

作者: 懒人成长 | 来源:发表于2017-03-02 18:25 被阅读27次

    第一篇入门文章中对 Vue.js 有了一个初步的认识,并且能够使用已有的知识完成简单实例的开发尝试——Todo List,如果有兴趣可以到我的Github中查看,感觉小有成就感。

    本文则继续入门学习,学习下Vue中重要的内容——组件

    概述

    组件是Vue中非常重要的部分,可以用来扩展HTML元素或者用于封装可复用代码,给开发带来更多的灵活性。

    注册

    组件在使用之前必须要先完成注册,注册有两种方式,全局注册和局部注册,通过全局注册的方式可以使组件在任意Vue实例中使用,而使用局部这次的方式则注册的组件只能用于当前Vue实例中。

    全局注册

    通过Vue.component(tagName, options)的方式来注册一个全局的组件。

    // 注册
    Vue.component('my-component', {
      template: '<div>A custom component!</div>'
    })
    // 创建根实例
    new Vue({
      el: '#example'
    })
    
    // 使用
    <div id="example">
      <my-component></my-component>
    </div>
    

    局部注册

    在Vue实例创建时通过components属性来注册仅能在当前实例中使用的组件。

    var Child = {
      template: '<div>A custom component!</div>'
    }
    new Vue({
      // ...
      components: {
        // <my-component> 将只在父模板可用
        'my-component': Child
      }
    })
    

    注意

    由于HTML的一些限制,一些特殊的HTML标签对包裹的标签进行了限制,这使得使用自定义组件时,若添加在受限的标签内部的话,就会出现不能解析的情况,导致无效,例如<ul><ol><table><select>

    在这种情况下,可以使用is属性来解决。

    <table>
      <tr is="my-row"></tr>
    </table>
    

    应当注意,如果您使用来自以下来源之一的字符串模板,这些限制将不适用:

    • <script type="text/x-template">
    • JavaScript内联模版字符串
    • .vue 组件

    因此,有必要的话请使用字符串模版。

    父子组件间通信

    在 Vue.js 中,父子组件的关系可以总结为 props down, events up。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。

    父子组件通信.png

    props

    组件实例的作用域是独立的,可以使用props属性来对父组件开放自定义属性。

    Vue.component('child', {
      // 声明 props
      props: ['message'],
      // 就像 data 一样,prop 可以用在模板内
      // 同样也可以在 vm 实例中像 “this.message” 这样使用
      template: '<span>{{ message }}</span>'
    })
    
    // 父组件中使用子组件
    <child message="hello!"></child>
    
    // 父组件中使用v-bind的方式绑定props
    <child :message="hello!"></child>
    

    由于HTML中不区分大小写,若组件中定义含大写字符的属性名称,则在父组件中使用时需要将大写字母转成小写,并用-连接单词。

    props是单向绑定的,父组件的数据变更会传递到子组件中,但是子组件的变更并不能传递回父组件。另外,每次父组件的变更都会带来子组件中所有props的更新。

    props可以设定验证规则,Vue提供了一些默认的规则,当然也支持自定义验证规则。

    Vue.component('example', {
      props: {
        // 基础类型检测 (`null` 意思是任何类型都可以)
        propA: Number,
        // 多种类型
        propB: [String, Number],
        // 必传且是字符串
        propC: {
          type: String,
          required: true
        },
        // 数字,有默认值
        propD: {
          type: Number,
          default: 100
        },
        // 数组/对象的默认值应当由一个工厂函数返回
        propE: {
          type: Object,
          default: function () {
            return { message: 'hello' }
          }
        },
        // 自定义验证函数
        propF: {
          validator: function (value) {
            return value > 10
          }
        }
      }
    })
    

    events

    父组件与子组件约定好事件名称,父组件使用$on(eventName)在自己的作用域中监听事件是否触发,子组件使用$emit(eventName)来触发事件,当父组件监听到事件后,就可以对子组件传递来的数据进行处理,更新自己的数据属性了。

    <div id="counter-event-example">
      <p>{{ total }}</p>
      <button-counter v-on:increment="incrementTotal"></button-counter>
      <button-counter v-on:increment="incrementTotal"></button-counter>
    </div>
    
    Vue.component('button-counter', {
      template: '<button v-on:click="increment">{{ counter }}</button>',
      data: function () {
        return {
          counter: 0
        }
      },
      methods: {
        increment: function () {
          this.counter += 1
          this.$emit('increment')
        }
      },
    })
    new Vue({
      el: '#counter-event-example',
      data: {
        total: 0
      },
      methods: {
        incrementTotal: function () {
          this.total += 1
        }
      }
    })
    

    Slot内容分发

    为了解决父组件内容与子组件自己模板混合的问题,Vue引入<slot>标签,通过该标签,就可以在子组件中定义承载父组件内容的插槽,当父组件对应位置有内容时,渲染父组件内容,没有内容时使用子组件自己定义的内容。

    // 子组件 my-component 模板:
    <div>
      <h2>我是子组件的标题</h2>
      <slot>
        只有在没有要分发的内容时才会显示。
      </slot>
    </div>
    
    // 父组件模版:
    <div>
      <h1>我是父组件的标题</h1>
      <my-component>
        <p>这是一些初始内容</p>
        <p>这是更多的初始内容</p>
      </my-component>
    </div>
    
    // 渲染结果:
    <div>
      <h1>我是父组件的标题</h1>
      <div>
        <h2>我是子组件的标题</h2>
        <p>这是一些初始内容</p>
        <p>这是更多的初始内容</p>
      </div>
    </div>
    

    可以通过对slot添加name属性的方式对其命名,这样就可以在一个模板中插入多个slot

    // 子组件模板
    <div class="container">
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
    
    // 父组件模版:
    <app-layout>
      <h1 slot="header">这里可能是一个页面标题</h1>
      <p>主要内容的一个段落。</p>
      <p>另一个主要段落。</p>
      <p slot="footer">这里有一些联系信息</p>
    </app-layout>
    
    // 渲染结果为:
    <div class="container">
      <header>
        <h1>这里可能是一个页面标题</h1>
      </header>
      <main>
        <p>主要内容的一个段落。</p>
        <p>另一个主要段落。</p>
      </main>
      <footer>
        <p>这里有一些联系信息</p>
      </footer>
    </div>
    

    特别注意事项

    1. 字面量语法和动态语法

    <!-- 传递了一个字符串"1" -->
    <comp some-prop="1"></comp>
    
    <!-- 传递实际的数字 -->
    <comp v-bind:some-prop="1"></comp>
    

    前者直接以字符串的形式进行了数据传递,后者则将值视为表达式计算后传递。

    2. 编写可服用组件

    Vue 组件的 API 来自三部分 - props, events 和 slots :

    • Props 允许外部环境传递数据给组件
    • Events 允许组件触发外部环境的副作用
    • Slots 允许外部环境将额外的内容组合在组件中。

    3.组件命名规则

    • 注册组件时可以使用kebab-case,camelCase或TitleCase。
    • 在 HTML 模版中,请使用 kebab-case 形式。
    • 使用字符串模式时,可以使用 camelCase 、 TitleCase 或者 kebab-case

    相关文章

      网友评论

          本文标题:Vue 学习笔记之入门2

          本文链接:https://www.haomeiwen.com/subject/tsekgttx.html