Vue-组件(2)

185 阅读1分钟

组件通信

自定义事件

Vue有一套与JS观察者模式类似的设计,子组件用$emit()来触发事件,父组件用$on()来监听子组件的事件。

<div id='app'>
    <son-component @change='handleTotal'></son-component>
    <!--change就是自定义事件-->
</div>
Vue.component('son-component',{
    template:
    '<div>\
        <button @click='handleIncrease'>+1</button>\
        <button @click='handleReduce'>-1</button>\
    </div>',
    data:function(){
        return {
            count: 0
        }
    },
    methods:{
        handleIncrease:function(){
            this.count += 1;
            this.$emit('change',this.count)
        },
        handleReduce:function(){
            this.count -= 1;
            this.$emit('change',this.count)
        }
    }
})
var app = new Vue({
    el:'#app',
    data:{
        total: 0
    },
    methods:{
        handleTotal:function(value){
            this.total = value
        }    
    }
})

在组件中使用v-model

<div id="app">
    <son-component v-model='total'></son-component>
</div>
Vue.component('son-component',{
  template:'<div>\
  <button @click="handleIncrease">+1</button>\
  </div>',
  methods:{
    handleIncrease:function(){
      this.count +=1
      this.$emit('input',this.count)
    }
  },
  data:function(){
    return {
      count:1
    }
  }
})
var app = new Vue({
  el:'#app',
  data:{
    total: 1
  }
})

非父组件的通信

  <div id="app">
    <component-a ref='a'></component-a>
    <component-b ref='b'></component-b>
    <hr style="background-color:cyan;height:4px;">
    <component-c ref='c'></component-c>{{msg}}
    <button @click='getChildData'>我是父组件的按钮,我要拿到子组件的内容</button>
    {{formChild}}
  </div>
Vue.component('component-a', {
  template: '<div><button @click="handle">我是a组件的按钮</button></div>',
  data: function () {
    return {
      a: '其实我是a组件的data定义的内容,我通过b中的函数显示出来。',
      msg: '我是a中的msg'
    }
  },
  methods: {
    handle: function () {
      this.$root.bus.$emit('eve', this.a) //eve为自定义的事件名,this.a是要传送的数据
    }
  }
})

Vue.component('component-b', {
  template: '<div>其实我是B组件</div>',
  data: function () {
    return {
      msg: '我是b中的msg'
    }
  },
  created: function () {
    this.$root.bus.$on('eve', function (value) {
      alert(value)
    })
  }
})

Vue.component('component-c', {
  template: '<button @click="amend">点我修改父组件的内容</button>',
  data: function () {
    return {
      msg: '我是c中的msg'
    }
  },
  methods: {
    amend: function () {
      this.$parent.msg = '猪突猛进'
    }
  }
})
var app = new Vue({
  el: '#app',
  data: {
    bus: new Vue(),
    msg: '我是未修改过的父组件的内容',
    formChild: '还未拿到'
  },
  methods: {
    //用来拿子组件中的内容
    getChildData: function () {
      this.formChild = this.$refs.b.msg;
    }
  }
})

插槽

单个slot

<div id="app">
    <part-component>
    {{msg}}
    </part-component>
</div>
var app = new Vue({
  el:"#app",
  data:{
    msg:'我爱你'
  },
  components:{
    "part-component":{
    template:'\
        <div>你爱我吗?\
            <slot>你要是不爱我我就出来再问你一遍。</slot>\
        </div>'
    }
  }
})

使用{{msg}}渲染时:

不渲染内容则默认显示<slot>标签中的内容:

具名插槽

<div id="app">
    <part-component>
        <h1 slot='head'>1</h1>
        <h2>2</h2>
        <h3>3</h3>
    </part-component>
</div>
var app = new Vue({
  el: "#app",
  data: {

  },
  components: {
    "part-component": {
      template: '\
            <div>\
                <div class="head">\
                  <slot name="head"></slot>\
                </div>\
                <div class="container">\
                  <slot></slot>\
                </div>\
            </div>',
    }
  }
})

template中<slot>标签中定义的name值会自动匹配html标签中slot属性值相同的属性;template中未定义name值的<slot>标签会去匹配没有设置slot属性的标签,从而改变其dom结构。从而更新数据变得方便。

作用域插槽

作用是通过slot从子组件获取数据。

  <div id="app">
    <my-component>
      <template slot='name' slot-scope="variable">  
        <!-- variable是一个临时变量名 -->
        {{variable}}
        <!--渲染出的标签属性可以以{{variable.xx}}方式渲染到html-->
      </template>
    </my-component>
  </div>
    Vue.component('my-component',{
      template:'\
      <div>\
        <slot class="hh" id="qq" qwe="123" text="我是要被拿到的数据" name="name"></slot>\
      </div>'
    })
    var app = new Vue({
      el:'#app',
      data:{
        
      }
    })

访问slot插槽

Vue.component('name-component', {
  template: '<div>\
    <div class="header"> \
      <slot name="header"></slot> \
    </div>   \
    <div class="container">  \
      <slot></slot>   \
    </div>  \
    <div class="footer">  \
      <slot name="footer"></slot>  \
     </div>   \
  </div>',
  mounted: function () {
    var head = this.$slots.header;
    console.log(head[0].elm.innerHTML)  //这样便能获取到插槽类名为header的内容
  }
})

动态组件

  <div id="app">
    <component :is='thisView'></component>
    <button @click="dispose('a')">1</button>
    <button @click="dispose('b')">2</button>
    <button @click="dispose('c')">3</button>
    <button @click="dispose('d')">4</button>
  </div>
Vue.component('component-a',{
      template:'<div>哈哈</div>'
    })
    Vue.component('component-b',{
      template:'<div>嘿嘿</div>'
    })
    Vue.component('component-c',{
      template:'<div>嗯嗯</div>'
    })
    Vue.component('component-d',{
      template:'<div>啵啵</div>'
    })
    var app = new Vue({
      el:'#app',
      data:{
        thisView:'component-a'
      },
      methods:{
        dispose:function(tag){
          this.thisView = 'component-' + tag;
        }
      }
    })