组件化开发思想
标准、分治、重用、组合
Web Components通过创建封装好功能的定制元素来实现
组件注册
1.全局组件注册
语法:
Vue.component(组件名称,{
data:组件数据,
template:组件模板内容
})
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('button-counter', {
data: function() {
return {
count: 0
}
},
template: '<button v-on:click="handle">点击了{{count}}次</button>',
methods: {
handle: function() {
this.count += 2;
}
}
})
var vm = new Vue({
el: '#app',
data: {
}
});
</script>
</body>
</html>
- 组件的数据是独立的,相互之间不受影响
- data必须是一个函数
- 组件模板内容必须是单个根元素,可嵌套
- 组件模板内容可以是模板字符串
- 使用驼峰式命名组件只能使用在字符串模板中
2.局部组件注册
语法:
var ComponentA={}
var ComponentB={}
var ComponentC={}
new Vue({
el:'#app'
components:{
'component-a':ComponentA,
'component-b':ComponentB
'component-c':ComponentC,
}
})
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>
<script src="./vue.js"></script>
<script>
var ComponentA = {
data: function() {
return {
msg: 'A'
}
},
template: '<h1>{{msg}}</h1>'
};
var ComponentB = {
data: function() {
return {
msg: 'B'
}
},
template: '<h1>{{msg}}</h1>'
};
var ComponentC = {
data: function() {
return {
msg: 'C'
}
},
template: '<h1>{{msg}}</h1>'
};
var vm = new Vue({
el: '#app',
data: {
},
components: {
'component-a': ComponentA,
'component-b': ComponentB,
'component-c': ComponentC
}
});
</script>
</body>
</html>
局部组件只能在注册它的父组件中使用
Vue调试工具
1.下载(Chrome)
下载地址:
https://chrome.zzzmh.cn/info?token=nhdogjmejiglipccpnnnanhbledajbpd
2.使用
先解压,然后在chrome浏览器地址栏中输入chrome://extensions/
然后将解压后的CRX文件拖进来,添加插件
成功界面如下:
如果vue使用不了,则打开详细信息,打开“允许访问文件网址”按钮:
然后就能在调试栏中看到vue:
这样就可以开始使用了
组件间数据交互
父组件向子组件传值
1.组件内部通过props接收传递过来的值
语法:
Vue.component('menu-item',{
props:['title'],
template:'<div>{{title}}</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>
</head>
<body>
<div id="app">
<menu-item :title="title" :content="content"></menu-item>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('menu-item', {
props: ['title', 'content'],
template: '<div>{{title}},{{content}}</div>'
});
var vm = new Vue({
el: "#app",
data: {
title: '我是父组件传递的title',
content: '我是父组件传递的content'
}
})
</script>
</body>
</html>
当props数值类型为对象数组时:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<menu-item :arr_obj='arr_obj'></menu-item>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('menu-item', {
props: ['arr_obj'],
template: `
<div>
<p :key='index' v-for='(item,index) in arr_obj'>
<span>{{item.name}}</span>
<span>{{item.age}}</span>
</p>
</div>
`
});
var vm = new Vue({
el: "#app",
data: {
arr_obj: [{
name: '大花',
age: 18
}, {
name: '小花',
age: 17
}]
}
});
</script>
</body>
</html>
一些注意:
props中使用驼峰形式,模板中需要使用短横线的形式
props传递数据是单向数据流
子组件向父组件传值
1.子组件通过自定义事件向父组件传递信息
<button @click='$emit("enlarge-text",5)'>扩大字体</button>
2.父组件监听子组件的事件
<menu-item @enlarge-text='fontsize+=$event'></menu-item>
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<p :style='{fontSize:fontSize+"px"}'>我是父组件</p>
<menu-item @enlarge-text='handle($event)'></menu-item>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('menu-item', {
template: `
<div>
<button @click='$emit("enlarge-text",5)'>增大字号</button>
</div>
`
});
var vm = new Vue({
el: '#app',
data: {
fontSize: 10
},
methods: {
handle: function(value) {
this.fontSize += value;
}
}
});
</script>
</body>
</html>
非父子组件传值
1.单独的事件中心管理组件间的通信
var eventHub=new Vue();
2.监听事件与销毁事件
//监听事件
eventHub.$on('add-todo',addtodo)
//销毁事件
eventHub.$off('add-todo')
3.触发事件
//触发事件
eventHub.$emit('add-todo',id)
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<button @click='handle'>销毁事件</button>
<test-first></test-first>
<test-second></test-second>
</div>
<script src="./vue.js"></script>
<script>
//事件中心
var eventHub = new Vue();
Vue.component('test-first', {
data: function() {
return {
num: 0
}
},
template: `
<div>
<div>first:{{num}}</div>
<div>
<button @click='handle'>first</button>
</div>
</div>
`,
methods: {
handle: function() {
//触发兄弟组件的事件
eventHub.$emit('second-event', 1)
}
},
mounted: function() {
//监听事件
eventHub.$on('first-event', (value) => {
this.num += value;
})
}
});
Vue.component('test-second', {
data: function() {
return {
num: 0
}
},
template: `
<div>
<div>second:{{num}}</div>
<div>
<button @click='handle'>second</button>
</div>
</div>
`,
methods: {
handle: function() {
eventHub.$emit('first-event', 1)
}
},
mounted: function() {
//监听事件
eventHub.$on('second-event', (value) => {
this.num += value;
})
}
});
var vm = new Vue({
el: '#app',
data: {
},
methods: {
handle: function() {
eventHub.$off('first-event');
eventHub.$off('second-event');
}
}
});
</script>
</body>
</html>
组件插槽
父组件向子组件传递模板内容
1.位置
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Something I want to say:</strong>
<slot></slot>
</div>
`
});
2.内容
<alert-box>Hello World!!!</alert-box>
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<alert-box>Hello World!!!</alert-box>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Something I want to say:</strong>
<slot></slot>
</div>
`
});
var vm = new Vue({
el: '#app'
})
</script>
</body>
</html>
效果:
具名插槽
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- ------------用法1-------------- -->
<base-layout>
<h1 slot="header">我是Header</h1>
<h2>我是main</h2>
<h1 slot="footer">我是footer</h1>
<h2>我是main</h2>
</base-layout>
<!-- -------------用法2------------- -->
<base-layout>
<template slot="header">
<h1>我是header</h1>
<h1>我是header</h1>
</template>
</base-layout>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('base-layout', {
template: `
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
`
});
var vm = new Vue({
el: '#app'
})
</script>
</body>
</html>
效果:
作用域插槽
父组件对子组件的内容进行加工
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<fruit-list :list='list'>
<template slot-scope="slotProps">
<span v-if="slotProps.info.id==2" class="current">
{{slotProps.info.name}}
</span>
<span v-else>{{slotProps.info.name}}</span>
</template>
</fruit-list>
</div>
<script src="./vue.js"></script>
<script>
Vue.component('fruit-list', {
props: ['list'],
template: `
<div>
<ul>
<li :key='index' v-for='(item, index) in list'>
<slot :info="item">{{item.name}}</slot>
</li>
</ul>
</div>
`
});
var vm = new Vue({
el: '#app',
data: {
list: [{
id: 1,
name: 'apple'
}, {
id: 2,
name: 'orange'
}, {
id: 3,
name: 'banana'
}]
}
});
</script>
<style scoped>
.current {
color: brown;
font-size: 20px;
font-weight: 700;
}
</style>
</body>
</html>
效果: