vue之组件与通信
目录
组件化开发基础
组件是什么?有什么用
扩展 HTML 元素,封装可重用的代码,目的是复用
-例如:有一个轮播,可以在很多页面中使用,一个轮播有js,css,html
-组件把js,css,html放到一起,有逻辑,有样式,有html
注意事项
1 自定义组件需要有一个root element,一般包裹在一个div中
2 父子组件的data是无法共享
3 组件可以有data,methods,computed....,但是data 必须是一个函数
组件注册方式
1 全局组件
Vue.component('组件名', {
template:`html代码`,
// 这里的data必须是方法所以要加() 在return里写变量
data(){
return {
变量:值
}
},
methods:{
方法(){}
}
}
},)
2 局部组件 在Vue对象内 和el、data、methods同级写components
components:{
'组件名':{
template:`html代码`,
data(){
return {
变量:值
}
},
methods:{
方法(){}
}
}
},
}
局部组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<Top></Top> // 在这里调用局部组件
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<Bottom></Bottom>
</div>
</body>
<script>
var vm = new Vue({
// el data methods watch computed 8个生命周期函数
el: '#app',
data: {},
// 定义再这里面的叫局部组件,只能再局部使用,只能再id为app的标签内使用
components: {
'Top': {
template: `<div><h1 style="background: pink;font-size: 60px;text-align: center">{{name}}</h1><hr><button @click="handleC">点我看美女</button>
</div>`,
data() {
return {
name: "我是头部"
}
},
methods: {
handleC() {
alert('美女')
}
},
},
'Bottom': {
template: `<div>
<hr><h1 style="background: green;font-size: 60px;text-align: center">{{name}</h1>
</div>`,
data() {
return {
name: "我是尾部"
}
},
},
},
})
</script>
</html>
全局组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<top></top> // 在这里调用全局组件
</div>
</body>
<script>
// 定义全局组件--->任意位置都可以用
Vue.component('top', {
template: `
<div>
<h1 style="background: pink;font-size: 60px;text-align: center">{{name}}</h1>
<hr>
<button @click="handleC">点我看美女</button>
</div>
`,
data() {
return {
name: "我是头部"
}
},
methods: {
handleC() {
alert('美女')
}
},
},)
var vm = new Vue({
// el data methods watch computed 8个
el: '#app',
data: {},
})
</script>
</html>
组件通信之父传子(自定义属性)
通过自定义属性实现
步骤:
1.给组件自定义属性绑定一个父中定义的变量eg:
2.在定义组件内写props属性,对应一个数组,数组内包含组件自定义属性名eg: props:['fathername',]
3.这样组件(子)就可以使用Vue对象(父)内的变量啦,实现了通信.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div_id">
// 给组件自定义属性绑定一个父中的变量
<top :fathername="headName"></top>
<hr>
{{headName}}
<hr>
<input type="text" v-model="headName">
</div>
<script>
Vue.component('top', {
template:`
<div><h1 style="background-color: pink;font-size: 60px;text-align: center">{{fathername}}</h1>
</div>
`,
data(){
return {
name:'我是头部'
}
},
props:['fathername',]
},)
let vm = new Vue({
el:'#div_id',
data:{
headName:'哈哈',
},
})
</script>
</body>
</html>
组件通信之子传父(自定义事件)
通过自定义事件实现
步骤:
1.给组件绑定自定义事件对应一个函数eg: <top @myevent="handleRev">
2.在另一个标签上绑定事件通过this.$emit('自定义事件名', 要传递的参数...)来触发其对应函数的执行
3.这样就在Vue对象中获得了组件传来的参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div_id">
<top @myevent="handleRev"></top>
<hr>
接收到的参数:{{revText}}
</div>
<script>
Vue.component('top', {
template:`
<div><h1 style="background-color: pink;font-size: 60px;text-align: center">{{name}}</h1>
<input type="text" v-model="text"><button @click="handleSend">点我传数据</button>
</div>`,
data(){
return {
name:'我是头部',
text:''
}
},
methods:{
// 触发绑定在该组件上的事件,myevent,然后传参.父组件中会执行事件对应的函数handelRecv
handleSend(){
this.$emit('myevent', this.text)
}
}
},)
let vm = new Vue({
el:'#div_id',
data:{
revText:'',
},
methods:{
handleRev(text){
// 接收一个参数,赋值给父组件的revText
this.revText = text
}
}
})
</script>
</body>
</html>
ref属性实现双向通信
ref放在标签上,拿到的是标签对象,可以点属性拿到对应的值
ref放在组件上,拿到的是组件对象,可以点属性拿到对应的值
通过这种方式实现子传父(this.$refs.mychild.text)
通过这种方式实现父传子(调用子组件方法传参数)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
<!-- 通过ref,获取input的值-->
<input type="text" ref="mytext">
<button @click="handleClick">点我</button>
<child ref="mychild"></child>
</div>
</body>
<script>
Vue.component('child',{
template:`<div>child</div>`,
data(){
return {
text:'子组件数据'
}
},
methods:{
add(){
console.log('子组件的add方法')
}
}
})
var vm = new Vue({
el: '#box',
data: {
},
methods: {
handleClick() {
console.log(this)
//this.$refs.mytext 获取到input控件,取出value值
console.log(this.$refs.mytext.value)
console.log(this.$refs.mychild.text)
// this.$refs.mychild.add()
this.$refs.mychild.add('传递参数')
}
}
})
</script>
</html>
动态组件和keep-alive
keep-alive:组件不销毁(页面切换之前输入的数据会保留)
component:有个is属性,指定显示的组件是哪个
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div_id">
<ul>
<li @click="handleC('index')">首页</li>
<li @click="handleC('order')">订单</li>
<li @click="handleC('good')">商品</li>
</ul>
<keep-alive>
<component :is="who"></component>
</keep-alive>
</div>
<script>
Vue.component('index', {
template: `
<div><h1>我是首页</h1>
</div>`,
},)
Vue.component('order', {
template: `
<div><h1>我是订单</h1><input type="text">
</div>`,
},)
Vue.component('good', {
template: `
<div><h1>我是商品</h1>
</div>`,
},)
let vm = new Vue({
el: '#div_id',
data: {
who: ''
},
methods: {
handleC(func) {
this.who = func
}
}
})
</script>
</body>
</html>
插槽
插槽就是可以在组件标签中间插入标签或内容,比如我自定义一个index标签,那么直接写
基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
<!-- 不使用插槽写的aaa不会显示,使用就会显示-->
<child1>aaa</child1>
</div>
</body>
<script>
var bus = new Vue() //new一个vue的实例,就是中央事件总线
Vue.component('child1', {
template: `<div>
首页
<slot></slot>
</div>`,
})
var vm = new Vue({
el: '#box',
})
</script>
</html>
插槽应用场景1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
<!-- 写了一个轮播组件,用户想轮播什么就放什么-->
<swiper>
<p v-for="data in 4">{{data}}</p>
</swiper>
<swiper>
<img :src="data" v-for="data in 5">
</swiper>
</div>
</body>
<script>
var bus = new Vue() //new一个vue的实例,就是中央事件总线
Vue.component('swiper', {
template: `<div>
<slot></slot>
</div>`,
})
var vm = new Vue({
el: '#box',
})
</script>
</html>
插槽应用场景2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
<!--通过插槽实现在一个组件中控制另一个组件的显示隐藏-->
<navbar> <button @click="isShow=!isShow">点我显示隐藏</button></navbar>
<swiper v-if="isShow"></swiper>
</div>
</body>
<script>
Vue.component('navbar', {
template: `<div>
navbar
<slot></slot>
</div>`,
})
Vue.component('swiper', {
template: `<div>
<p>111</p>
<p>222</p>
<p>333</p>
</div>`,
})
var vm = new Vue({
el: '#box',
data:{
isShow:true
}
})
</script>
</html>
具名插槽
具名插槽的意思就是给插槽起名字,然后使用的时候把指定的标签或内容插到指定的插槽中,这样可以指定不同的插槽使用不同的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div_id">
<index>
<p slot="a">我来替换插槽a</p>
<div slot="b">我来替换插槽b</div>
</index>
</div>
<script>
Vue.component('index', {
template: `
<div>
<slot name="a"></slot>
<h1>我是首页</h1>
<slot name="b"></slot>
</div>`,
},)
let vm = new Vue({
el: '#div_id',
data: {
},
})
</script>
</body>
</html>