Vue学习笔记之深入理解Vue组件(二)

父子组件间的数据传递

1.父向子组件传值:

1.1 子组件通过props接收
1.2 单向数据流:父组件可以随意向子组件传递参数,子组件不可以改父组件的参数。解决办法: 要想改变父组件的参数,子组件在data项中新赋值父组件的变量,操作新定义的变量即可

2.子向父组件传参数

使用触发事件:this.$emit(‘方法名’,参数),参数为传给父组件中监听事件
运行这个例子,父组件给子组件传递了count属性,子组件通过props接收这个属性,通过number:this.count保存这个属性,因为直接更改也许会影响其它也使用了这个属性的组件。点击子组件,emit一个change事件,根组件监听着这个组件,一旦触发,执行handleChange函数。

<div id="root">
    <counter
        @change='handleChange'
        :count='1'
    ></counter>
    <counter
        @change='handleChange'
        :count='2'
    ></counter>
    <div>{{total}}</div>
</div>
<script type="text/javascript">
    Vue.component('counter',{
        template: "<div  @click='handleClick'>{{number}}</div>",
        props:['count'],
        data () {
            return {
                number: this.count
            }
        },
        methods: {
            handleClick: function () {
                this.number++;
                this.$emit('change',1)
            }
        }
    })

    var vm =new Vue({
        el: '#root',
        data: {
            total:3
        },
        methods: {
            handleChange: function (num) {
                this.total+=1
            }
        }
    })
</script>

组件参数校验

如果父组件定义 content="" 属性,引号里表示的是一个字符串;只有 :content="" 的形式,引号里才表示一个 js 表达式。
组件参数校验:
子组件对父组件传递过来的参数,做一些约束,比如要求一定是字符串,props对象中的键:
type
required: 表示必须传,
default: 如果不传参数,会有默认值,
validator : 校验器,定义方法

  props:{
          content:{
             type:
             required:falsedefault:d value,
             validator:function(value){
         		}
 	   }
  }

非props特性:
父组件向子组件传递属性,子组件并没有通过props接收,子组件不能获取到父组件这个属性的值
特点:
属性会展示在子组件最外层的dom标签上

给组件绑定原生事件

1.传统方法绑定事件为:

1、在子组建上绑定事件
2、在子组件中的methods设置相应的事件函数,并在函数中设置自定义事件函数,将自定义事件传递给父组件
3、在父组件上绑定从子组件methods函数中传来的自定义事件
4、在父组件methods中设置对应的事件函数。

<div id="root">
    <item @click='handleClick'></item>
</div>
<script type="text/javascript">
    Vue.component('item',{
        template: "<div @click='handleChild'>hello</div>",
        methods: {
            handleChild: function () {
                this.$emit('click')
            }
        }
    })
    var vm = new Vue({
        el: '#root',
        methods: {
            handleClick: function () {
                alert(1);
            }
        }
    })
</script>
2.组建上绑定原生事件:

1、在父组件绑定事件(如@click.native=“handle”)
2、在vue实例中的methods下定义事件函数。
给组件绑定原生事件的话,这个例子等于

<div id="root">
    <item @click.native='handleClick'></item>
</div>
<script type="text/javascript">
    Vue.component('item',{
        template: "<div>hello</div>",
    })
    var vm = new Vue({
        el: '#root',
        methods: {
            handleClick: function () {
                alert(1);
            }
        }
    })
</script>

非父子组件间的传递

Vue学习笔记之深入理解Vue组件(二)
例如1向3传值,3向3传值便是非父子组件间的传值。我们该如何实现呢?
一般来说我们有两种方式:

1.(Bus/总线/发布订阅模式/观察者模式)

Vue.prototype.bus = new Vue() 在vue的prototype上挂载bus属性,该属性指向vue实例,接下来的每一个vue实例乃至组件都有了bus属性
在子组件中定义方法,
在组件实例中:
在methods传递数据 : 通过this.bus.emit(&quot;&quot;,data)mountedthis.bus.emit(&quot;函数名 &quot;,data) 在mounted接收数据:通过this.bus.on(“函数名”,function(value){})

    <div id="root">
        <child content="hello"></child>
        <child content="world"></child>
    </div>
<script>
    Vue.prototype.bus = new Vue()
    Vue.component('child', {
        data: function () {
            return {
                selfContent: this.content
            }
        },
        template: "<div @click='handleClick'>{{selfContent}}</div>",
        props: {
            content: String
        },
        methods: {
            handleClick: function () {
                this.bus.$emit('change',this.selfContent)
            }
        },
        mounted: function () {
            var this_=this;
            this.bus.$on('change',function (msg) {
                this_.selfContent=msg;
            })
        }
    })

    var vm = new Vue ({
        el: '#root'
    })
</script>

实现效果,点击hello那个组件,world也会跟着变成hello,這就是一个简单的发布订阅,实现了子组件间的传值。

2.Vuex

这个内容又比较多了,以后单独写一章吧!

在Vue中使用插槽

插槽(slot):
作用:父组件可以优雅的向子组件传递dom,方便维护。
在父组件中直接写要插入的dom,在子组件的template中 用默认内容这个标签来替换父组件中的dom。
注意:可以在slot中定义默认值
具名插槽:
父组件传给子组件2个插槽,在父组件的标签上分别为slot=“a” slot=“b”
在子组件的template的slot标签中这样来使用:

  <slot name="a"></slot>
  <slot name="b"></slot>

举个简单的具名插槽的例子

<div id="root">
    <item>
        <div class="header" slot="header"><h1>header</h1></div>
        <div class="footer" slot="footer">footer</div>
    </item>
</div>
<script type="text/javascript">
    Vue.component('item',{
        template: `<div>
                        <slot name="header"></slot>
                        body
                        <slot name="footer"></slot>
                    </div>`

    })
    var vm = new Vue({
        el: '#root',
    })
</script>

这个的结果就是Vue学习笔记之深入理解Vue组件(二)

作用域插槽:

使用场景:
子组件遍历展示,并且DOM是从父组件传入的时候,
或者说,同一个组件在不同地方使用,需要展现不同的样子。
作用域插槽在父组件中一定要用<template slot-scope="props"></template>包裹且必须定义slot-scope="name"来接收子组件中的数据。
例如无序列表输出1234

<div id="root">
    <child>
        <template slot-scope="props">
            <li>{{props.item}}</li>
        </template>
    </child>
</div>
<script type="text/javascript">
    Vue.component('child',{
        data: function () {
            return {
                list: [1,2,3,4]
            }
        },
        template: `<div>
                        <ul>
                            <slot
                                v-for="item of list"
                                :item="item"
                            ></slot>
                        </ul>
                    </div>`

    })
    var vm = new Vue({
        el: '#root',
    })
</script>

动态组件

动态组件:
<component :is="name"></component> 注:Vue自带默认的动态组件。
它用:is 绑定data数据,动态的切换组件。data数据是子组件的名称。