• Tags
  •         
  • www.breakyizhan.com
  •    

    Vue.js的组件 component 是Vue.js最要的功能,主要用来扩展 HTML 元素,封装可重用的代码。由于组件这一块比较大,所以这篇文章最主要讲的是Vue.js 的组件基础,主要通过以下内容来认识Vue.js 的组件基础:

    • Vue.js 组件component的基本示例
    • Vue.js 组件component的复用
    • Vue.js 组件component的组织架构
    • Vue.js 组件component通过Prop向子元素传递数据
    • Vue.js 组件component的单个根元素
    • Vue.js 组件component通过事件向父组件发送信息
    • Vue.js 组件component通过插槽分发内容
    • Vue.js 组件component动态组件

    上面的对于component有点多,Vue.js的组件意思就是把html分解成各个部分,实现各个功能,便于管理,一般组件都是在src/component这个目录下面的。

    Vue.js 组件component的基本示例

    我们可以看这个示例:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="components-demo">
      <button-counter></button-counter>
    </div>
    
    <script>
    // 定义一个名为 button-counter 的新组件
    Vue.component('button-counter', {
      data: function () {
        return {
          count: 0
        }
      },
      template: '<button v-on:click="count++">你点击我 {{ count }} 次.</button>'
    })
    new Vue({ el: '#components-demo'})
    </script>
    </body>
    </html>
    

    可以看到,这个例子里面,组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <button-counter>。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用。

    Vue.js 组件component的复用

    对于上面的例子,<button-counter>这个组件是可以复用的,也就是说,多创建几个<button-counter>的话,每个组件都会各自独立维护它的 count。因为你每用一次组件,就会有一个它的新实例被创建。

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="components-demo">
      <button-counter></button-counter>
      <button-counter></button-counter>
      <button-counter></button-counter>
    </div>
    
    <script>
    // 定义一个名为 button-counter 的新组件
    Vue.component('button-counter', {
      data: function () {
        return {
          count: 0
        }
      },
      template: '<button v-on:click="count++">你点击我 {{ count }} 次.</button>'
    })
    new Vue({ el: '#components-demo'})
    </script>
    </body>
    </html>
    

    但是对于上面代码中的data中必须是一个函数,不然的话,就没办法独立维护了,可以运行下面的代码试试,每个组件都不会各自独立维护它的 count

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="components-demo">
      <button-counter></button-counter>
      <button-counter></button-counter>
      <button-counter></button-counter>
    </div>
    
    <script>
    // 定义一个名为 button-counter 的新组件
    Vue.component('button-counter', {
      data: function () {
          count: 0
      },
      template: '<button v-on:click="count++">你点击我 {{ count }} 次.</button>'
    })
    new Vue({ el: '#components-demo'})
    </script>
    </body>
    </html>
    

    注:上面的代码可复制之后在线运行;

    Vue.js 组件component的组织架构

    通常一个应用会以一棵嵌套的组件树的形式来组织:

    Vue.js 的组件基础 component

    例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

    为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的。

    Vue.component 全局注册的示例:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
    	<breakyizhan></breakyizhan>
    </div>
    
    <script>
    // 注册
    Vue.component('breakyizhan', {
      template: '<h1>自定义组件!</h1>'
    })
    // 创建根实例
    new Vue({
      el: '#app'
    })
    </script>
    </body>
    </html>
    

    尝试一下 >>

    Vue.component 局部注册的示例:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
    	<breakyizhan></breakyizhan>
    </div>
    
    <script>
    var Child = {
      template: '<h1>自定义组件!</h1>'
    }
    
    // 创建根实例
    new Vue({
      el: '#app',
      components: {
        // <breakyizhan> 将只在父模板可用
        'breakyizhan': Child
      }
    })
    </script>
    </body>
    </html>

    尝试一下 >>

    Vue.js 组件component通过Prop向子元素传递数据

    prop 是父组件用来传递数据的一个自定义属性。父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop"。一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样。

    一个 prop 被注册之后,你就可以像这样把数据作为一个自定义特性传递进来。对于Prop传递数据,用了基本Prop传递,Prop动态Prop,Prop和v-bind的例子。 注意:prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。

    基本Prop传递:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
    	<child message="hello!"></child>
    </div>
    
    <script>
    // 注册
    Vue.component('child', {
      // 声明 props
      props: ['message'],
      // 同样也可以在 vm 实例中像 “this.message” 这样使用
      template: '<span>{{ message }}</span>'
    })
    // 创建根实例
    new Vue({
      el: '#app'
    })
    </script>
    </body>
    </html>
    

    尝试一下 >>

    Prop动态Prop:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
    	<div>
    	  <input v-model="parentMsg">
    	  <br>
    	  <child v-bind:message="parentMsg"></child>
    	</div>
    </div>
    
    <script>
    // 注册
    Vue.component('child', {
      // 声明 props
      props: ['message'],
      // 同样也可以在 vm 实例中像 “this.message” 这样使用
      template: '<span>{{ message }}</span>'
    })
    // 创建根实例
    new Vue({
      el: '#app',
      data: {
    	parentMsg: '父组件内容'
      }
    })
    </script>
    </body>
    </html>

    尝试一下 >>

    Prop和v-bind的例子:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
    	<ol>
        <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
      	</ol>
    </div>
    
    <script>
    Vue.component('todo-item', {
      props: ['todo'],
      template: '<li>{{ todo.text }}</li>'
    })
    new Vue({
      el: '#app',
      data: {
        sites: [
          { text: 'Breakyizhan' },
          { text: 'Google' },
          { text: 'Taobao' }
        ]
      }
    })
    </script>
    </body>
    </html>

    尝试一下 >>

    Vue.js 组件component的单个根元素

    every component must have a single root element (每个组件必须只有一个根元素)。这句话是每个组件的要求,不能有多个根元素的。比如只有一个app,而不能有两个(app和app2)的组件

    <div id="app">
       <child message="hello!"></child>
    </div>
    <div id="app2">
       <child message="hello!"></child>
    </div>
    

    Vue.js 组件component通过事件向父组件发送信息

    父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!

    我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:

    • 使用 $on(eventName) 监听事件
    • 使用 $emit(eventName) 触发事件

    另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。

    以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件,那么应该怎么实现呢?可以看一下下面这个例子:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
    	<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>
    </div>
    
    <script>
    Vue.component('button-counter', {
      template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
      data: function () {
        return {
          counter: 0
        }
      },
      methods: {
        incrementHandler: function () {
          this.counter += 1
          this.$emit('increment')
        }
      },
    })
    new Vue({
      el: '#counter-event-example',
      data: {
        total: 0
      },
      methods: {
        incrementTotal: function () {
          this.total += 1
        }
      }
    })
    </script>
    </body>
    </html>

    尝试一下 >>

    使用v-on绑定自定义事件可以让子组件向父组件传递数据,用到了this.$emit(‘自定义的事件名称',传递给父组件的数据)

    <!DOCTYPE html>
    <html lang="en">
    <head>
     <meta charset="UTF-8">
     <title>Title</title>
     <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
    <parent-component></parent-component>
    </div>
    <template id="parent-component">
    <div>
     <p>总数是{{total}}</p>
     <child-component @increment="incrementTotal"></child-component>
     <!--@increment是子组件this.$emit('increment'自定义的事件用来告诉父组件自己干了什么事
     然后会触发父子间incrementTotal的方法来更新父组件的内容)-->
    </div>
    </template>
    <template id="child-component">
     <button @click="increment()">{{mycounter}}</button>
    </template>
    <script>
     var child=Vue.extend({
      template:"#child-component",
      data:function () {
       return {
        mycounter:0
       }
      },
      methods:{
       increment:function(){
        this.mycounter=10;
        this.$emit("increment",this.mycounter);//把this.mycounter传递给父组件
       }
      }
     })
     var parent=Vue.extend({
      data:function () {
       return {
        total:0
       }
      },
      methods:{
       incrementTotal:function(newValue){
        this.total+=newValue;
       }
      },
      template:"#parent-component",
      components:{
       'child-component':child
      }
     })
     var vm=new Vue({
      el:"#app",
      components:{
       'parent-component':parent
      }
     })
    </script>
    </body>
    </html>
    

    @increment是子组件this.$emit('increment'自定义的事件用来告诉父组件自己干了什么事。然后会触发父子间incrementTotal的方法来更新父组件的内容。

    Vue.js 组件component通过插槽分发内容

    Vue 自定义的 <slot> 元素让“向一个组件传递内容”变得非常简单。我们只要在需要的地方加入插槽就行了:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
    	<alert-box>
      		Something bad happened.
    	</alert-box>
    </div>
    
    <script>
    // 注册
    Vue.component('alert-box', {
      template: `
        <div class="demo-alert-box">
          <strong>Error!</strong>
          <slot></slot>
        </div>
      `
    })
    // 创建根实例
    new Vue({
      el: '#app'
    })
    </script>
    </body>
    </html>
    

    Vue.js 组件component动态组件

    在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里。我们是通过 Vue 的 <component> 元素加一个特殊的 is 特性来实现的。

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - Break易站(breakyizhan.com)</title>
    <style>
    	.tab-button {
      padding: 6px 10px;
      border-top-left-radius: 3px;
      border-top-right-radius: 3px;
      border: 1px solid #ccc;
      cursor: pointer;
      background: #f0f0f0;
      margin-bottom: -1px;
      margin-right: -1px;
    }
    .tab-button:hover {
      background: #e0e0e0;
    }
    .tab-button.active {
      background: #e0e0e0;
    }
    .tab {
      border: 1px solid #ccc;
      padding: 10px;
    }
    </style>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="dynamic-component-demo" class="demo">
      <button
        v-for="tab in tabs"
        v-bind:key="tab"
        v-bind:class="['tab-button', { active: currentTab === tab }]"
        v-on:click="currentTab = tab"
      >{{ tab }}</button>
    
      <component
        v-bind:is="currentTabComponent"
        class="tab"
      ></component>
    </div>
    
    <script>
    Vue.component('tab-home', { 
    	template: '<div>Home component</div>' 
    })
    Vue.component('tab-posts', { 
    	template: '<div>Posts component</div>' 
    })
    Vue.component('tab-archive', { 
    	template: '<div>Archive component</div>' 
    })
    
    new Vue({
      el: '#dynamic-component-demo',
      data: {
        currentTab: 'Home',
        tabs: ['Home', 'Posts', 'Archive']
      },
      computed: {
        currentTabComponent: function () {
          return 'tab-' + this.currentTab.toLowerCase()
        }
      }
    })
    </script>
    </body>
    </html>
    

     
    转载请保留页面地址:https://www.breakyizhan.com/vue/6691.html