Vue/组件
创建组件
单独声明一个Vue.component,使用只需要在Vue实例下使用定义的组件名
在组件中data不能是一个对象,而必须是一个函数,这个函数返回一个对象
全局组件
<div id='#app'>
<my-component></my-component>
</div>
Vue.component('my-component',{
data(){
return {
name: 'sss'
}
},
template: `<div>我的第一个组件 - {{name}}}</div>`
})
//my-component 声明的组件名
//template 组件的模板
局部组件
放在实例的对象components下,使用只能在实例el下使用
let vm = new Vue({
el: '#app2',
components: {
"child-component": {
template: `<div>局部组件 - {{name}}}</div>`
}
}
})
组件通信
props down, events up,
父组件传递给子组件数据,通过属性传递,子组件传递给父组件数据,通过事件传递
<div id="app">
<my-component food="西瓜"></my-component>
</div>
Vue.component('my-component',{
props:['food'], //一个子组件需要通过props中的获得父组件传递的属性信息
template: `<div><p>{{food}}</p></div>`
})
//获取实例下数据
<div id="app">
<my-component v-bild:food="foods"></my-component>
</div>
Vue.component('my-component',{
props:["food"],
template:`
<div>
<p>{{food}}</p>
</div>
`,
})
new Vue({
el: '#app',
data: {
foods: "苹果"
}
})
//苹果
子组件可以接收来自父组件的数据,为了保证数据的正确性,完整性,安全性,vue会禁止直接修改父组件的数据,如果非要更改这个数据,一定要通过事件的方式通知父组件
比如上面的我们在模版下定义一个按钮,当点击的时候
<div id="app3">
<my-component :data="foods" @edit-data="callback"></my-component>
</div>
Vue.component('my-component',{
props:["data"],
template:`
<div>
<p>{{data}}</p>
<button @click="click">按钮</button>
</div>
`,
methods: {
click(){
this.$emit('edit-data',"我要吃苹果")
//点击后,触发事件
}
}
})
let vm = new Vue({
el: '#app3',
data: {
foods:
"苹果"
},
methods: {
callback(v){
//这边就监听到后,相当于子组件要请求修改数据,通过事件传递给父组件,然后告诉实例,实例自己来修改数据,最后影响到数据的更改
this.foods = v;
}
}
})
console.log(vm.foods)
props验证
我们可以为组件的 props 指定验证规格。如果传入的数据不符合规格,Vue 会发出警告。当组件给其他人使用时,要指定验证规格,需要用对象的形式,而不能用字符串数组:
//在props里通过一个对象来给props来限制条件
Vue.component('example', {
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 value > 10
}
}
}
})
非prop属性
如果一个组件标签上的属性没有在props中定义,那么这个属性将会被自动添加到组件的根元素上,对于style和class进行合并(把组件标签上的style或class与区间根元素上的style或class进行合并),但是其他的属性将是覆盖操作
//div background: red; border: 1px solid #000;<div id="app">
<m-area style="border: 1px solid #000" :r="100"></m-area>
</div>
Vue.component("mArea",{
props: {
r: {
type: Number,
default: 10
}
},
template: `
<div style="background: red">
<p>面积: {{Math.PI * r * r}}</p>
</div>
`
});
let vm = new Vue({
el: "#app"
})
//div background: red; border: 1px solid #000;
style标签并没有在props中定义,那就会自动添加在组件模版根元素(div)上,style这个属性也不是被覆盖,而是合并在一起了
插槽slot
在组件模板中通过 <slot></slot> 来定义一个插槽,在解析的时候,会把对应的内容放到slot位置
一个组件中可以使用多个slot,如果有多个的话,需要给slot设置name属性,没有name的就是默认插槽
<div id="app">
<h1>自身h1标题</h1>
<my-component>
<p>自身的文字</p>
<p>自身的文字1111</p>
</my-component>
</div>
Vue.component('my-component',{
template:`
<div>
<p>模版文字</p>
<span>moban</span>
<slot>slot的文字</slot>
</div>
`
});
//如果外面使用模版,有模版以为的内容,看里面是否有插槽,有就把外面自身的内容放到插槽位置里,没有内容就是用插槽的内容
具名
<slot>
元素可以用一个特殊的属性name
来配置如何分发内容。多个 slot 可以有不同的名字。具名 slot 将匹配内容片段中有对应slot
特性的元素。仍然可以有一个匿名 slot,它是默认 slot,作为找不到匹配的内容片段的备用插槽。如果没有默认的 slot,这些找不到匹配的内容片段将被抛弃。
<div id="app">
<my-component>
<p>没有固定要放的位置</p>
<h1 slot="head">我要放的自己的头部内容</h1>
<p>没有固定要放的位置111</p>
<p slot="foot">我要放的自己的底部内容</p>
<p slot="head">我要放的自己的头部内容111</p>
</my-component>
</div>
Vue.component('my-component',{
template:`
<div>
<header>
<slot name="head"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="foot"></slot>
</footer>
</div>
`
});
//展示
<div>
<header>
<h1>我要放的自己的头部内容</h1>
<p>我要放的自己的头部内容111</p>
</header>
<main>
<p>没有固定要放的位置</p>
<p>没有固定要放的位置111</p>
</main>
<footer>
<p>我要放的自己的底部内容</p>
</footer>
</div>
作用域插槽
作用域插槽是一种特殊类型的插槽,用作使用一个 (能够传递数据到) 可重用模板替换已渲染元素。
在父级中,具有特殊属性
scope
的<template>
元素必须存在,表示它是作用域插槽的模板。scope
的值对应一个临时变量名,此变量接收从子组件中传递的 props 对象:
<div id="app">
<div class="parent">
<my-component>
<template scope="props">
<span>{{props.text}}</span>
</template>
</my-component>
</div>
</div>
Vue.component('my-component',{
template:`
<div class="child">
<slot a=10></slot>
<slot b=10></slot>
<slot age="18"></slot>
<slot text="hello from child"></slot>
</div>
`
});
//相当于循环了模版里的内容,你有几个slot就循环几次,那就是4个span标签,内容就用{{props.需要的属性}},没有就为空标签
//展现
<div class="parent">
<div class="child">
<span></span>
<span></span>
<span></span>
<span>hello from child</span>
</div>
</div>
具名作用域
<div id="app">
<my-component>
<template scope="props" slot="list"> //
<li>{{props.text}}</li>
</template>
</my-component>
</div>
Vue.component('my-component',{
template:`
<ul>
<slot name="list" v-for="item in items" :text="item"></slot>
</ul>
`
new Vue({
el: '#app',
data: {
items: ["a","b","c","d","e"]
}
})
//显示
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
</ul>