一、认识组件化
1、什么是组件化
2.Vue组件化思想
二、注册组件
1.注册组件的基本步骤
代码如下:
<div id='app'>
<my-cpn></my-cpn>
</div>
<script src='./js/vue.js'></script>
<script>
// 1.创建组件构造器对象
const cpnC = Vue.extend({
// 字符串语法 tab键上面
template: `
<div>
<h2>标题</h2>
<p>内容</p>
<p>结尾</p>
</div>
`
})
// 2.注册组件
Vue.component('my-cpn', cpnC)
const app = new Vue({
el: '#app',
data: {
message: '你好'
}
})
</script>
效果如下:
2.注册组件步骤解析
三、组件其他补充
1.全局组件和局部组件
代码如下:
<div id='app'>
<my-cpn></my-cpn>
<my-all></my-all>
</div>
<script src='./js/vue.js'></script>
<script>
const cpn = Vue.extend({
template: `
<div>
<h2>头部</h2>
<h2>尾部</h2>
</div>
`
})
// 1.全局组件:意味着可以在多个Vue的实例下面使用
Vue.component('my-cpn', cpn)
const app = new Vue({
el: '#app',
data: {
message: '你好'
},
// 2.局部注册组件
components: {
'my-all': cpn
}
})
</script>
效果如下:
2.父组件和子组件
代码如下:
<div id='app'>
<!-- <cpn1></cpn1> -->
<cpn2></cpn2>
</div>
<script src='./js/vue.js'></script>
<script>
// 1.创建第一个组件 子组件
const cpnc1 = Vue.extend({
template: `
<div>
<h2>标题</h2>
<h2>内容</h2>
</div>
`
})
// 2.创建第二个组件 父组件
const cpnc2 = Vue.extend({
template: `
<div>
<h2>标题2</h2>
<h2>内容2</h2>
<cpn1></cpn1>
</div>
`,
components: {
cpn1: cpnc1
}
})
// root组件
const app = new Vue({
el: '#app',
data: {
message: '你好'
},
components: {
cpn2: cpnc2,
}
})
</script>
效果如下:
3.注册组件语法糖
代码如下:
<div id='app'>
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script src='./js/vue.js'></script>
<script>
// 1.全局组件注册的语法糖
Vue.component('cpn1', {
template: `
<div>
<h2>标题</h2>
<h2>内容</h2>
</div>
`
})
// 2.局部组件注册的语法糖
const cpn2 = {
template: `
<div>
<h2>标题2</h2>
<h2>内容2</h2>
</div>
`
}
const app = new Vue({
el: '#app',
data: {},
components: {
'cpn2': cpn2
}
})
</script>
效果如下:
4.模板分离写法
代码如下:
<div id='app'>
<cpn></cpn>
<cpn2></cpn2>
</div>
<!-- 1.通过script标签,注意:类型必须为text/x-template -->
<script type="text/x-template" id="cpn">
<div>
<h2>标题</h2>
<p>内容</p>
</div>
</script>
<!-- 2.template标签 -->
<template id="cpn2">
<div>
<h2>标题cpn2</h2>
<p>内容cpn2</p>
</div>
</template>
<script src='./js/vue.js'></script>
<script>
// 注册全局组件
Vue.component('cpn', {
template: '#cpn'
})
Vue.component('cpn2', {
template: '#cpn2'
})
const app = new Vue({
el: '#app'
})
</script>
效果如下:
四、组件数据存放
1.组件可以访问Vue实例数据吗?
2.组件数据存放
3.为什么组件中data是一个函数?
五、父子组件的通信
1.父子组件的通信
2.父向子传递数据—props
- props基本用法
代码如下:
<div id='app'>
<children :movies="movies" :message="message"></children>
</div>
<template id="children">
<div>
<ul>
<li :key="index" v-for="(item, index) in movies">{{item}}</li>
</ul>
<h2>{{message}}</h2>
</div>
</template>
<script src='./js/vue.js'></script>
<script>
// 父传子 props
const children = {
props: ['movies', 'message'],
template: '#children'
}
const app = new Vue({
el: '#app',
data: {
message: '你好',
movies: ['大娃', '二娃', '三娃', '四娃']
},
components: {
children
}
})
</script>
- props数据验证
代码如下:
const children = {
template: '#children',
// props: ['movies', 'message'],
props: {
// 1.类型限制
// movies: Array,
// message: String
// 2.提供一些默认值,没传入时显示
message: {
type: String,
default: 'aaaa',
// 表示使用时,必须传值,否则报错
required: true
},
movies: {
type: Array,
// 类型是对象或者数组时,默认值必须是一个函数
// 以下两种写法都可以,但是 直接default:[]对vue版本支持不同
// default: [],
default() {
return []
},
// 表示使用时,必须传值,否则报错
required: true
}
}
}
- props中驼峰标识
总结:在Vue实例data中定义的数据名若为驼峰命名,则在数据绑定时改为以横线分割的字符串:
如infoMessage
→info-message
代码图片如下:着重看红色框框中的代码
3.子向父传递数据—自定义事件
效果如下:
六、父子组件的访问
1.父子组件的访问方式:$children
代码如下:
<div id='app'>
<cpn ref="aaa"></cpn>
<cpn></cpn>
<cpn></cpn>
<button @click="btnClick">按钮</button>
</div>
<template id="cpn">
<div>
我是子组件
</div>
</template>
<script src='./js/vue.js'></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好'
},
methods: {
btnClick() {
// 1.通过children方式
console.log(this.$children[0].showMessage)
console.log(this.$children[0].name)
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '子组件的name'
}
},
methods: {
showMessage() {
console.log('showMessage')
}
}
}
}
})
</script>
2.父子组件的访问方式:$refs ★★★★★
代码如下:
<div id='app'>
<cpn ref="aaa"></cpn>
<cpn></cpn>
<cpn></cpn>
<button @click="btnClick">按钮</button>
</div>
<template id="cpn">
<div>
我是子组件
</div>
</template>
<script src='./js/vue.js'></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好'
},
methods: {
btnClick() {
// 2.通过$refs方式★★★
// 需要在自定义组件中加上 ref 属性
console.log(this.$refs.aaa.name)
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '子组件的name'
}
},
methods: {
showMessage() {
console.log('showMessage')
}
}
}
}
})
</script>
3.子访问父-访问方式:$parent或 $root
$parent
:用来访问父组件
$root
:用来访问根组件
代码如下:
<div id='app'>
<h2>子组件</h2>
<cpn></cpn>
</div>
<!-- 子组件 -->
<template id="cpn">
<div>
<ccpn></ccpn>
</div>
</template>
<!-- 孙组件 -->
<template id="ccpn">
<div>
<h2>我是子-孙组件</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script src='./js/vue.js'></script>
<script>
// 根组件
const app = new Vue({
el: '#app',
data: {
message: '根组件'
},
// 子组件
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '子组件'
}
},
// 孙组件
components: {
ccpn: {
template: '#ccpn',
methods: {
btnClick() {
// 1.子访问父$parent
console.log(this.$parent)
console.log(this.$parent.name)
// 2.访问根组件$root
console.log(this.$root.message)
}
},
}
}
}
}
})
</script>
效果如下:
4.非父子组件传值
代码如下:
<div id="app">
<test-tom></test-tom>
<test-joy></test-joy>
<button @click='handle'>销毁事件</button>
</div>
<script src="../vue.js"></script>
<script>
// 提供事件中心
var hub = new Vue();
Vue.component('test-tom', {
data: function () {
return {
num: 0
}
},
template: `
<div>
<div>tom:{{num}}</div>
<button @click='handle'>点击</button>
</div>
`,
methods: {
handle: function () {
// 触发兄弟组件的事件
hub.$emit('joy-event', 2);
}
},
mounted: function () {
//监听事件,钩子函数
hub.$on('tom-event', (val) => {
// val是兄弟组件传递过来的
this.num += val;
});
}
})
Vue.component('test-joy', {
data: function () {
return {
num: 0
}
},
template: `
<div>
<div>joy:{{num}}</div>
<button @click='handle'>点击</button>
</div>
`,
methods: {
handle: function () {
hub.$emit('tom-event', 1);
}
},
mounted: function () {
//监听事件,钩子函数
hub.$on('joy-event', (val) => {
// val是兄弟组件传递过来的
this.num += val;
});
}
})
var vm = new Vue({
el: '#app',
data: {},
methods: {
handle: function () {
hub.$off('tom-event');
hub.$off('joy-event');
}
}
})
</script>
七、插槽slot
1.为什么使用slot
2.如何封装这类组件
3.slot基本使用
代码如下:
<!-- 1.插槽基本使用,定义slot标签 -->
<!-- 2.插槽默认值,slot标签内的内容 -->
<!-- 3.多个值,同时放入组件中进行替换,一起作为替换元素 -->
<div id='app'>
<cpn><button>按钮</button></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是组件</h2>
<p>我是组件,哈哈哈</p>
<!-- 如果组件没有内容,默认显示 -->
<slot><button>默认按钮</button></slot>
</div>
</template>
<script src='./js/vue.js'></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好'
},
components: {
cpn: {
template: '#cpn'
}
}
})
</script>
效果如下:
4.具名插槽slot
代码如下:
<div id='app'>
<cpn><span slot="center">标题</span></cpn>
<cpn><button slot="left">返回</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 app = new Vue({
el: '#app',
data: {
message: '你好'
},
components: {
cpn: {
template: '#cpn'
}
}
})
</script>
效果如下:
5.编译作用域
代码如下:
<div id='app'>
<cpn v-show="isShow"></cpn>
</div>
<template id="cpn">
<div>
<h2>我是子组件</h2>
<p>我是内容</p>
<button v-show="isShow"></button>
</div>
</template>
<script src='./js/vue.js'></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好',
isShow: true
},
components: {
cpn: {
template: '#cpn',
data() {
return {
isShow: false
}
}
}
}
})
</script>
效果如下:
6.作用域插槽:准备
7.作用域插槽:使用
代码如下:
<div id='app'>
<cpn></cpn>
<cpn>
<!-- 目的是获取子组件中的数据 -->
<template slot-scope="slot">
<!-- <span v-for="item in slot.data">{{item}}、</span> -->
<span>{{slot.data.join('、')}}</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<slot :data='pLanguages'>
<ul>
<li v-for="item in pLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script src='./js/vue.js'></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好'
},
components: {
cpn: {
template: '#cpn',
data() {
return {
pLanguages: ['JavaScript', 'c++', 'python', 'Go', 'Java', 'c#']
}
}
}
}
})
</script>
效果如下:
内容持续更新中…
lvan学习笔记-文章内容仅个人观点
2020.6.3