组件
- 复用
- 隔离(拆分)
全局组件
可以在整项目中不注册直接使用
定义 :Vue.component(名称,参数对象)
<script>
Vue.component("Count",{
template:`<div><button>按钮</button></div>`
})
new Vue({
el:"#app",
data:{}
})
</script>
使用
<div id="app">
<Count></Count>
</div>
局部组件
谁注册谁使用
- 定义:var CounterItem={template:"",methods,…}
- 注册:components:{CounterItem}
- 使用:
<counter-item ></counter-item>
或<Counter-Item></Counter-Item>
var CounterItem={
template:`<div><button @dblclick="say()" @click="num++">{{num}}</button></div>`,
data(){return {num:1}},
props:["count"],
methods:{
say(){alert("666")}
},
}
new Vue({
el:"#app",
data:{},
components:{CounterItem}
})
</script>
<div id="app">
<counter-item ></counter-item>
<Counter-Item></Counter-Item>
</div>
数据传递 父传子
传入数据
<counter-item :count="2" ></counter-item>
接收数据
props:["count"]
或props:{type:Number,default:1}
props验证默认值:
- props:{type:Number,default:1}
- type:Number String Object Array Boolean
组件的单向数据流
- vue提倡单向数据流 :父传递的组件的数据应该是只读的
- 想修改父组件传递过来的数据(以父组件的传递过来的数据作为当前组件data初始值)
传参初始化
props:["count"],
created(){this.num=this.count} //可以修改num值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<counter-item v-for="(item,index) in list" :key="index" :count="item"></counter-item>
<!-- 01参数 传入属性给组件 -->
<hr/>
<Counter-Item></Counter-Item>
</div>
</body>
<script>
var CounterItem={
template:`<div><button @dblclick="say()" @click="num++">{{num}}</button></div>`,
data(){return {num:1}},
// props:["count"],
props:{"count":{type:Number,default:20}},
// 通过props 接收数据
methods:{
say(){alert("666")}
},
create(){
this.num=this.count
//count传过来的数据是num的初始值
}
}
new Vue({
el:"#app",
data:{
list:[1,2,3,4,5]
},
components:{CounterItem}
})
</script>
</html>
子向父传参
this.$emit("事件名",this.num)
//向父组件发送checknum事件,值为this.num
<Step @checknum="nuber($event)"></Step>
接收数据
小案例—步进器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/vue.js"></script>
<style>
.step{display: inline-block;}
.step input[type="text"]{width: 30px; text-align: center;}
</style>
</head>
<body>
<div id="app">
<Step></Step>
<Step :min="30" :max="100" :step="10" :count="40" @checknum="nuber($event)"></Step>
<h1 v-if="number">{{number}}</h1>
</div>
</body>
<script>
var Step={
template:`<div class="step">
<button :disabled="num<=min" @click="cal(-1)">-</button>
<input type="text" v-model="num" @input="check()" >
<button :disabled="num>=max" @click="cal(1)">+</button></div>`,
data(){return{num:1}},
props:{
"count":{type:Number,default:1},
"min":{type:Number,default:1},
"max":{type:Number,default:999},
"step":{type:Number,default:1},
},
created(){
this.num=this.count
},
methods:{
check(){
if(this.num<=this.min){this.num=this.min}
if(this.num>=this.max){this.num=this.max}
this.$emit("checknum",this.num)
//向父组件发送checknum事件,值为this.num
},
cal(type){
this.num+=this.step*type;
this.check();
}
}
}
new Vue({
el:"#app",
data:{
number:null
},
components:{Step},
methods:{
nuber(e){
this.number=e
}
}
})
</script>
</html>
插槽
定义:
<slot></slot>
使用:
<组件><p>嵌入内容</p><组件>
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/vue.js"></script>
<style>
.Parent{border: 1px solid #eee;margin: 10px; padding: 10px;}
</style>
</head>
<body>
<div id="app">
<Parent>
<h1>我是嵌套内容1</h1>
<Parent>
<p>我是嵌套内容2</p>
<Parent>
<p>我是嵌套内容3</p>
</Parent>
</Parent>
</Parent>
</div>
</body>
<script>
var Parent={
template:` <div class="Parent"><p>parent组件</p><slot></slot></div>`
}
new Vue({
el:"#app",
data:{
},
components:{Parent}
})
</script>
</html>
具名插槽
定义:
<slot name="插槽名"></slot>
使用:
<div slot="插槽名"><p>我是标题</p></div>
小案例–弹出框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/vue.js"></script>
<style>
*{ margin: 0;padding: 0;}
body{ padding: 50px;}
.modal{
background-color: rgba(0,0,0,.3);
position: absolute;
z-index: 10000;
height: 100vh;
width: 100%;
left:0;
top: 0;
display: flex;
justify-content: center;
align-items: center;
}
.modal-content{
width: 400px;
height: 300px;
background-color: #fff;
display: flex;
flex-direction: column;
}
.modal-title{
line-height: 44px;
background-color: #fafafa;
display: flex;
justify-content: space-between;
padding-left: 15px;
}
.close{ width: 44px; text-align: center; color:coral;cursor: pointer;}
.modal-foot{ height: 44px; padding: 0 15px; text-align: right;}
.modal-body{flex:1}
</style>
</head>
<body>
<div id="app">
<button @click="flag=true">弹出</button>
<Model title="你笑起来真好看" :visible="flag" @close="flag=$event">
<div>
<p>用户名:<input type="text"></p>
<p>密码:<input type="text"></p>
</div>
<div slot="foot"><button @click="flag=false">确定</button><button @click="flag=false">取消</button></div>
<div slot="title"><p>我是标题</p></div>
</Model>
</div>
</body>
<script>
var Model={
template:`
<div class="modal" v-if="visible">
<div class="modal-content">
<div class="modal-title">
<div class="title" v-if="$slots.title">
<slot name="title"></slot>
</div>
<div class="title" v-else>{{title}}</div>
<div class="close" @click="$emit('close',false)">x</div>
</div>
<div class="modal-body">
<slot></slot>
</div>
<div class="modal-foot" v-if="$slots.foot">
<slot name="foot"></slot>
</div>
<div class="modal-foot" v-else>
<button @click="$emit('close',false)">确定</button>
</div>
</div>
</div>
`,
props:{
title:{type:String,default:""},
visible:{type:Boolean,default:false},
}
}
new Vue({
el:"#app",
data:{
flag:false
},
components:{Model}
})
</script>
</html>
$slots.foot:
所有插槽列表下名字为foot的插槽
$emit 向父组件传递信息
属性.sync修饰符
- :visible.sync=“flag”
- 组件中:
<div v-if="visible"><button @click="$emit('update:visible',false)"></button></div>
props:{visible:{type:Boolean,default:false}}
组价传参-复用-小案例-列表
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<Inp @adds="list.unshift({done:false,title:$event})"></Inp>
<List :list="list" @del="delHd($event)"></List>
</div>
</body>
<script>
var Inp={
template:`
<div>
<input type="text" v-model="temp" @keyup.enter="enterHd()">
</div>`,
data(){return{
temp:"",
}},
methods:{
enterHd(){
this.$emit("adds",this.temp);
this.temp=''
}
},
}
var Item={
template:`
<div>
<input type="checkbox" :checked="item.done">
{{item.title}}
<button @click="$emit('del',item)">删除</button>
</div>`,
props:{item:{type:Object,defaule:{}}}
}
var List={
template:` <div>
<Item v-for="item in list"
:key="item.title"
:item="item"
@del="$emit('del',$event)"
></Item>
</div>`,
props:{list:{type:Array,default:[]}},
components:{Item}
}
new Vue({
el:"#app",
data:{
list:[
{done:true,title:"吃饭"},
{done:true,title:"睡觉"},
{done:true,title:"打豆豆"},
]
},
methods:{
delHd(item){
var ind=this.list.indexOf(item)
this.list.splice(ind,1)
}
},
components:{Inp,List}
})
</script>
</html>