文章目录
组件基础
注册组件的基本步骤
- 创建组件构造器
- 调用Vue.extend()方法
- 注册组件
- 调用Vue.component()方法
- 使用组件
- 在Vue实例的作用范围内使用组件
案例:全局组件的基本使用
<div id=app>
<!-- 使用组件-->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<script>
<!--创建组件构造器-->
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈</p>
<p>我是内容,嘻嘻嘻</p>
</div>
`
})
//注册组件-全局组件
Vue.component('my-cpn',cpnC)
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue'
}
})
</script>
全局组件与局部组件
-
全局组件可以在多个Vue实例中使用
-
局部组件只能在注册了这个组件的Vue实例中使用
-
局部组件的基本使用
<div id=app>
<!-- 使用组件-->
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<script>
<!--创建组件构造器-->
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈</p>
<p>我是内容,嘻嘻嘻</p>
</div>
`
})
//注册组件-全局组件
// Vue.component('my-cpn', cpnC)
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue'
},
//注册局部组件
components: {
myCpn: cpnC
}
})
</script>
父子组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>Document</title>
</head>
<body>
<div id=app>
<cpn2></cpn2>
</div>
<script>
const cpn1 = Vue.extend({
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容,哈哈哈</p>
</div>
`
})
const cpn2 = Vue.extend({
template: `
<div>
<cpn1></cpn1>
<h2>我是标题2</h2>
<p>我是内容,嘻嘻嘻</p>
</div>
`,
components: {
cpn1
}
})
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue'
},
//注册局部组件
components: {
cpn2
}
})
</script>
</body>
</html>
父子组件,其实就是组件的嵌套关系
组件注册语法糖
- 全局组件
//注册组件-全局组件
Vue.component('my-cpn', {
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈</p>
<p>我是内容,嘻嘻嘻</p>
</div>
`
})
- 局部组件
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue'
},
//注册局部组件
components: {
cpn2: {
template: `
<div>
<cpn1></cpn1>
<h2>我是标题2</h2>
<p>我是内容,嘻嘻嘻</p>
</div>
`,
components: {
cpn1
}
}
}
})
- 抽离出模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>Document</title>
</head>
<body>
<template id="cpn2">
<div>
<h2>我是标题1</h2>
<p>我是内容,哈哈哈</p>
</div>
</template>
<div id=app>
<cpn2></cpn2>
</div>
<script>
Vue.component('cpn2',{
template: '#cpn2'
})
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue'
},
//注册局部组件
components: {
}
})
</script>
</body>
</html>
为什么组件中的data必须是函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>Document</title>
</head>
<body>
<template id="cpn2">
<div>
<h2>{{title}}</h2>
<p>我是内容,哈哈哈</p>
</div>
</template>
<div id=app>
<cpn2></cpn2>
</div>
<script>
Vue.component('cpn2', {
template: '#cpn2',
data() {
return {
title: '我是标题111'
}
}
})
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue'
},
//注册局部组件
components: {}
})
</script>
</body>
</html>
答案非常简单,因为组件是需要被复用的,我们必须保证每次使用的时候,都有自己的一个数据空间。
相当于,因为data是一个函数,每次创建组件使用的时候,才能够使用一份单独的数据,不让同一个组件的不同实例产生影响。
父子间通讯
父传子:props
- 子组件中,
props
使用数组声明接收的数据名称
const cpn = {
template: `
<div>
<h2>{{title}}</h2>
<p>{{cmovies}}</p>
</div>
`,
props: ['cmovies'],
data() {
return {
title: '我是标题111'
}
}
}
- 注册子组件
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue',
movies: ['电影1', '电影2', '电影3']
},
//注册局部组件
components: {
cpn
}
})
- 传递数据
<div id=app>
<cpn :cmovies="movies"></cpn>
</div>
扩展
上例中,props的值是一个数组类型,还可以使用对象类型,这样可以指定变量的类型和默认值
const cpn = {
template: `
<div>
<h2>{{title}}</h2>
<p>{{cmovies}}</p>
</div>
`,
props: {
cmovies: Array,
cmessage: {
type: String,
required: false,
default: '111aa'
},
cc: {
default: function () {
//默认值是对象的话必须使用function返回
return {
a: 'aaa'
}
}
}
},
data() {
return {
title: '我是标题111'
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GtvbLVKh-1584459683921)(http://tuchuang.zhangln.com/uQ9qko.png)]
子传父:自定义事件
- 基本案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>Document</title>
</head>
<body>
<div id=app>
<!-- Step 2:父组件中监听子组件中的自定义事件 并设置处理函数-->
<cpn @title-changed="updateTitle"></cpn>
<h2>{{title}}</h2>
</div>
<script>
<!-- 子组件 -->
const cpn = Vue.extend({
template: `
<div>
<h1 @click="changeTitle">{{title}}</h1>
</div>
`,
data() {
return {
title: "Vue.js Demo"
}
},
methods: {
changeTitle() {
console.log("子组件向父组件发送消息");
//Step 1:子组件触发自定义事件,并传递参数
this.$emit("title-changed", "子向父组件传值");
}
}
})
//父组件
const app = new Vue({
el: '#app',
data: {
title: 'Hello Vue',
},
methods: {
//Step 3:父组件中定义函数处理子组件传递过来的数据
updateTitle(e) {
console.log("父组件收到子组件消息:" + e);
this.title = e;
}
},
//注册局部组件
components: {
cpn
}
})
</script>
</body>
</html>
父子间访问
父子组件内部,可以使用下面的方式,获取到父子组件的引用
父访问子
方式:this.$children
或this.$refs
子访问父
方式:this.$parent
插槽
基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>Document</title>
</head>
<body>
<div id=app>
<!-- 使用组件-->
<my-cpn>
<button>按钮</button>
</my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<script>
<!--创建组件构造器-->
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈</p>
<p>我是内容,嘻嘻嘻</p>
<slot></slot>
</div>
`
})
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue'
},
//注册局部组件
components: {
myCpn: cpnC
}
})
</script>
</body>
</html>
在组件模板中,使用<slot>
添加插槽
父组件使用带有插槽的子组件的时候,通过在组件中添加额外的html元素,替换子组件中原先插槽的位置
- 设置插槽的默认值
<slot><button>
按钮
</button></slot>
具名插槽
当需要替换多个内容的时候,就会用到多个插槽,多个插槽之间使用name标识
<div id="solt">
<app-layout>
<p slot="footer">这个是footer</p>
<h1 slot="header">这个是header</h1>
<p>这个什么都没有,只是一个P标签A</p>
<p>这个什么都没有,只是另一个P标签B</p>
<p slot="footer">这个是footer</p>
<p>这个什么都没有,只是另一个P标签C</p>
</app-layout>
</div>
<script>
Vue.component('app-layout', {
template: `
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
`,
})
new Vue({
el: '#solt'
})
编译作用域
<div id=app>
<!-- 使用组件-->
<my-cpn v-show="isShow">
<button>按钮</button>
</my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
这里isShow,会从app实例中的去查找,而不是my-cpn这个组件
父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译
作用域插槽
父组件替换插槽的标签,但是内容由子组件来提供;
在作用域插槽内,父组件可以拿到子组件的数据。子组件可以在slot标签上绑定属性值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BLsmA8iW-1584459683923)(http://tuchuang.zhangln.com/Smblgn.png)]
参考:https://www.jianshu.com/p/e10baeff888d