ch4 深入理解vue组件

组件使用细节点

is用于动态组件且基于 DOM 内模板的限制来工作。

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentView"></component>

<!--  `<my-row>` 放在一个`<table>` 内可能无效且被放置到外面 -->
<!-- 所以使用is  类似的有ul>li select>option -->
<table>
  <tr is="my-row"></tr>
</table>

<ul>
  <li is="my-row"></li>
</ul>

<select>
  <option is="my-row"></option>
</select>

 一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝

Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。

如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素

<p ref="p">hello</p>

如果用在子组件上,引用就指向组件实例

<child-component ref="child"></child-component>

计数example:

<div id="root">
    <counter ref="one" @change="handleChange"></counter>
    <counter ref="two" @change="handleChange"></counter>
    <div>{{total}}</div>
</div>
<script>
    Vue.component('counter', {
        template:'<div @click="handleClick">{{number}}</div>',
        data: function() {
            return {
                number: 0
            }
        },
        methods: {
            handleClick: function() {
                this.number++;
                this.$emit('change');
            }
        }
    })
    var vm = new Vue({
        el: '#root',
        data: {
            total: 0
        },
        methods: {
            handleChange: function() {
                this.total = this.$refs.one.number + this.$refs.two.number;
            }
        }
    })
</script>

父子组件的数据传递

父组件通过属性的形式向子组件传值,子组件通过事件触发的形式向父组件传值。

父组件向子组件传递数据----props

单向数据流:父组件可以向子组件传递参数,但子组件不能直接修改父组件传递过来的参数。因为一旦修改的参数不是一个基础类型而是引用类型的数据时,有可能接收的引用类型的数据还被其他的子组件使用,改变传递过来的数据里的内容可能对其他的子组件造成影响。
<div id="root">
    <!--传递-->
    <!--加了冒号是数字(js表达式) 不加是字符串-->
    <counter :count="0"></counter>
    <counter :count="1"></counter>
</div>
<script>
    var counter = {
        props: ['count'], //接收
        data: function() {
            return {
                number: this.count//把count复制一份放到子组件自己的data里 解决单向数据流
            }
        },
        template: '<div @click="handleClick">{{number}}</div>',
        methods: {
            handleClick: function() {
                this.number++;
            }
        }
    }
    var vm = new Vue({
        el: "#root",
        components: {
            counter: counter
        }
    })
</script>

子组件向父组件传递数据----事件触发

<div id="root">
    <!--2 @inc="handleInc 父组件在这里监听子组件传递的事件-->
    <counter :count="0" @inc="handleInc"></counter> 
    <counter :count="1" @inc="handleInc"></counter>
    <div>{{total}}</div>
</div>
<script>
    var counter = {
        props: ['count'],
        data: function() {
            return {
                number: this.count
            }
        },
        template: '<div @click="handleClick">{{number}}</div>',
        methods: {
            handleClick: function() {
                this.number = this.number + 2;
               //1 子组件向父组件通过事件触发的形式传递数据 inc后面可以携带多个参数
                this.$emit('inc', 2);
            }
        }
    }
    var vm = new Vue({
        el: "#root",
        components: {
            counter: counter
        },
        data: {
            total: 1
        },
        methods: {
            handleInc: function(step) { //step即子组件向父组件传递的参数 2
                this.total += step;
            }
        }
    })
</script>

组件参数校验

<div id="root">
    <child content="helloo"></child>
</div>
<script>
    Vue.component('child', {
        // props: {
        //     content: [Number, String]
        // },
        props: {
                content: {
                    type: String,//类型为string
                    required: false,//如果为true则一定要传content
                    default: 'default value',//如果没传content显示的默认值
                    validator: function(value) {//value为传入的字符串的内容
                        return (value.length > 5)
                    }
                }
            },
        template:'<div>{{content}}</div>'
    })
    var vm = new Vue({
        el: "#root",
    })

给组件绑定原生事件

要在一个组件的根元素上直接监听一个原生事件,可以使用 v-on 的 .native 修饰符:

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

<div id="root">
    <!--监听的是自定义事件 -->
    <child @click="handleClick"></child>
</div>
<script>
    Vue.component('child', {
        template:'<div @click="handleChildClick">Child</div>',
        methods: {
            handleChildClick: function() {
                alert('child click');
                this.$emit('click');//触发自定义事件
            }
        }
    })
    var vm = new Vue({
        el: "#root",
        methods: {
            handleClick: function() {
                alert('click');
            }
        }
    })
</script>
<div id="root">
    <!--监听原生事件 -->
    <child @click.native="handleClick"></child>
</div>
<script>
    Vue.component('child', {
        template:'<div>Child</div>',
    })
    var vm = new Vue({
        el: "#root",
        methods: {
            handleClick: function() {
                alert('click');
            }
        }
    })
</script>

非父子组件间的数据传递(Bus/总线/发布订阅模式/观察则模式)

<div id="root">
    <child content="a"></child>
    <child content="b"></child>
</div>
<script>
    Vue.prototype.bus = new Vue()//!

    Vue.component('child', {
        props:{
            content: String
        },
        data: function() {
            return {
                selfContent: this.content
            }
        },
        template:'<div @click="handleClick">{{selfContent}}</div>',
        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>

插槽slot

更方便地向子组件传递DOM元素,子组件通过<slot></slot>使用内容

可以在slot里写一些默认的值——<slot>默认内容</slot>

<div id="root">
    <child><p>dell</p></child>
</div>
<script>

    Vue.component('child', {
        props: ['content'],
        template: '<div> <p>hello</p> <slot>默认内容</slot> </div>'
    })

    var vm = new Vue({
        el: "#root",
    })

具名插槽

<body>
<div id="root">
    <child>
        <div class="header" slot="header">header</div>
        <div class="footer" slot="footer">footer</div>
    </child>
</div>
<script>

    Vue.component('child', {
        props: ['content'],
        template: '<div> <slot name="header"> </slot><slot name="header"></slot></div>'
    })

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

自 2.6.0 起有所更新。

<template v-slot:header>
    <h1>Here might be a page title</h1>
</template>

作用域插槽

当子组件做循环或者某一部分结构应该由外部传递进来的时候就用作用域插槽

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

动态组件

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

v-once指令

只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过,可以用于优化更新性能。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值