美文网首页
Vue核心知识-Vue的组件之高级属性

Vue核心知识-Vue的组件之高级属性

作者: 王童孟 | 来源:发表于2018-09-08 17:21 被阅读0次

    插槽

    slot 是 vue 的内置组件。

    简单使用

    定义一个布局组件,里面放什么会在调用组件时决定,我们不会在布局组件里进行内容设置。在组件标签内部写的内容,可以通过 slot 在组件内部模板中进行使用。

    import Vue from 'vue'
    
    const component = {
      template: `
        <div :style="style">
          <slot></slot>
        </div>
      `,
      data () {
        return {
          style: {
            width: '200px',
            height: '200px',
            border: '1px solid #aaa'
          }
        }
      }
    }
    
    new Vue({
      components: {
        CompOne: component
      },
      el: '#root',
      data () {
        return {
          value: '123'
        }
      },
      template: `
        <div>
          <comp-one v-model="value">
            <span>this is content</span>
          </comp-one>
        </div>
      `
    })
    

    具名插槽

    通过 slot 的 name 属性可以指定插入多个内容。

    import Vue from 'vue'
    
    const component = {
      template: `
        <div :style="style">
          <div class="header">
            <slot name="header"></slot>
          </div>
          <div class="body">
            <slot name="body"></slot>
          </div>
        </div>
      `,
      data () {
        return {
          style: {
            width: '200px',
            height: '200px',
            border: '1px solid #aaa'
          }
        }
      }
    }
    
    new Vue({
      components: {
        CompOne: component
      },
      el: '#root',
      data () {
        return {
          value: '123'
        }
      },
      template: `
        <div>
          <comp-one v-model="value">
            <span slot="header">this is content</span>
            <span slot="body">this is body</span>
          </comp-one>
        </div>
      `
    })
    

    作用域插槽

    scoped slot ,作用域插槽,组件内属性通过作用域插槽传出进行使用。

    通常,插槽内使用的属性,使用的是引用组件的组件的属性值。

    import Vue from 'vue'
    
    const component = {
      template: `
        <div :style="style">
          <slot></slot>
        </div>
      `,
      data () {
        return {
          style: {
            width: '200px',
            height: '200px',
            border: '1px solid #aaa'
          }
        }
      }
    }
    
    new Vue({
      components: {
        CompOne: component
      },
      el: '#root',
      data () {
        return {
          value: '123'
        }
      },
      template: `
        <div>
          <comp-one v-model="value">
            <span>{{value}}t</span>
          </comp-one>
        </div>
      `
    })
    

    如果希望插槽模板中使用的属性是组件中的属性时,就用到了 scoped slot

    import Vue from 'vue'
    
    const component = {
      template: `
        <div :style="style">
          <slot :value="value" aaa="111"></slot>
        </div>
      `,
      data () {
        return {
          style: {
            width: '200px',
            height: '200px',
            border: '1px solid #aaa'
          },
          value: 'component value'
        }
      }
    }
    
    new Vue({
      components: {
        CompOne: component
      },
      el: '#root',
      data () {
        return {
          value: '123'
        }
      },
      template: `
        <div>
          <comp-one v-model="value">
            <span slot-scope="props">{{props.value}} {{props.aaa}} {{value}}</span>
          </comp-one>
        </div>
      `
    })
    

    给组件加 ref

    打印结果 this.$refs.comp 是 vue 组件,this.$refs.span 打印出来的是 html 节点,这也是 ref 用在组件和 html 原生标签上的区别

    可以通过 $refs 得到组件,进而调用组件的变量和方法,如 this.$refs.comp.value 拿到了组件内部变量 value 值。所以可以通过 ref 操纵组件上的内容(推荐用 props 操纵),除非特殊情况

    mounted () {
        console.log(this.$refs.comp, this.$refs.span, this.$refs.comp.value)
      },
      template: `
        <div>
          <comp-one ref="comp">
            <span slot-scope="props" ref="span">{{props.value}} {{props.aaa}} {{value}}</span>
          </comp-one>
        </div>
      `
    

    provide inject越级得实例

    $parent 只能到 组件上一级,如果是跨域多级是不行的,通过 provide 和 injection 可以 越级拿到 vue 实例

    import Vue from 'vue'
    
    const ChildComponent = {
      template: `<div>child component</div>`,
      inject: ['yeye', 'value'],  // 通过 inject 注入
      mounted () {
        console.log(this.yeye, this.value)  // 在子子组件打印 爷爷实例和数据
      }
    }
    
    const component = {
      name: 'comp',
      components: {
        ChildComponent
      },
      template: `
        <div :style="style">
          <slot :value="value" aaa="111"></slot>
          <child-component />
        </div>
      `,
      data () {
        return {
          style: {
            width: '200px',
            height: '200px',
            border: '1px solid #aaa'
          },
          value: 'component value'
        }
      }
    }
    
    new Vue({
      components: {
        CompOne: component
      },
      provide () {   // 通过 provide,提供 实例 和 实例的一个属性
        return {
          yeye: this,
          value: this.value
        }
      },
      el: '#root',
      data () {
        return {
          value: '123'
        }
      },
      mounted () {
        console.log(this.$refs.comp, this.$refs.span, this.$refs.comp.value)
      },
      template: `
        <div>
          <comp-one ref="comp">
            <span slot-scope="props" ref="span">{{props.value}} {{props.aaa}} {{value}}</span>
          </comp-one>
        </div>
      `
    })
    

    默认情况,provide 不提供 reactive 的属性的,所以我们改 value 的值,子孙组件里 Inject拿到的 value 是不会跟着变的。如果需要改变,需要自己给指定的属性提供 get 方法。这样子孙组件拿到的 data.value 都是通过 get 方法,而 get 方法每次都会获取最新的 value。这个方法比较 hack,可能会被废弃

    // 子孙组件
    const ChildComponent = {
      template: `<div>child component: {{data.value}}</div>`,
      inject: ['yeye', 'data'],
      mounted () {
        console.log(this.yeye, this.value)
      }
    }
    // 爷爷组件
    provide () {
        const data = {}
    
        Object.defineProperties(data, 'value', {
          get: () => this.value,
          enumerable: true
        })
        return {
          yeye: this,
          value: this.value
        }
      },
    

    相关文章

      网友评论

          本文标题:Vue核心知识-Vue的组件之高级属性

          本文链接:https://www.haomeiwen.com/subject/zzhlgftx.html