vue-组件化
组件的使用分为三个步骤
- 创建组件构造器
调用Vue.extend()方法创建组件构造器 - 注册组件
调用Vue.component()方法注册组件 - 使用组件
在Vue实例的作用范围内使用组件
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{{message}}
<!--使用组件-->
<my-cpn></my-cpn>
</div>
<script src="../js/vue.js"></script>
<script>
//1.创建组件构造器对象
const cnpC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>`
})
//2.注册组件
Vue.component('my-cpn',cpnC)
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
</body>
</html>
全局组件和局部组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{{message}}
<!--使用组件-->
<my-cpn></my-cpn>
</div>
<div id="app2">
<my-cpn></my-cpn>
</div>
<script src="js/vue.js"></script>
<script>
//1.创建组件构造器对象
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>`
})
//2.注册组件(全局组件,意味着可以在多个Vue的实例下面使用)
Vue.component('my-cpn',cpnC)
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
//cpn使用组件时的标签名//2.注册组件(局部组件)
cpn: cpnC
}
})
const app2 = new Vue({
el: '#app2',
})
</script>
</body>
</html>
父组件和子组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{{message}}
<!--使用组件-->
<cpn2></cpn2>
</div>
<script src="js/vue.js"></script>
<script>
//1.创建第一个组件构造器对象(子组件)
const cpnC1 = Vue.extend({
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>`
})
//1.创建第二个组件构造器对象(父组件)
const cpnC2 = Vue.extend({
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>`,
components: {
cpn1: cpnC1
}
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
//cpn使用组件时的标签名 注册组件(局部组件)
cpn2: cpnC2
}
})
</script>
</body>
</html>
语法糖格式
语法糖注册全局组件
//2.注册组件(全局组件,意味着可以在多个Vue的实例下面使用)
Vue.component('my-cpn', {
template: `
<div>
<h2>我是标题</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>
`
})
语法糖注册局部组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
'cpn2': {
template: `
<div>
<h2>我是标题</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>
`
}
}
})
组件模板抽离写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
</div>
<!-- 1.script标签,注意:类型必须是text/x-template -->
<!-- <script type="text/x-template" id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>
</script> -->
<!-- 2.template标签 -->
<template id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>
</template>
<script src="js/vue.js"></script>
<script>
//2.注册组件(全局组件,意味着可以在多个Vue的实例下面使用)
Vue.component('cpn', {
template: `#cpn`
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
</body>
</html>
组件数据存放问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
</div>
<!-- 1.script标签,注意:类型必须是text/x-template -->
<!-- <script type="text/x-template" id="cpn">
<div>
<h2>我是标题</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>
</script> -->
<!-- 2.template标签 -->
<template id="cpn">
<div>
<h2>{{title}}</h2>
<p>我是内容1</p>
<p>我是内容2</p>
</div>
</template>
<script src="js/vue.js"></script>
<script>
//2.注册组件(全局组件,意味着可以在多个Vue的实例下面使用)
Vue.component('cpn', {
template: '#cpn',
data() {
return {
title: 'abc'
}
}
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
</body>
</html>
父子组件的通信
通过props向子组件传递
通过事件向父组件发送消息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn :cmessage="message" :cmovies="movies"></cpn>
</div>
<template id="cpn">
<div>
<h2>{{cmovies}}</h2>
<p>{{cmessage}}</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
// props: ['cmovies', 'cmessage'],
props: {
// 提供一些默认值和类型限制,以及必传值
cmessage: {
type: String,
default: 'bbbb',
required: true
},
// 当类型是对象或者数组时,默认值必须是一个函数
cmovies: {
type: Array,
default() {
return []
}
}
},
data() {
return{}
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
cpn
}
})
</script>
</body>
</html>
props数据验证所支持的数据类型
当我们又自定义构造函数时,验证也支持自定义的类型
props的驼峰表示写法
子传父
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn @btn-click="cpnClick"></cpn>
</div>
<template id="cpn">
<div>
<button v-for="item in apps" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return{
apps: [
{id:'1',name:'学习强国'},
{id:'2',name:'淘宝'},
{id:'3',name:'知乎'},
{id:'4',name:'抖音'}
]
}
},
methods: {
btnClick(item) {
//发射事件
this.$emit('btn-click',item)
}
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
cpn
},
methods: {
cpnClick(item) {
console.log(item)
}
}
})
</script>
</body>
</html>
父子间通信结合双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn :mesage1="message1"
:mesage2="message2"
@msg1change="msg1Change"
@msg2change="msg2Change">
</cpn>
</div>
<template id="cpn">
<div>
<h1>props:{{mesage1}}</h1>
<h2>data:{{dmesage1}}</h2>
<input type="text" :value="dmesage1" @input="msg1Input">
<h1>props:{{mesage2}}</h1>
<h2>data:{{dmesage2}}</h2>
<input type="text" :value="dmesage2" @input="msg2Input">
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
props: {
mesage1: Number,
mesage2: Number
},
data() {
return{
dmesage1:this.mesage1,
dmesage2:this.mesage2
}
},
methods: {
msg1Input(event){
// 将input中的value赋值到dnumber中
this.dmesage1 = event.target.value;
// 为了让父组件可以修改值,发出一个事件
this.$emit('msg1change',this.dmesage1)
// // 同时修改dmesage2的值
// this.dmesage2 = this.dmesage1 * 100;
// this.$emit('msg2change',this.dmesage2)
},
msg2Input(event){
this.dmesage2 = event.target.value;
this.$emit('msg2change',this.dmesage2)
// // 同时修改dmesage1的值
// this.dmesage1 = this.dmesage2 * 100;
// this.$emit('msg1change',this.dmesage1)
}
}
}
const app = new Vue({
el: '#app',
data: {
message1: 1,
message2: 2
},
components: {
cpn
},
methods: {
msg1Change(value){
this.message1 = parseInt(value)
},
msg2Change(value){
this.message2 = parseInt(value)
}
}
})
</script>
</body>
</html>
父访问子的属性或方法children- refs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn ref="aaa"></cpn>
<button @click="btnClick">按钮</button>
</div>
<template id="cpn">
<div>
<h1>111</h1>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return{
name:'我是子组件的name'
}
},
methods: {
showMessage(){
console.log('showMessage');
}
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好'
},
components: {
cpn
},
methods: {
btnClick(){
// 1、$children
// console.log(this.$children);
// for(let c of this.$children){
// console.log(c.name);
// c.showMessage();
// }
//2 $ ref
console.log(this.$refs.aaa.name);
}
}
})
</script>
</body>
</html>
子访问父组件的属性或方法
用 p a r e n t 访 问 父 组 件 用 parent访问父组件 用 parent访问父组件用root访问根组件
插槽
(同一个组件显示不同数据)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn>aaa</cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h1>111</h1>
<slot><button>按钮</button></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return{
}
},
methods: {
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好'
},
components: {
cpn
},
methods: {
}
})
</script>
</body>
</html>
具名插槽的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn><span slot="center">标题</span></cpn>
<cpn><button slot="left">1</button></cpn>
</div>
<template id="cpn">
<div>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return{
}
},
methods: {
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好'
},
components: {
cpn
},
methods: {
}
})
</script>
</body>
</html>
什么是编译作用域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn v-show="isShow"></cpn>
</div>
<template id="cpn">
<div>
<span v-show="isShow">左边</span>
<span>中间</span>
<span>右边</span>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return{
isShow: false
}
},
methods: {
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好',
isShow: true
},
components: {
cpn
},
methods: {
}
})
</script>
</body>
</html>
作用域插槽的使用
父组件替换插槽的标签,但是内容由子组件来提供
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn>
<template slot-scope="slot">
<span>{{slot.data.join(' - ')}}</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<slot :data="pugs">
<ul>
<li v-for="i in pugs">{{i}}</li>
</ul>
</slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return{
pugs:['java','c++','c#','javascript']
}
},
methods: {
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好'
},
components: {
cpn
},
methods: {
}
})
</script>
</body>
</html>