深入理解vue组件

使用组件的细节点

  1. is属性:
    有些html标签如table,ul,ol,select对哪些标签可以出现在其内部是有着严格的要求的。
    因此当这些标签内部出现了自定义组件,有可能会被作为无效的内容提升到外部,导致页面渲染出错。
    而是用is属性则可以解决这个问题,在子级标签中用is属性来使用自定义组件。
    <table>
    <tr is="模板名称"></tr>
    </table>

  2. 子组件中的data必须是一个函数,并且返回一个对象,当一个组件被多次使用的时候,组件间的数据不会相互影响。

Vue.component('row', {
    data:function () {
          return{
              content:'this is row'
          }
    },
    template:"<tr><td>{{content}}</td></tr>"
})
  1. 通过ref 获取dom节点
<div @click="handdle" ref="hello">
    hello world
</div>

handdle:function(){
    console.log(this.$refs.hello)
}

父子组件传值

  1. 父组件向子组件传值

父组件通过属性绑定将值绑定到子组件上,子组件通过 props 属性来接收,然后子组件就可以使用父组件中传递过来的数据了。props是一个数组。

  1. 子组件向父组件传值:
  • 子组件通过this.$emit()方法向父组件传值;
  • $emit("事件名",args)第一个参数是自定义事件名,第二个参数是需要传递的数据
  • 父组件使用v-on监听子组件
  1. 单向数据流

父组件可以随意向子组件传递参数,子组件不可以改变父组件的数据,否则会报警告。
解决办法:要想改变父组件的参数,在子组件的data属性中拷贝一份父组件的数据,然后可以对数据进行操作。

<div id="app">
    <counter :count="1" @change="handleAdd"></counter>
    <counter :count="2" @change="handleAdd"></counter>
    <div>{{total}}</div>
</div>
<script>
    var counter = {
        props:['count'],
        data:function(){
          return{
              number:this.count
          }
        },
        template:'<div @click="handdle">{{number}}</div>',
        methods:{
            handdle:function(){
                this.number++;
                this.$emit('change',1)
            }
        }
    }
    var app = new Vue({
        el:'#app',
        data:{
          total:3
        },
        components:{
            counter:counter
        },
        methods: {
            handleAdd:function(step){
                this.total+=step
            }
        }
    })
</script>

组件参数校验与非props特性

  1. 简单校验:限定传入的值的类型,可以是单个类型,也可以是一个数组。
props:{
  content: [String,Number]
}
  1. 复杂校验:
props:{
 content:{
  type: String,//数据类型
  required: false,//是否是必传
  default: 'default content',//如果没传值,默认值
  validator: function(val){//自定义校验器,数据必须>5
    return (val.length>5)
  }
 }
}

给组件绑定原生事件

  1. 在父组件上绑定事件(如:@click.native="handleClick")
  2. 在vue实例中的methods下定义事件函数。
<child @click.native="handleClick" ></child>

传统方法绑定事件:

  1. 在子组件上绑定事件
  2. 在子组件中的methods中设置相应的事件函数,并在函数中定义自定义事件函数,将自定义事件函数传给父组件(如 this.$emit('click'))
  3. 在父组件上绑定子组件methods函数中传来的自定义函数
  4. 在父组件methods中设置对应的事件函数

非父子组件间的传值

  1. vuex,
  2. 发布订阅模式(总线模式)
  • 给 Vue 类加上原型属性 bus, 这样每个 Vue 实例都能访问到原型属性 bus
 Vue.prototype.bus = new Vue()
  • 利用 bus 的实例方法 $emit 触发事件
this.bus.$emit('触发事件', this.selfContent)
  • 再利用生命周期方法(钩子) mounted 给 bus 绑定监听函数, 在事件触发时执行
 this.bus.$on('eventName', cellback)
  • 建议使用箭头函数做为回调函数,不会影响回调函数中this的指向问题
 this.bus.$on('eventName',(msg) => {
     this.selfContent = mag;
 })

完整代码

<div id="app">
    <child  content="Dell"></child>
    <child  content="Lee"></child>
</div>
<script>
 Vue.prototype.bus = new Vue()
    Vue.component('child',{
        data:function(){
          return{
              selfContent:this.content
          }
        },
        props:{
            content:{
                type:String,
            }
        },
        template:'<div @click="handClick">{{selfContent}}</div>',
        methods: {
            handClick:function () {
                this.bus.$emit('change',this.selfContent)
            }
        },
        mounted:function(){
            var that = this;
           this.bus.$on('change',function(msg){
             that.selfContent = msg
           })
        }
    })
    var app = new Vue({
        el:'#app',
    })
</script>

vue中使用插槽

  1. 插槽:可以使父组件很容易向子组件传递DOM元素
  2. 匿名插槽:父组件内部的DOM元素,可以通过子组件的<slot></slot>标签渲染,slot标签中可以写默认的内容,如果父组件中不传递就显示默认内容
Vue.component('child',{
        template:'<div>' +
            '<slot>默认内容</slot>' +
            '</div>',
    })
  1. 具名插槽:有名字的插槽,父组件中为slot属性设置值,子组件slot中使用name属性接收父组件slot的属性值可以实现具名插槽。
<div id="app">
    <body-content>
       <div class="header" slot="header">header</div>
       <div class="footer" slot="footer">footer</div>
    </body-content>
</div>
<script>
Vue.component('body-content',{
    template:'<div>' +
        '<slot name="header">默认</slot>' +
        '<div class="content">content</div>' +
        '<slot name = "footer"></slot>' +
        '</div>'
})
    var app = new Vue({
        el:'#app',
    })
</script>
  1. 作用域插槽
  • 使用场景:当子组件做循环的数据和结构需要外部传入时
  • 父组件中必须以
<template slot-scope='自定义'></template>

作为包裹的标签,slot-scope接受子组件传递过来的值

  • 作用是:可以使父组件灵活的控制样式
<div id="app">
    <child>
     <template slot-scope="props">
         <h1>{{props.item}}</h1>
     </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></slot>" +
        "</ul></div>"
})
    var app = new Vue({
        el:'#app',
    })
</script>

动态组件与v-once指令

  1. 使用is与使用:is的区别:
    • is:如果这里使用is,is=后面跟的是字符串,就是指将当前使用is替换为名为type的组件,
    • :is:如果使用:is,其实,就是v-bind:is,:is=后面跟的就是一个JS表达式,表达式为type指向了type这个对象
  2. vue自带的动态标签
<component></component>

根据type的值变换为相应的组件
如果点击按钮前是type=“one”则会显示vue.component(“one”,{})这个组件
如果点击前按钮是type=“two”则会显示vue.component(“two”,{})这个组件

<div id="app">
    <component :is="type"></component>
    <button @click="handclick">点击</button>
</div>
<script>
Vue.component('child-one',{
    template:'<div>one</div>'
})
Vue.component('child-two',{
    template:'<div>two</div>'
})
    var app = new Vue({
        el:'#app',
        data:{
            type:'child-one'
        },
        methods:{
            handclick:function(){
                this.type = this.type =='child-one'?'child-two':'child-one'
            }
        }
    })

  1. v-once只对内部渲染一次,如果模板发生变化,也不会理会
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容