vue入门笔记系统(六)vue组件

组件注册

  • 关于组件名:

*组件名可所以kebab-case (短横线分开定名)或许PascalCase (驼峰式定名)
当运用 kebab-case (短横线分开定名) 定义一个组件时,你也必需在援用这个自定义元素时运用 kebab-case
当运用 PascalCase (驼峰式定名) 定义一个组件时,你在援用这个自定义元素时两种定名法都能够运用。*

全局注册

//在注册以后能够用在任何新竖立的 Vue 根实例 (new Vue) 的模板中
Vue.component('my-component-name', {
  // ... 选项 ...
})

部分注册

const component = {
    template: `
    <div>
      <input type="text" v-model="text">
    </div>
  `,
    data() {
        return {
            text: 123
        }
    },
    methods:{

    }

}
const app = new Vue({
    //el:'#root',
    components: {
        comp: component
    },
    template: '<comp></comp>',

}).$mount("#root")

模板的请求

注重:组件的模板只能有一个根元素。下面的状况是不许可的。

template: `<div>这是一个部分的自定义组件,只能在当前Vue实例中运用</div>
            <button>hello</button>`,

组件中的data必需是函数

当我们定义这个 <button-counter> 组件时,你能够会发明它的 data 并非像如许直接供应一个对象:

data: {
  count: 0
}

取而代之的是,一个组件的 data 选项必需是一个函数,因而每一个实例能够保护一份被返回对象的自力的拷贝:

data: function () {
  return {
    count: 0
  }
}

假如 Vue 没有这条划定规矩,一切模板都邑同享一份数据。

剖析 DOM 模板时的注重事项

有些 HTML 元素,诸如 <ul>、<ol>、<table> 和 <select>,关于哪些元素能够涌现在其内部是有严厉限定的。而有些元素,诸如 <li>、<tr> 和 <option>,只能涌现在别的某些特定的元素内部。

这会致使我们运用这些有约束条件的元素时碰到一些问题。比方:

<table>
  <blog-post-row></blog-post-row>
</table>

这个自定义组件 <blog-post-row> 会被作为无效的内容提升到外部,并致使终究衬着效果失足。幸亏这个特别的 is 特征给了我们一个变通的要领:

<table>
  <tr is="blog-post-row"></tr>
</table>

须要注重的是假如我们从以下泉源运用模板的话,这条限定是不存在的:

字符串 (比方:template: ‘…’)
单文件组件 (.vue)
<script type=”text/x-template”>

Prop

  • Prop 范例
//一般范例
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
//指定范例
props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object
}

单项数据流,通报事后不能修正
有两种罕见的试图转变一个 prop 的情况:

//这个 prop 用来通报一个初始值;这个子组件接下来愿望将其作为一个当地的 prop 数据来运用。
props: ['initialCounter'],
data: function () {
  return {
    counter: this.initialCounter
  }
}
//这个 prop 以一种原始的值传入且须要举行转换
props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

Prop 考证

