组件注册
- 关于组件名:
*组件名可所以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