vue组件化
任何应用都可以抽象成一颗组件树
组件注册过程
- 创建组件构造器 Vue.extend 要传一个对象,一个模板
- 注册组件 Vue.component
- 使用组件
//1.第一种方法
//vue cli 脚手架构造vue项目 vue构造vue
//必须得放在实例中,比如<div>标签下,否则无用,而且得是vue实例
//全局组件
<div id="app">
<my-cpn></my-cpn>
</div>
<script type="text/javascript">
//1.构造
const cpnC=Vue.extend({
template:`<h1>Hello World</h1>`
})
//2.注册 全剧注册
//Vue.component(组件名,组件构造器)
Vue.component('my-cpn',cpnC);
const app=new Vue({
el:"#app",
</script>
全局组件
全局都可以使用
局部组件
局部注册
<div id="app">
<my-cpn></my-cpn>
<!-- <myCpn2></myCpn2> --><!--错误-->
<my-cpn2></my-cpn2>
</div>
<script type="text/javascript">
//1.构造 全局组件
const cpnC=Vue.extend({
template:`<h1>Hello World</h1>`
})
//2.注册
//Vue.component(组件名,组件构造器) 注册方式是全局注册
Vue.component('my-cpn',cpnC);
const app=new Vue({
el:"#app",
components:{
//cpn是注册组件的标签名,不能携带-,否则报错,可以使用驼峰命名,然后标签名用-链接
myCpn2:cpnC
}
})
</script>
父子组件
<div id="app">
<cpn2></cpn2>
<!-- <cpn1></cpn1> --><!--错误,要么全局,要么在实例中-->
</div>
<script type="text/javascript">
//1.构造 第一个
const cpnC1=Vue.extend({
template:`<h1>我是子组件</h1>`
})
//2.构造第二个
const cpnC2=Vue.extend({
template:`
<h1>我是父组件</h1>
<cpn1></cpn1>
`,
components:{
//cpnC2父组件,cpnC1子组件 本质来看vue也是一个父组件而且是顶层组件,root
//关键的父组件必须包含子组件,也就是不能让子组件并行和其她标签显示
/*
对的
template:`
<div>
<h1>我是父组件</h1>
<cpn1></cpn1>
</div>
`,
错的
template:`
<h1>我是父组件</h1>
<cpn1></cpn1>
`,
错误为 template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.
也就是说要有个根
*/
cpn1:cpnC1
}
})
const app=new Vue({
el:"#app",
components:{
//cpn是注册组件的标签名,不能携带-,否则报错,可以使用驼峰命名
cpn2:cpnC2
}
})
</script>
父子组件语法糖
全局组件
<div id="app">
<cpn1></cpn1>
</div>
<script type="text/javascript">
//1.
Vue.component('cpn1',{
template:`<div><h1>hello</h1></div>`
})
const app=new Vue({
el:"#app",
components:{
}
})
</script>
局部组件
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script type="text/javascript">
//1.全局
Vue.component('cpn1',{
template:`<div><h1>全局注册语法糖</h1></div>`
})
const app=new Vue({
el:"#app",
components:{
//局部
'cpn2':{
template:`<div><h1>局部注册语法糖</h1></div>`
}
}
})
</script>
组件模板抽离
一旦在模板中出现了很多的html将会很复杂
- 在script里写
- template标签里写
<body>
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script type="text/x-template" id="cpn">
<div>
<h1>
script type="text/x-template"
在这个标签里写
</h1>
</div>
</script>
<template id="cpn2">
<div>
<h1>
template
在这个标签里写
</h1>
</div>
</template>
<script type="text/javascript">
//1.全局
Vue.component('cpn1',{
template:"#cpn"
})
const app=new Vue({
el:"#app",
components:{
//局部
'cpn2':{
template:"#cpn2"
}
}
})
</script>
</body>
```
### 父子组件通信
* vue组件应该有自己保存数据的地方、
* 组件无法访问vue实例,假设即使可以访问,但是数据过多会臃肿
* 组件也可以传值,在component里传一个data,但不能是对象类型,要return,是一个函数,而且这个和vue很像
组件之间的属性与方法调用
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script type="text/x-template" id="cpn">
<div>
<h1>
script type="text/x-template"
在这个标签里写
{{msg1}}
计数器:{{counter}}
<button @click="counter++">+</button>
<!-- <button @click="add()">+</button> -->
<button @click="counter--">-</button>
</h1>
</div>
</script>
<template id="cpn2">
<div>
<h1>
template
在这个标签里写
{{msg2}}
</h1>
</div>
</template>
<script type="text/javascript">
//1.全局
Vue.component('cpn1',{
template:"#cpn",
data(){
//不能是类
return{
msg1:'abc',
counter:0
}
},
methods:{
add(){
this.counter++;
}
}
})
const app=new Vue({
el:"#app",
data:{
msg:"hhhh"
},
components:{
//局部
'cpn2':{
template:"#cpn2",
data(){
return{
msg2:"abc2"
}
}
}
}
})
</script>
父子组件传值
* 子组件注册时,定义props用来接收数据
* 子组件模板定义时,调用数据
* 父组件引用子组件,给他绑定参数,:
* props:可以传数组,也可以类
**父传子**
<div id="app">
<cpn1 :cmovies="movies" :cmsg="msg"></cpn1>
</div>
<script type="text/x-template" id="cpn">
<div>
<h1 v-for="c in cmovies">
{{c}}
</h1>
<h1>{{cmsg}}</h1>
</div>
</script>
<script type="text/javascript">
//父传子 props
const cpn={
template:"#cpn",
props:['cmovies','cmsg'],
data(){
return {}
}
};
//root组件
const app=new Vue({
el:"#app",
data:{
movies:['o1','zio','build'],
msg:"hello"
},
components:{
//局部
'cpn1':cpn
}
})
</script>
类传值
子传父
<div id="app">
<cpn1 @itemclick='cpnClick'></cpn1>
</div>
<script type="text/x-template" id="cpn">
<div>
<button v-for="(item,index) in categories" @click="btnClick(item)">
{{item.name}}
</button>
{{cl}}
</div>
</script>
<script type="text/javascript">
//子传父
const cpn={
template:"#cpn",
data(){
return {
categories:[
{id:'aaa',name:'热门推荐'},
{id:'bbb',name:'手机数码'},
{id:'ccc',name:'服装衣服'},
{id:'ddd',name:'电脑办公'}
],
cl:''
}
},
methods:{
btnClick(item){
//子组件发射事件,事件名字,参数
this.$emit('itemclick',item);
this.cl=item.name;
}
}
};
//root组件
const app=new Vue({
el:"#app",
data:{
},
methods:{
cpnClick(item){
console.log(item);
}
},
components:{
//局部
'cpn1':cpn
}
})
</script>
父子组件通信
watch
children-refs
父访问子
parent-root
子访问父
组件插槽solt
使用方法:<slot></slot>
此时调用子组件时,在组件标签里往下添加标签即可<cpn1 @itemclick='cpnClick'><button></button></cpn1>
同时也可以给插槽默认值:<slot><button></button></slot>
具名插槽
如何修改具体插槽,给插槽设置name,不同的不会替换,没有Name会替换,同理要提替换,只需组件调用插槽名字即可
//会显示按钮和左中右
<div id="app">
<cpn1 @itemclick='cpnClick'>
</cpn1>
</div>
<script type="text/x-template" id="cpn">
<div>
<button v-for="(item,index) in categories" @click="btnClick(item)">
{{item.name}}
</button>
{{cl}}
<!-- <slot><button></button></slot> -->
<slot name="left">leftt</slot>
<slot name="mid">zhong</slot>
<slot name="right">you</slot>
</div>
</script>
//显示标题太
<div id="app">
<cpn1 @itemclick='cpnClick'>
标题太
</cpn1>
</div>
<script type="text/x-template" id="cpn">
<div>
<button v-for="(item,index) in categories" @click="btnClick(item)">
{{item.name}}
</button>
{{cl}}
<!-- <slot><button></button></slot> -->
<slot >leftt</slot>
<slot>zhong</slot>
<slot >you</slot>
</div>
</script>
//显示左中右
<div id="app">
<cpn1 @itemclick='cpnClick'>
标题太
</cpn1>
</div>
<script type="text/x-template" id="cpn">
<div>
<button v-for="(item,index) in categories" @click="btnClick(item)">
{{item.name}}
</button>
{{cl}}
<!-- <slot><button></button></slot> -->
<slot name="left">leftt</slot>
<slot name="mid">zhong</slot>
<slot name="right">you</slot>
</div>
//标题 zhong you,记住不能直接绑在组件标签里
<div id="app">
<cpn1 @itemclick='cpnClick'>
<span slot="left">标题</span>
</cpn1>
</div>
<script type="text/x-template" id="cpn">
<div>
<button v-for="(item,index) in categories" @click="btnClick(item)">
{{item.name}}
</button>
{{cl}}
<!-- <slot><button></button></slot> -->
<slot name="left">leftt</slot>
<slot name="mid">zhong</slot>
<slot name="right">you</slot>
</div>
</script>
编译作用域
作用域插槽,父组件替换插槽的标签,但是内容由子组件来提供
commonJS
let {} require()