使用
-
创建组件构造器
Vue.extend()
-
注册组件
Vue.component()
-
使用组件
<div id="app">
<!-- 3.使用组件(必须已经被Vue托管) -->
<Mycpn></Mycpn>
</div>
<script type="text/javascript">
// 1.创建组件构造器
const cpnC = Vue.extend({
template:`
<div>
<h2>我是标题二</h2>
<p>我是段落</p>
<p>我是段落</p>
</div>
`
});
// 2.注册组件(全局) 对Vue对象托管的元素生效
//Vue.component('my-cpn',cpnC); 标签名最多支持首字母大写,不能使用驼峰命名法
const app = new Vue({
el:'#app',
data:{
},
//2.注册组件(局部) 只对被该Vue对象托管的元素生效
components:{
//标签名:组件构造器
Mycpn:cpnC
}
});
</script>
</script>
父组件子组件
<div id="app">
<cpn></cpn>
</div>
<script type="text/javascript">
const cpnC1 = Vue.extend({
template:`
<div>
<h2>我是子</h2>
<p>我是段落</p>
<p>我是段落</p>
</div>
`
});
const cpnC2 = Vue.extend({
template:`
<div>
<h2>我是父</h2>
<p>我是段落</p>
<p>我是段落</p>
<cpn1/>
</div>
`,
components:{
cpn1:cpnC1//在哪里注册,只能在哪里使用
}
});
const app = new Vue({
el:'#app',
data:{
},
components:{
cpn:cpnC2
}
});
</script>
语法糖
//无需创建组件构造器
Vue.component('cpn',{
template:`
<div>
<h2>我是子</h2>
<p>我是段落</p>
<p>我是段落</p>
</div>
`
})
const app = new Vue({
el:'#app',
data:{
},
components:{
cpn:{
template:`
<div>
<h2>我是父</h2>
<p>我是段落</p>
<p>我是段落</p>
<cpn1/>
</div>
`
}
}
});
模板的分离写法
<div id="app">
<cpn></cpn>
</div>
<template id="tpl">
<div>
<h2>我是子</h2>
<p>我是段落</p>
<p>我是段落</p>
</div>
</template>
<script type="text/javascript">
const cpnC1 = Vue.extend({
template:'#tpl'
});
// 2.注册组件(全局)
Vue.component('cpn',cpnC1);
const app = new Vue({
el:'#app',
data:{
}
});
</script>
<div id="app">
<cpn></cpn>
</div>
<script type="text/x-template" id="tpl">
<div>
<h2>我是子</h2>
<p>我是段落</p>
<p>我是段落</p>
</div>
</script>
<script type="text/javascript">
const cpnC1 = Vue.extend({
template:'#tpl'
});
// 2.注册组件(全局)
Vue.component('cpn',cpnC1);
const app = new Vue({
el:'#app',
data:{
}
});
</script>
组件中的数据存放
<div id="app">
<cpn></cpn>
</div>
<template id="tpl">
<div>
<h2>我是{{who}}</h2>
<p>我是段落</p>
<p>我是段落</p>
</div>
</template>
<script type="text/javascript">
const cpnC1 = Vue.extend({
template:'#tpl',
//组件不能访问Vue实例中的data
data(){//必须是个函数形式而且名为data,为了多次使用的实例可以有独立的data
return {//返回一个对象
who:'王灿'
}
}
});
Vue.component('cpn',cpnC1);
const app = new Vue({
el:'#app',
data:{
}
});
</script>
父子组件之间的通信
- 父——>子:
props
属性 - 子——>父:
$emit Events
父——>子
<div id="app">
<father></father>
</div>
<template id="father">
<div>
<son :cmovies='movies' :cnames='names'></son>
<!-- 必须使用v-bind,不然则会把‘movies’这个字符串传入下层 -->
</div>
</template>
<template id="son">
<ul>
<li v-for="item in cmovies">{{item}}</li>
<li v-for="item in cnames">{{item}}</li>
</ul>
</template>
<script type="text/javascript">
Vue.component('father',{
template:'#father',
data(){
return{
movies:['asd','dsa'],
names:['xxx','zzzz']
}
},
components:{
'son':{
template:'#son',
props:['cmovies','cnames']//当作变量名解析,写在子组件中
}
}
});
const app = new Vue({
el:'#app',
data:{
}
});
</script>
props属性形式
props:['asd','asdd'];//可以是数组
props:{//最好是对象
//1.类型限制
cmovies:Array,
cnames:String,
//2.提供默认值
cmovies:{
type:Array,//可以是自定义类型
default:['asd','asdd']//类型为数组或对象时,版本不同,可能这种不行,酌情选择
default(){
return ['asd','asdd']
}
required:true//使用该子组件必须传值
}
cMovies{}//props属性名若是驼峰命名法
//则v-bind绑定属性时,不能使用cMovies,而要使用c-movies 驼峰要变为-小写
}
子——>父
<div id="app">
<father ></father>
</div>
<template id="father">
<div>
<son @btnclick='myclick'></son>
<!-- 2.使用子组件发射的函数=自定义方法 -->
</div>
</template>
<template id="son">
<ul>
<button v-for="item in sorts" @click='itemclick(item)'>
{{item}}
</button>
</ul>
</template>
<script type="text/javascript">
Vue.component('father',{
template:'#father',
data(){
return{
}
},
methods:{
myclick(item){//3.自定义方法中,使用子组件的数据
console.log(item);
}
},
components:{
'son':{
template:'#son',
data(){
return{
sorts:['家电','数码','母婴','虚拟']
}
},
methods:{
itemclick(item){
this.$emit('btnclick',item)
// 1.在事件函数中使用this.$emit('方法名',参数)发射函数
}
}
}
}
});
const app = new Vue({
el:'#app',
data:{
}
});
父子访问
父访问子
- 使用
$children
访问子组件(不推荐使用) - 使用
$refs
访问子组件
<div id="app">
<son></son>
<son></son>
<son></son>
<son ref='whatever'></son>
<!-- 设置该属性后,就可以从$refs中访问了 -->
<button @click='btnClick'>访问子</button>
</div>
<template id="son">
<div>
我是son
</div>
</template>
<script type="text/javascript">
var app = new Vue({
el:'#app',
data:{
message:'你好'
},
methods:{
btnClick(){
// console.log(this.$children);
// this.$children[0].showMessage();
// 开发中,极少使用$children,一般用来获取所有子组件
console.log(this.$refs.whatever);
// 绝大部分使用$refs来访问我们需要的子组件
}
},
components:{
son:{
template:'#son',
methods:{
showMessage(){
console.log('我是子组件的message');
}
},
}
}
});
</script>
子访问父
- 使用
$parent
访问父组件 - 使用
$root
访问根组件(顶层Vue
实例)
<div id="app">
<son></son>
</div>
<template id="son">
<div style="background-color: #00BFFF;display: inline-block;">
<h2>我是子组件</h2>
<button @click="btnClick">访问父</button>
<!-- 这里父组件为顶层Vue实例 也就是$root-->
<grandson></grandson>
</div>
</template>
<template id="grandson">
<div style="background-color: #19692C;display: inline-block;">
<h2>我是孙子组件</h2>
<button @click="visitParent">访问父</button>
<button @click="visitRoot">访问根</button>
</div>
</template>
<script type="text/javascript">
var app = new Vue({
el:'#app',
data:{
message:'你好'
},
methods:{
},
components:{
son:{
template:'#son',
methods:{
btnClick(){
console.log(this.$parent);
}
},
components:{
grandson:{
template:'#grandson',
methods:{
visitParent(){
console.log(this.$parent);
// 很少使用子访问父,Vue组件化的意义在于可复用性,每个使用场景的父组件不一定相同,下同
},
visitRoot(){
console.log(this.$root);
}
}
}
}
}
}
});
</script>
插槽
基本使用
<div id="app">
<son></son>
<son><span>文字</span></son>
<son><button>按钮</button></son>
<!-- 双标签内部的元素会被全部替换到slot标签的位置 -->
<!-- 若没有元素,则使用slot标签中的默认元素 -->
</div>
<template id="son">
<div>
<h2>我是子组件</h2>
<slot><i>我是默认内容</i></slot>
<!-- slot插槽,预留一个位置放不同的内容 -->
<!-- 不是具名插槽会全部被替换为相同内容-->
</div>
</template>
<script type="text/javascript">
var app = new Vue({
el:'#app',
components:{
son:{
template:'#son'
}
}
});
</script>
</body>
具名插槽的使用
<div id="app">
<son>
<span slot="left">左边的</span>
<span slot="right">右边的</span>
<!-- 会替换slot属性指定的name -->
</son>
</div>
<template id="son">
<div>
<slot name="left"><span>left</span></slot>
<slot>我没有具名,我不会被替换,</slot>
<slot name="right"><span>right</span></slot>
</div>
</template>
<script type="text/javascript">
var app = new Vue({
el:'#app',
components:{
son:{
template:'#son'
}
}
});
</script>
变量作用域
<div id="app">
<cpn v-show="isShow"></cpn>
<!-- 此处cpn在Vue看来和普通标签没区别,在使用isShow时,会查找当前实例的data,这里的当前实例为app -->
</div>
<template id="cpn">
<div>
<h2>我是标题</h2>
<p v-show="isShow">我是内容</p>
<!-- 这里的当前实例为cpn -->
<!-- 总结:在哪里写的用哪里的 -->
</div>
</template>
<script type="text/javascript">
const app = new Vue({
el:'#app',
data:{
isShow:true
},
components:{
cpn:{
template:'#cpn',
data(){
return{
isShow:false
}
}
}
}
})
</script>
作用域插槽
<!-- 目的:我们希望第二个子组件不按照slot默认行为来渲染,但是又需要拿到子组件的数据 -->
<div id="app">
<cpn></cpn>
<!-- 这里的x随便命名 -->
<cpn v-slot='x'>
<span>{{x.data.join('——')}}</span>
</cpn>
<!-- -->
<cpn></cpn>
</div>
<template id="cpn">
<div>
<!-- 这里的data随便命名 -->
<slot :data='language'>
<ul>
<li v-for="i in language">{{i}}</li>
</ul>
</slot>
</div>
</template>
<script type="text/javascript">
const app = new Vue({
el:'#app',
components:{
cpn:{
template:'#cpn',
data(){
return{
language:['C','Python','Javascript','Java','C#']
}
}
}
}
})
</script>