一、组件
那么首先,什么是组件呢:
我们在开发的时候把一些可以复用的内容封装成组件
在vue中定义组件有两种常见的形式:
1.全局组件
2.局部组件
1.全局组件
Vue.component('', { template })
// 全局组件定义之后可以直接使用不需要注册
例:
<hello></hello>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('hello', {
template: `
<div>
<h1>Hello 小明</h1>
<p>小明是个万人迷,万物皆可小明</p>
</div>
`,
})
</script>
结果如下方图片
2.局部组件
const c = { template: `` }
// 局部组件在使用的时候需要注册
// components 属性进行注册
例:
<div id="app">
<count></count>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
// 局部组件
var Counter = {
template: `
<div class="counter">
<h1>我是一个局部组件</h1>
</div>
`,
}
var app = new Vue({
el: "#app",
components: {
count: Counter,
}
})
</script>
结果如下方图片
3.自定义组件
定义局部组件, 就是一个对象,此对象包含有一些特殊的属性。
// template 模板内容
// data 组件的数据, data必须是一个function,此function有一个对象
做为返回值
// methods 方法
// computed 计算属性
// ... 其他的等等等等,所有vue中可以使用的方法或者属性都可以在组件
内部使用
// 定义的组件必须只有一个根节点
二、传值
1.父传子
通过props属性
例:
<div id="app">
<count :step="2"></count> <!-- : 表示一个对象 -->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
// 局部组件
var Counter = {
template: `
<div class="counter">
<h1>我是一个计数器:{{count}}</h1>
<p>步长:{{step}}</P>
<button @click="count+=step">点击</button>
</div>
`,
// props: ['step'],
// 或者如下,以对象的形式设置属性,可以对传递的数据做验证
//props是属性传值 这个是父组件向子组件传,通过属性来传
props:{
step:Number,
}
data() {
return {
count: 0
}
}
}
var app = new Vue({
el: "#app",
components: {
count: Counter,
}
})
</script>
结果如下方图片:
每次点击增加2
2.子传父
通过事件派发
<div id="app">
<p style="color: darkred">从计数器中传递出来的数据:{{fromCount}}</p>
<p>{{stepValue}}</p>
<input type="range" max="10" min="0" step="1" v-model.number="stepValue">
<count @countchanged="countCHandel" :step="stepValue"></count> <!-- : 表示一个对象 -->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
// 局部组件
var Counter = {
template: `
<div class="counter">
<h1>我是一个计数器:{{count}}</h1>
<p>步长:{{step}}</P>
<button @click="addHandle">点击</button>
</div>
`,
//props: ['step'],
// 或者如下,以对象的形式设置属性,可以对传递的数据做验证
//props是属性传值 这个是父组件向子组件传,通过属性来传
props:{
step:Number,
},
data() {
return {
count: 0
}
},
methods: {
addHandle() {
this.count += this.step;
// 派发事件,谁派发事件,谁监听。Count组件派发,Count监听,所以@countchanged绑定在count上
this.$emit('countchanged', this.count)
},
}
}
var app = new Vue({
el: "#app",
components: {
count: Counter,
},
data: {
stepValue: 2,
fromCount: 0
},
methods: {
// 接收组件传递的数据
countCHandel(v) {
this.fromCount = v
}
}
})
</script>
结果图如下:
3.非相关组件传值
事件总线:解决非相关组件之间传值;
如图:导航组件和列表组件,点击购买,购物车后数字加1,
我们通过定义一个空白的对象 所有的事件派发和监听都在这个对象上进行。
const eventBus = new Vue();// 定义一个空白的vue实例用来做事件的转发。
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>非相关组件之间传值</title>
<style>
img {
width: 100px;
max-width: 100px;
}
.nav {
display: block;
width: 100%;
height: 80px;
}
.nav ul {
list-style: none;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.nav li {
color: deeppink;
margin: 0 3rem;
}
.product {
border: 0.01rem solid deeppink;
padding: 0.8rem;
margin: 0.5rem;
}
</style>
</head>
<body>
<!-- 事件总线 解决非相关组件之间传值 -->
<!-- 我们通过定义一个空白的对象 所有的事件派发和监听都在这个对象上进行 -->
<div id="app">
<!-- 顶部导航组件 -->
<navbar></navbar>
<!-- 商品列表组件 -->
<product v-for="(p,i) in list" :key="i" :product="p"></product>
</div>
<script src="./libs/vue.js"></script>
<script>
const eventBus = new Vue(); // 定义一个空白的vue实例用来做事件的转发
const navbar = {
template: `<div class="nav">
<ul>
<li>首页</li>
<li>商品列表</li>
<li>购物车({{cartCount}})</li>
<li>其他</li>
</ul>
</div>`,
created() {
eventBus.$on('buy-product', this.buyHandle);
},
methods: {
buyHandle(product) {
console.log(product);
this.cartCount += 1;
},
},
data() {
return {
cartCount: 0,
};
},
};
const product = {
template: `<div class="product">
<img :src="product.img"/>
<h5>{{product.name}}</h5>
<button @click="buyHandle(product)">购买</button>
</div>`,
props: ['product'],
methods: {
buyHandle(p) {
eventBus.$emit('buy-product', p);
},
},
};
const app = new Vue({
el: '#app',
components: {
product,
navbar,
},
data: {
list: [
{
img:
'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2002504746,179271572&fm=26&gp=0.jpg',
name: 'Nokia',
price: 200,
},
{
img:
'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=4162623679,2168960991&fm=26&gp=0.jpg',
name: 'IPhone',
price: 300,
},
{
img:
'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=591403396,1405019377&fm=26&gp=0.jpg',
name: 'HuaWei',
price: 400,
},
],
},
});
</script>
</body>
</html>