组件化开发
组件的基本使用(全局组件)
<!--
组件的使用分成三个步骤:
1.创建组件构造器
2.注册组件
3.使用组件。
-->
<div id="app">
<!--3.在Vue实例范围内使用组件-->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<!-- 如果组件中间没有内容,也可以写成单标签 <my-cpn/> -->
<div>
<div>
<my-cpn></my-cpn>
</div>
</div>
</div>
<my-cpn></my-cpn>
<script src="../js/vue.js"></script>
<script>
// 1.创建组件构造器对象 extend() 没有s
const cpnC = Vue.extend({
// 自定义组件的模板 使用到组件的地方,要显示的HTML代码
// *最外需要一个div包裹
template: `
<div>
<h2>我是标题</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>`
})
// 2.注册组件(全局注册)
// 需要传递两个参数:
// 1、注册组件的标签名 (必须加引号)
// 2、组件构造器
Vue.component('my-cpn', cpnC)
// 以上两步需要在Vue实例创建之前
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
全局组件和局部组件
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<div id="app2">
<cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建组件构造器
const cpnC = Vue.extend({
template: `
<div>
<h2>我是全局组件</h2>
<p>我是内容,哈哈哈哈啊</p>
</div>
`
})
// 2.注册组件(component注册的是全局组件, 意味着可以在多个Vue的实例下面使用,比如app,和app2都可以使用cpn)
// Vue.component('cpn', cpnC); // '标签名一定要加引号'
// 疑问: 怎么注册的组件才是局部组件了? 挂载在某个实例中
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
// 使用组件时的标签名:组件构造器
// 'cpn': cpnC 局部组件的标签名有无引号都可以
cpn: cpnC
}
})
const app2 = new Vue({
el: '#app2'
})
</script>
父组件和子组件
父子组件正确用法:在 父组件的components注册,在template 中使用子组件标签
<div id="app">
<cpn2></cpn2>
<!-- 父子组件错误用法:以子标签的形式在Vue实例中使用 -->
<!--<cpn1></cpn1>-->
<!-- 正确写法 在 template 中使用 <cpn1></cpn1> -->
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建第一个组件构造器(子组件)
const cpnC1 = Vue.extend({
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容, 哈哈哈哈</p>
</div>
`
})
// 2.创建第二个组件构造器(父组件)
const cpnC2 = Vue.extend({
// 2.2 在 template 中使用 <cpn1></cpn1>
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容, 呵呵呵呵</p>
<cpn1></cpn1>
</div>
`,
// 2.1 在components注册子组件cpn1
components: {
cpn1: cpnC1
}
})
// root组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn2: cpnC2
}
})
</script>
注册组件语法糖
主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替。
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<script>
// 主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替
// 1.全局组件注册的语法糖
// * Vue.component标签名必须加引号
Vue.component('cpn1', {
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容, 哈哈哈哈</p>
</div>
`
})
// 2.注册局部组件的语法糖
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
'cpn2': {
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容, 呵呵呵</p>
</div>
`
}
}
})
</script>
模块的分离写法
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<!--1.script标签, 注意:类型必须是text/x-template 然后给它设置一个id -->
<script type="text/x-template" id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈</p>
</div>
</script>
<!--2.template标签-->
<template id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容,呵呵呵</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 1.注册一个全局组件
Vue.component('cpn', {
template: '#cpn' // 需要加上选择器
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
组件数据的存放
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>{{title}}</h2>
<p>我是内容,呵呵呵</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 1.注册一个全局组件
Vue.component('cpn', {
template: '#cpn',
data() {
return {
title: 'abc'
}
}
})
// 组件是不能直接访问Vue实例中的data数据
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
// title: '我是标题'
}
})
</script>
为什么data在组件中必须是一个函数呢?
- 首先,如果不是一个函数,Vue直接就会报错。
- 其次,原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
<!--组件实例对象-->
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>当前计数: {{counter}}</h2>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 1.注册组件
const obj = {
counter: 0
}
Vue.component('cpn', {
template: '#cpn',
// data() {
// return {
// counter: 0
// }
// },
data() {
// 会一起改变
return obj
},
methods: {
increment() {
this.counter++
},
decrement() {
this.counter--
}
}
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
<script>
const object = {
name: 'why',
age: 18
}
// function abc() {
// 共用一个对象
// return object;
// }
function abc() {
// 每调用一次函数都返回一个新的对象
return {
name: 'why',
age: 18
}
}
let obj1 = abc();
let obj2 = abc();
let obj3 = abc();
obj1.name = 'kobe'
console.log(obj2);
console.log(obj3);
</script>
父子组件的通信(数据的传递)
- 通过props向子组件传递数据(父传子)
- 通过事件向父组件发送消息(子传父)
父级向子级传递---props
props基本用法
<div id="app">
<!--<cpn v-bind:cmovies="movies"></cpn>-->
<!-- 没有v-bind直接这样写是给prop传递一个静态的值,也就是说movies不是一个变量而是一个字符串 -->
<!--<cpn cmovies="movies" cmessage="message"></cpn>-->
<!-- 步骤2 通过:cmessage="message" 将data中的数据传给子组件props -->
<cpn :cmessage="message" :cmovies="movies"></cpn>
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<!-- 步骤3 将props中的值显示在子组件中 -->
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
<h2>{{cmessage}}</h2>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 父传子: props
// -------子组件------
const cpn = {
template: '#cpn',
// 子组件通过prop接收 我们能够在组件实例中访问这个值,就像访问 data 中的值一样
/* ***步骤1*** 在 子组件 定义props */
// ****方式1:字符串数组,数组中的字符串就是传递时的名称(之后要引用的变量名)
// props: ['cmovies', 'cmessage'], // 不要把元素当成字符串,把它当成数组
data() {
return {}
}
}
// -----父组件-----
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
cpn
}
})
</script>
<!--
步骤:
1.在子组件里写props
2.在子组件的标签加上v-bind <cpn v-bind:props里定义的名称="父组件data数据名称"></cpn>
3.将props中的值显示在子组件中
-->
<!--
工厂函数
1,它是一个函数。
2,它用来创建对象。
3 ,它像工厂一样,“生产”出来的函数都是“标准件”(拥有同样的属性)
-->
props数据验证---对象写法
// ***方式2:对象,对象可以设置传递时的类型,也可以设置默认值等->当需要对props进行类型等验证时
props: {
// 1.类型限制
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
// cmovies: Array,
// cmessage: String,
// 多个可能的类型
// propB: [String, Number],
// 2.提供一些默认值, 以及必传值
cmessage: {
type: String,
default: 'aaaaaaaa',
required: true // 必填的字符串
},
// 类型是对象或者数组时, 默认值必须是一个工厂函数
cmovies: {
type: Array,
default () {
return {
message: 'hello'
}
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
},
props中的驼峰标识
<div id="app">
<!-- v-bind 不支持驼峰 需要换成 - -->
<cpn :c-info="info" :child-my-message="message" v-bind:class></cpn>
</div>
<template id="cpn">
<div>
<h2>{{cInfo}}</h2>
<h2>{{childMyMessage}}</h2>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
props: {
// 在这里使用驼峰 :c-info="info" 那里要用 -
cInfo: {
type: Object,
default () {
return {}
}
},
childMyMessage: {
type: String,
default: ''
}
}
}
const app = new Vue({
el: '#app',
data: {
info: {
name: 'why',
age: 18,
height: 1.88
},
message: 'aaaaaa'
},
components: {
cpn
}
})
</script>
子级向父级传递---自定义事件
子级向父级传递
<!--父组件模板-->
<div id="app">
<!-- 3.在父组件子标签中,通过v-on来监听子组件事件 并添加一个响应该事件的处理方法 -->
<cpn @item-click="cpnClick"></cpn>
</div>
<!--子组件模板-->
<template id="cpn">
<div>
<!-- 1.在子组件中创建一个按钮,给按钮绑定一个点击事件 -->
<button v-for="item in categories" @click="btnClick(item)">
{{item.name}}
</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 子传父 自定义事件
// 子组件
const cpn = {
template: '#cpn',
data() {
return {
categories: [{
id: 'aaa',
name: '热门推荐'
},
{
id: 'bbb',
name: '手机数码'
},
{
id: 'ccc',
name: '家用家电'
},
{
id: 'ddd',
name: '电脑办公'
},
]
}
},
methods: {
btnClick(item) {
// 发射事件: 自定义事件
// 2.在子组件中,通过$emit()来触发事件
this.$emit('item-click', item)
// 注意!!!!这里的$emit事件名不要写成驼峰!!!脚手架里可以,会先编译成一个组件对象render函数
}
}
}
// 父组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn
},
methods: {
cpnClick(item) { // 这里的参数是接收子组件传过来的数据的
console.log('cpnClick', item);
}
}
})
</script>
父传子--结合双向绑定案例
<!-- 父组件 -->
<div id="app">
<h3>父组件</h3>
<h3>-----num1----</h3>
<h3>{{num1}}</h3>
<h3> -----num2----</h3>
<h3>{{num2}}</h3>
<hr>
<cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change" />
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<!-- 这样写会报错 应该是由父组件修改它,避免直接修改props的值 -->
<!--
<input v-model="number1" type="text" />
<input v-model="number2" type="text" />
-->
<h3>子组件</h3>
<h3> -----number1----</h3>
<!-- 为什么props也会跟着一起变? -> number1绑定的是父组件num1 -->
<h2>props:{{number1}}</h2>
<h2>data:{{dnumber1}}</h2>
<!--<input type="text" v-model="dnumber1">-->
<!-- v-model的本质 用@input来传值 -->
<input type="text" :value="dnumber1" @input="num1Input">
<h3>-----number2----</h3>
<h2>props:{{number2}}</h2>
<h2>data:{{dnumber2}}</h2>
<!--<input type="text" v-model="dnumber2">-->
<input type="text" :value="dnumber2" @input="num2Input">
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 子组件
const cpn = {
template: '#cpn',
props: {
number1: Number,
number2: Number
},
data() {
return {
dnumber1: this.number1,
dnumber2: this.number2
}
},
methods: {
num1Input(event) {
// 1.将input中的value赋值到dnumber中
this.dnumber1 = event.target.value;
// 2.为了让父组件可以修改值, 发出一个事件
this.$emit('num1change', this.dnumber1)
// 3.同时修饰dnumber2的值
this.dnumber2 = this.dnumber1 * 100;
this.$emit('num2change', this.dnumber2);
},
num2Input(event) {
this.dnumber2 = event.target.value;
this.$emit('num2change', this.dnumber2)
// 同时修饰dnumber1的值
this.dnumber1 = this.dnumber2 / 100;
this.$emit('num1change', this.dnumber1);
}
}
}
// 父组件
const app = new Vue({
el: '#app',
data: {
num1: 1,
num2: 0
},
methods: {
num1change(value) {
// value传过来的是string类型,需要转换成数字
this.num1 = parseFloat(value)
},
num2change(value) {
this.num2 = parseFloat(value)
}
},
components: {
cpn
}
})
</script>
父传子--结合双向绑定案例(watch实现)
<div id="app">
<cpn :number1="num1"
:number2="num2"
@num1change="num1change"
@num2change="num2change"/>
</div>
<template id="cpn">
<div>
<h2>props:{{number1}}</h2>
<h2>data:{{dnumber1}}</h2>
<input type="text" v-model="dnumber1">
<h2>props:{{number2}}</h2>
<h2>data:{{dnumber2}}</h2>
<input type="text" v-model="dnumber2">
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
num1: 1,
num2: 0
},
methods: {
num1change(value) {
this.num1 = parseFloat(value)
},
num2change(value) {
this.num2 = parseFloat(value)
}
},
components: {
cpn: {
template: '#cpn',
props: {
number1: Number,
number2: Number,
name: ''
},
data() {
return {
dnumber1: this.number1,
dnumber2: this.number2
}
},
watch: {
dnumber1(newValue) {
this.dnumber2 = newValue * 100;
this.$emit('num1change', newValue);
},
dnumber2(newValue) {
this.number1 = newValue / 100;
this.$emit('num2change', newValue);
}
}
}
}
})
</script>
补充:监听器watch
- watch选项能够监听值的变化。
<!-- watch选项能够监听值的变化 -->
<div id="app">
<input type="text" v-model="number">
</div>
<script src='../js/vue.js'></script>
<script>
const app = new Vue({
el: '#app',
data: {
number: 1,
},
watch: {
// 监听number变量,当它有变化执行
/* number(newValue, oldValue) { // newValue新值,oldValue旧值 参数只写newValue也可以
console.log('newVal', newValue);
console.log('oldVal', oldValue);
} */
// 也可以这样写
number: {
handler(newValue, oldValue) { //handler方法就是你watch中需要具体执行的方法
console.log('newVal', newValue);
console.log('oldVal', oldValue);
},
immediate: true
//immediate为true时则立即触发回调函数;如果为false,则和上面的例子一样,不会立即执行回调。
}
}
})
</script>
父子组件的访问
父子组件的访问方式: $children(父访问子)
- 父组件访问子组件:使用$children或$refs
- 子组件访问父组件:使用$parent
父子组件的访问方式: $refs(父访问子)
<div id="app">
<cpn></cpn>
<cpn></cpn>
<my-cpn></my-cpn>
<y-cpn></y-cpn>
<cpn ref="aaa"></cpn>
<button @click="btnClick">按钮</button>
</div>
<template id="cpn">
<div>我是子组件</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
methods: {
btnClick() {
// 1.$children
// console.log(this.$children);
this.$children[0].showMessage(); // 子组件的方法可以听过这种方式调用
// this.$children是一个数组类型,它包含所有子组件对象。
// for (let c of this.$children) {
// console.log(c.name);
// c.showMessage();
// }
// console.log(this.$children[3].name);
// 明确获取其中一个特定的组件,这个时候就可以使用$refs
// 2.$refs reference(引用) => 对象类型, 默认是一个空的对象 ref='bbb'
console.log(this.$refs.aaa.name);
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是子组件的name'
}
},
methods: {
showMessage() {
console.log('showMessage');
}
}
},
}
})
</script>
父子组件的访问方式: $parent(子访问父)、$root(根组件)
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是cpn组件</h2>
<ccpn></ccpn>
</div>
</template>
<template id="ccpn">
<div>
<h2>我是子组件</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是cpn组件的name'
}
},
components: {
ccpn: {
template: '#ccpn',
methods: {
btnClick() {
// 1.访问父组件$parent
// console.log(this.$parent);
// console.log(this.$parent.name);
// 2.访问根组件$root
console.log(this.$root);
console.log(this.$root.message);
}
}
}
}
}
}
})
</script>
插槽slot
slot的基本使用
<!--
插槽
插槽,也就是slot,是组件的一块HTML模板,这块模板 显示不显示、以及 怎样显示 由父组件来决定
单个插槽 | 默认插槽 | 匿名插槽
可以放置在组件的任意位置 一个组件中只能有一个该类插槽
1.插槽的基本使用 <slot></slot>
2.插槽的默认值 <slot>button</slot>
3.如果有多个值, 同时放入到组件进行替换时, 一起作为替换元素
-->
<div id="app">
<cpn></cpn>
<cpn>
<span>哈哈哈</span>
</cpn>
<cpn>
<i>呵呵呵</i>
</cpn>
<cpn>
<i>呵呵呵</i>
<div>我是div元素</div>
<p>我是p元素</p>
</cpn>
<cpn></cpn>
<cpn></cpn>
<!-- 如果不使用插槽,往组件标签里写东西是没有效果的 -->
<cpn2>略略略</cpn2>
</div>
<template id="cpn">
<div>
<h2>我是组件</h2>
<p>我是组件, 哈哈哈</p>
<slot><button>按钮</button></slot>
<!--<button>按钮</button>-->
</div>
</template>
<template id="cpn2">
<div>
<h2>我是组件222</h2>
<p>我是组件22222, 哈哈哈</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn'
},
cpn2: {
template: '#cpn2'
}
}
})
</script>
具名插槽slot
使用方式:只要给slot元素一个name属性即可 <slot name='myslot'></slot>
vue2.5写法:
<!--
具名插槽其实就是给插槽取个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,
而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中。
具名插槽就可以有很多个,只要名字(name属性)不同就可以了
-->
<div id="app">
<!-- 这个只能替换没有名字的插槽-->
<cpn><span>没有名字的替换</span></cpn>
<!-- vue2.5的写法 -->
<!-- 下面这两个还是会显示没有名字的插槽的默认内容 -->
<cpn><span slot="center">标题</span></cpn>
<cpn><button slot="left">返回</button></cpn>
</div>
<template id="cpn">
<div>
<!-- 没有名字的插槽 -->
<slot>没有名字的插槽默认内容</slot>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn'
}
}
})
</script>
vue2.6写法:
<!--
注意 v-slot 只能添加在 < template > 上,只有当被提供的内容只有默认插槽时,
组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot 直接用在组件
-->
<div id="app">
<!-- 默认 -->
<cpn></cpn>
<hr>
<!-- 使用v-slot替换 -->
<cpn>
<!-- vscode 快捷语法 vslot-named -->
<template v-slot:left>
<span>返回</span>
</template>
</cpn>
<cpn>
<!--任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。或者可以给他起名default-->
<!--<template v-slot:default>
我是内容
</template>-->
<template v-slot:center>
<span>标题</span>
</template>
<span>替换没有名字的插槽</span>
</cpn>
<cpn>
<!--
跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。
例如 v-slot:header 可以被重写为 #header:,前提是必须要有插槽名!!!
-->
<template #right>
<span>替换后的右边</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
<slot>默认插槽内容</slot>
</div>
</template>
<!-- 需要重新引入一个vue2.6之后的版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
const cpn = {
template: '#cpn'
}
const app = new Vue({
el: '#app',
data: {},
components: {
cpn
}
})
</script>
编译作用域
<div id="app">
<cpn v-show="isShow"></cpn>
<cpn v-for="item in names"></cpn>
</div>
<template id="cpn">
<div>
<h2>我是子组件</h2>
<p>我是内容, 哈哈哈</p>
<button v-show="isShow">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isShow: true
},
components: {
cpn: {
template: '#cpn',
data() {
return {
isShow: false
}
}
},
}
})
</script>
作用域插槽的使用
vue2.6之前写法:
<!-- vue2.6之前写法 -->
<div id="app">
<!-- 以下三个组件 内容一样,样式不同 -->
<cpn></cpn>
<cpn>
<!--slot-scope声明属性名 接收子组件传递的数据pLanguages-->
<template slot-scope="slot">
<!-- 在dom标签使用该数据,通常用插值表达式接收具体数据 -->
<!--<span v-for="item in slot.data"> - {{item}}</span>-->
<h3>{{slot}}</h3>
<span>{{slot.data.join(' - ')}}</span>
</template>
</cpn>
<cpn>
<template slot-scope="slot">
<!--<span v-for="item in slot.data">{{item}} * </span>-->
<span>{{slot.data.join(' * ')}}</span>
</template>
</cpn>
<!--<cpn></cpn>-->
</div>
<!-- 子组件 template -->
<template id="cpn">
<div>
<!-- 作用域插槽要求,在slot上面绑定数据 -->
<slot :data="pLanguages">
<ul>
<li v-for="item in pLanguages">{{item}}</li>
</ul>
</slot>
<hr>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn',
data() {
return {
pLanguages: ['JavaScript', 'C++', 'Java', 'C#', 'Python', 'Go', 'Swift']
}
}
}
}
})
</script>
vue2.6之后写法:
<div id="app">
<!-- 默认 -->
<h4>默认</h4>
<cpn></cpn>
<hr>
<h4>替换样式</h4>
<cpn>
<!-- 具名插槽和作用域插槽混用 -->
<template v-slot:slot1='props1'>
<!--
<span>
{{props1}}
</span> -->
<span>{{props1.data1.join('-')}}</span>
<h3>
{{props1.msg}}
</h3>
</template>
<template v-slot:slot2="props2">
<h2 style="color: red;">
{{props2.data2}}
</h2>
</template>
</cpn>
<!--
当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。
这样我们就可以把 v-slot 直接用在组件上,但是不能和具名插槽混用
-->
<cpn v-slot="props3">
<template>
<h3 style="color: blue;">
{{props3.data3}}
</h3>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<!-- 可以传多个值 所有的值会包含在一个对象中 在父组件中v-slot=""中定义名字接收 -->
<slot :data1='movies' :msg='message' name='slot1'>
<ul>
<li v-for="(item, index) in movies" :key="index">
{{item}}
</li>
</ul>
</slot>
<slot :data2='name' name='slot2'>
{{name}}
</slot>
<slot :data3='defult'>默认插槽</slot>
</div>
</template>
<!-- 需要重新引入一个vue2.6之后的版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
movies: ['战狼', '鬼吹灯', '盗墓笔记'],
message: '你好呀',
name: 'yangyanyan',
defult: '我是默认的数据'
}
},
}
const app = new Vue({
el: '#app',
data: {},
components: {
cpn
}
})
</script>