Vue.component('my-component', {
  props: {
    // 基本的范例搜检 (`null` 婚配任何范例)
    propA: Number,
    // 多个能够的范例
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默许值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默许值的对象
    propE: {
      type: Object,
      // 对象或数组且肯定会从一个工场函数返回默许值
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义考证函数
    propF: {
      validator: function (value) {
        // 这个值必需婚配以下字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

parent选项

范例:Vue instance

细致:

指定已竖立的实例之父实例,在两者之间竖立父子关联。子实例能够用 this.$parent 接见父实例,子实例被推入父实例的 $children 数组中。

//定义一个父组件
const parent = new Vue({
  name: 'parent'
})
//定义一个组件
const componet2 = {
  data () {
    return {
      text: 1
    }
  },
  mounted () {
    console.log(this.$parent.$options.name) //打印Root
    this.$parent.text = 1234; //也能够修正,控制地运用 $parent 和 $children - 它们的重要目标是作为接见组件的应急要领。更引荐用 props 和 events 完成父子组件通讯
  }
}

//竖立vue实例
new Vue({
  parent: parent,
  name: 'Root',
  el: '#root',
  mounted () {
    console.log(this.$parent.$options.name) //此时打印出'parent'
  },
  components: {
    Comp: componet2
  },
  data: {
    text: 23333
  },
  template: `
    <div>
      <span>{{text}}</span>
      <comp></comp>
    </div>
  `
})

组件继续

Vue.extend( options )
运用基本 Vue 组织器,竖立一个“子类”。参数是一个包括组件选项的对象。

//包括组件选项的对象
const compoent = {
  props: {
    active: Boolean,
    propOne: String
  },
  template: `
    <div>
      <input type="text" v-model="text">
      <span @click="handleChange">{{propOne}}</span>
      <span v-show="active">see me if active</span>
    </div>
  `,
  data () {
    return {
      text: 0
    }
  },
  mounted () {
    console.log('comp mounted')
  },
  methods: {
    handleChange () {
      this.$emit('change')
    }
  }
}

// 竖立组织器
const CompVue = Vue.extend(compoent)

// 竖立 CompVue实例,并挂载到一个元素上。
new CompVue({
  el: '#root',
  propsData: { //通报props属性
    propOne: 'xxx'
  },
  data: { //能够掩盖或许兼并
    text: '123'
  },
  mounted () { //不会掩盖 ,都邑被挪用
    console.log('instance mounted')
  }
})

自定义双向绑定

父子组件通报举行绑定

// 1定义一个组件对象
const component = {
  props: ['value'],
  template: `
    <div>
      <input type="text" @input="handleInput" :value="value">  //绑定通报过来的value
    </div>
  `,
  methods: { //向父组件触发事宜
    handleInput (e) {
      this.$emit('input', e.target.value)
    }
  }
}

//2定义一个实例
new Vue({
  components: {
    CompOne: component
  },
  el: '#root',
  data () {
    return {
      value: '123'
    }
  },
//接收事宜并转变value举行属性通报
  template: `
    <div>
        <span>{{value}}</span>
       <comp-one :value="value" @input="value = arguments[0]"></comp-one>
    </div>
  `
})

v-model绑定

const component = {
//   model: {
//     prop: 'value1',
//     event: 'change'
//   },
  props: ['value'],
  template: `
    <div>
      <input type="text" @input="handleInput" :value="value">
    </div>
  `,
  methods: {
    handleInput (e) {
      this.$emit('input', e.target.value)
    }
  }
}

new Vue({
  components: {
    CompOne: component
  },
  el: '#root',
  data () {
    return {
      value: '123'
    }
  },
  template: `
    <div>
        <span>{{value}}</span>
       <comp-one v-model=value></comp-one> //直接运用v-model绑定
    </div>
  `
})

选项model

许可一个自定义组件在运用 v-model 时定制 prop 和 event。默许状况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event,然则一些输入范例比方单选框和复选框按钮能够想运用 value prop 来到达差别的目标。运用 model 选项能够逃避这些状况发生的争执。

import Vue from 'vue'

const component = {
  model: {
    prop: 'value1', //绑定value1    
    event: 'change'//绑定事宜
  },
  props: ['value','value1'],
  template: `
    <div>
      <input type="text" @change="handleInput" :value="value1">
    </div>
  `,
  methods: {
    handleInput (e) {
      this.$emit('change', e.target.value)
    }
  }
}

new Vue({
  components: {
    CompOne: component
  },
  el: '#root',
  data () {
    return {
      value: '123'
    }
  },
  template: `
    <div>
        <span>{{value}}</span>
       <comp-one v-model=value></comp-one>
    </div>
  `
})

非父子组件间的传值

兄弟间的组件通报:

1.运用vue官方供应的vuex(有肯定难度,进修本钱较大)
2.宣布定阅形式(总线机制,Bus)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id = "app">
        <child content="Dell"></child>
        <child content="lee"></child>

    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
    <script>
        //增添一个bus属性,指向vue的实例
        Vue.prototype.bus = new Vue()


        Vue.component('child',{
            props:{
                content:String
            },
            data:function(){
                return {
                    seleContent:this.content
                }
            },
            template:'<div @click="handleClick">{{seleContent}}</div>',
            methods:{
                handleClick(){
                    this.bus.$emit('change',this.seleContent)
                }
            },
            mounted(){
                let _this = this;
                this.bus.$on('change',function(msg){
                    _this.seleContent = msg
                })
            }
        })

        new Vue({
            el: "#app"
        })
    </script>
</body>
</html>

插槽

插槽内容

const component = {
  template: `
    <div :style="style">
      <slot></slot> //vue的默许组件,安排插槽的处所
    </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'
    }
  },
  mounted () {

  },
  template: `
    <div>
      <comp-one>
        <span>this is contne</span> //通报插槽内容
      </comp-one>
    </div>
  `
})

签字插槽

有些时刻我们须要多个插槽,能够举行定名;

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'
      },
      value: 'component value'
    }
  }
}

new Vue({
  components: {
    CompOne: component
  },
  el: '#root',
  data () {
    return {
      value: '123'
    }
  },
  mounted () {

  },
  template: `
    <div>
      <comp-one ref="comp">
        <span slot="header">this is header</span> ///向指定的内容
        <span slot="body">this is body</span>
      </comp-one>
    </div>
  `
})

插槽的默许内容

能够在 <slot> 标签内部指定默许的内容来做到这一点。

<button type="submit">
  <slot>Submit</slot>
</button>

假如父组件为这个插槽供应了内容,则默许的内容会被替换掉。

作用域插槽

import Vue from 'vue'

const component = {
  template: `
    <div :style="style">
      <slot :value="value"></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'
    }
  },
  mounted () {
    console.log(this.$refs.comp.value, this.$refs.span) //打印出组件实例和HTML标签
  },
  template: `
    <div>
      <comp-one ref="comp">
        <span>{{value}}</span> //此时没有作用域,接见到的不是组件内的value,而是外部的value
        //增加作用域,组件内部通报的数据都保存在props对象中
        <span slot-scope="props" ref="span">{{props.value}}</span>
      </comp-one>
    </div>
  `
})

动态组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id = "app">
        <!-- <child-one v-if="type ==='child-one'"></child-one>
        <child-two v-if="type ==='child-two'"></child-two> -->
        <component :is="type"></component>
        <button @click="handleBtn">change</button>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
    <script>

        Vue.component('child-one',{
            template:'<div>child-one</div>'
        })
        Vue.component('child-two',{
            template:'<div>child-two</div>'
        })
        new Vue({
            el: "#app",
            data:{
                type:"child-one"
            },
            methods:{
                handleBtn(){
                    this.type=this.type==="child-one"?"child-two":"child-one"
                }
            }
        })
    </script>
</body>
</html>

provide / inject 跨级组件通讯

这对选项须要一同运用,以许可一个先人组件向其一切子孙后代注入一个依靠,不管组件条理有多深,并在起上下游关联建立的时间里一直见效。

import Vue from 'vue'

const ChildComponent = {
  template: '<div>child component:</div>',
  inject: ['yeye','value'], 
  mounted () {
    console.log(this.$parent.$options.name) //上一级
    console.log(this.yeye,this.value) //上上一级,接收到的数据,打印出上上一级的vue实例和123
  }
}

const component = {
  name: 'comp',
  components: {
    ChildComponent
  },
  template: `
    <div :style="style">
      <slot :value="value"></slot>
      <ChildComponent></ChildComponent>
    </div>
  `,
  data () {
    return {
      style: {
        width: '200px',
        height: '200px',
        border: '1px solid #aaa'
      },
      value: 'component value',
      value2: 'component222 value'
    }
  }
}

new Vue({
  components: {
    CompOne: component
  },
  provide () { //和data一样,能够挪用相应的值,是一个对象或返回一个对象的函数。该对象包括可注入其子孙的属性。
    return {
      yeye: this,
      value:this.value
    }
  },
  el: '#root',
  data () {
    return {
      value: '123'
    }
  },
  mounted () {
    console.log(this.$refs.comp.value2, this.$refs.span)
  },
  template: `
    <div>
      <comp-one ref="comp">
        <span slot-scope="props" ref="span">{{props.value}}</span>
      </comp-one>
    </div>
  `
})

provide 和 inject 绑定并非可相应的。这是刻意为之的。provide 和 inject 绑定并非可相应的。这是刻意为之的。

import Vue from 'vue'

const ChildComponent = {
  template: '<div>child component:{{data.value}}</div>',
  inject: ['yeye','data'],
  mounted () {
    console.log(this.$parent.$options.name) //上一级
    console.log(this.yeye,this.value) //上一级
  }
}

const component = {
  name: 'comp',
  components: {
    ChildComponent
  },
//   template: `
//     <div :style="style">
//       <div class="header">
//         <slot name="header"></slot>
//       </div>
//       <div class="body">
//         <slot name="body"></slot>
//       </div>
//     </div>
//   `,
  template: `
    <div :style="style">
      <slot :value="value"></slot>
      <ChildComponent></ChildComponent>
    </div>
  `,
  data () {
    return {
      style: {
        width: '200px',
        height: '200px',
        border: '1px solid #aaa'
      },
      value: 'component value',
      value2: 'component222 value'
    }
  }
}

new Vue({
  components: {
    CompOne: component
  },
  provide () { //和data一样,能够挪用相应的值
    const data = {}

    // es5双向绑定完成道理
    Object.defineProperty(data, 'value', {
      get: () => this.value, //猎取最新value,每次挪用value相当于get()要领
      enumerable: true //可读取
    })

    return {
      yeye: this,
    //   value:this.value
      data
    }
  },
  el: '#root',
  data () {
    return {
      value: '123'
    }
  },
  mounted () {
    console.log(this.$refs.comp.value2, this.$refs.span)
  },
  template: `
    <div>
      <comp-one ref="comp">
        <span slot-scope="props" ref="span">{{props.value}}</span>
      </comp-one>
      <input v-model="value" />
    </div>
  `
})

provide 和 inject 重要为高阶插件/组件库供运用例。并不引荐直接用于运用程序代码中。

衬着函数 & JSX

参考:衬着函数&JSX

    原文作者:sevencui
    原文地址: https://segmentfault.com/a/1190000015969998
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