一、组件化
(1):全局组件与局部组件的定义
组件定义的步骤:
1:组件注册
2:组件的模板定义与绑定
3:组件的使用
注意点:
/*全局组件
01:全局组件:Vue.component(name,options)
name:为组件名称
options:为组件的配置参数(是个对象)
template:只能是有一个根节点
组件用途:
复用---(每一次返回一个对象)为了达到复用的时候,每一个为独立的数据
三段论:
大前提:Vue有着以下配置参数(data,directives,methods等)
小前提:组件是一个Vue实例
结论:组件具有与Vue实例一样的配置参数 但是没有el,其中data必须为函数(返回一个对象)
*/
<div id="app">
<!-- 3:使用组件 -->
<cpm></cpm>
</div>
<!-- 2-1定义模板 -->
<template id="cpm">
<div>
<!--02: 使用局部组件 -->
<my-header></my-header>
my name is {{name}},我今年{{age}}。
<my-footer></my-footer>
</div>
</template>
//1:定义一个全局组件
Vue.component('cpm', {
data() {
return {
name: 'liang',
age: 22,
sex: 'nan'
}
},
//2-2:利用选择器绑定模板
template: "#cpm",
//01:定义局部组件
components: { //全局组件里面可以定义局部组件
myHeader: { //header为局部组件名称,{}为配置参数
template: `<header>cpm组件的头部</header>`
},
myFooter: {
template: `<footer>cpm组件的尾部</footer>`
}
},
methods: {
}
})
//这是根组件
const vm = new Vue({
el: "#app",
data: {
},
methods: {
},
directives: {
},
componets: {
}
})
二、父子组件的通讯
//父子组件的通讯
// 一般而言,一些数据都是在大组件发送请求数据,然后向下层传递数据
// 父子间的通讯有两种方式
//1:通过props属性向子组件传递数据
//2:通过事件向父组件发送消息
2:props属性名命名规则
01:如果props中使用驼峰命名法,模板中(html)则需要使用-来划分(buttonContent :button-content)
02:字符串形式的模板则没有这个限制
3:props属性值类型
01:字符串-String 02:数值-number
03:布尔值-boolean 04:数组-Array 05:对象-Object---常用
// 注意点:首先是父组件的数据(本身定义一个局部组件),然后通过属性绑定的方式, ,然后在子组件里面通过props属性接受
(1): 父组件向子组件传值
步骤:
1:定义父组件—里面定义行数据
2:再父组件内部定义一个局部组件(子组件用于接收父组件传递值)
注意点:在里面使用了 对象的字面量增强写法 本来是cpm:cpm
3:对子组件的抽离出去的进行定义–
01:模板的定义和绑定
02:数据的传递与接收 传递是在Vue实例中(cpm例如属性的绑定来传递的),props接收传递的值
03:其中prop可以输数组,对象,字符串等 可以提高默认值
04:最后在模板中使用数据
<div id="app">
<!-- 2:使用父组件来传递值 通过属性的绑定,子组件绑定承接父组件的数据-->
<cpm :cmovies="movies" :cmsg="msg"></cpm>
</div>
<!--02: 子组件的模板 -->
<template id="cpm">
<div>
<!-- 03:最后引用数据 -->
<ul>
<li v-for="item in cmovies">{{cmsg +'-'+ item}}</li>
</ul>
</div>
</template>
//01-2:子组件的定义(抽离出来)
const cpm = {
template: '#cpm',
// props: ['cmovies', 'cmsg'],//数组类型
props: { //其中prop可以输数组,对象,字符串等 可以提高默认值
cmovies: {
type: Array,
defalute() { //类型为数组或者对象的时候,默认值是一个函数,有返回值(数组或者对象)
return []
},
required: true, //必须传递这个属性
},
cmsg: {
type: String
}
}
}
//1:定义父组件
const vm = new Vue({
el: "#app",
data: {
msg: '你好啊',
movies: ['火影', '蓝色', '佳佳']
},
// 01-1:定义子组件
components: {
// 'cpm': {
// //假如是 'cpm':cpm的话,则是被抽离到外部,需要在外面定义组件 const cpm
// },
cpm //或者直接简写 cpm(则是被抽离到外部,需要在外面定义组件 const cpm )
// 对象的字面量增强写法 本来是cpm:cpm
}
});
(2): 父组件向子组件传值(驼峰写法)
<body>
<div id="app">
<!--3 组件定义的属性为驼峰的时候,在html这边,需要以-来拆分, -->
<cpm :c-info="info" :c-msg="msg"></cpm>
</div>
<!-- 02:子组件模板 -->
<template id="cpm">
<div>
<h2>{{cInfo}}</h2>
<p>{{cMsg}}</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
//父传子-props驼峰标识
//01:子组件
const cpm = ('cpm', {
data() {
return {}
},
//03:接受模板和接受数据
template: '#cpm',
props: {
cInfo: {
type: Object,
defalute() {
return {}
}
},
cMsg: {
type: String,
defalute: 'aaaa',
}
}
})
//1-父组件
const vm = new Vue({
el: "#app",
data: {
msg: '你好啊',
info: {
uname: 'why',
sex: '男',
age: 18
}
},
//2:定义一个局部组件
components: {
cpm
}
});
</script>
</body>
(3): 子组件向父组件传值
/*
子组件向父组件发送数据的步骤:
01:定义子组件
02:子组件模板 并且子子组件进行绑定(id)
03:对子组件内的数据进行定义并且在模板渲染
04-子组件向父组件发送点击事件
注意点:1:子组件发射事件1-定义btnclick事件(并且发生参数)
2:子组件发射事件2-btnclick事件 发射事件itemclick(自定义一个事件)
3:子组件发射事件3,在父组件(引用了cpm组件)监听该事件,并且化为cpmclick事件再父组件处理
4:在父组件的方法里面,做输出等
*/
<!-- 父组件模板 -->
<div id="app">
<!-- 子组件发射事件,在父组件监听该事件,并且化为cpmclick事件再父组件处理 -->
<cpm @itemclick="cpmclick"></cpm>
</div>
<!-- 子组件模板 -->
<template id="cpm">
<div>
<ul>
<!-- 子组件发射事件1-定义btnclick事件 -->
<li v-for="(item,index) in catagories" @click="btnclick(item)">{{item.name}}</li>
</ul>
</div>
</template>
//01-2:定义一个子组件模板和内容
const cpm = {
data() {
return {
catagories: [{
id: 1,
name: '胡奥'
},
{
id: 2,
name: '电器'
}, {
id: 3,
name: '号码'
}
]
}
},
template: '#cpm',
methods: {
// 子组件发射事件2-btnclick事件 发射事件itemclick
btnclick(item) {
this.$emit('itemclick', item);
}
}
}
//1:定义父组件
const vm = new Vue({
el: "#app",
data: {},
//01-1:定义一个子组件
components: {
cpm
},
methods: {
cpmclick(item) {
console.log(item);
}
}
})
三、组件访问
(1):父访问子
<!-- 父组件 -->
<div id="app">
<cpm></cpm>
<cpm></cpm>
<cpm ref="aaa"></cpm>
<button @click="btnclick">点击</button>
</div>
<!-- 02-1:子组件模板 并且子子组件进行绑定(id) -->
<template id="cpm">
<div>
我是子组件的
</div>
</template>
//01:定义一个父组件
const vm = new Vue({
el: "#app",
data: {},
methods: {
},
methods: {
btnclick() {
//1:利用$children来访问子组件的内容
// console.log(this.$children);
// this.$children[0].showMsg();
// for (let i of this.$children) {
// console.log(i.name);
// }
//2:使用$refs来访问子组件的内容---常用
//2-1:首先需要定义ref属性(html中,并且有一个属性值,证明你需要取得的某个组件)例如:ref="aaa"
this.$refs;
console.log(this.$refs.aaa.name);
}
},
//02:定义局部组件 组件{模板-数据-方法}
components: {
cpm: {
template: '#cpm',
data() {
return {
name: '我是子组件的name'
}
},
methods: {
showMsg() {
console.log('showMsg');
}
}
},
}
});
(1):子访问父
<div id="app">
<cpm></cpm>
</div>
<template id="cpm">
<div>
<h2>我是子组件</h2>
<button @click="btnClick">点击</button>
</div>
</template>
//点击子组件的按钮,访问父组件的数据
const vm = new Vue({
el: "#app",
data: {},
components: {
cpm: {
template: '#cpm',
methods: {
btnClick() {
//1:访问父组件---通过$parent
console.log(this.$parent);
//2:访问根组件
console.log(this.$root);
}
}
}
}
});
四、插槽
(1):插槽的基本使用
slot插槽
目的:是的原来的设备具有更多的扩展性(slot标签:就是给组件留下预留空间)
1:就是在组件内部定义一个<slot></slot>标签
2:插槽里面的默认值:<slot><button>按钮</button></slot>
假如cpm组件里面,在父组件使用的时候,里面没有任何标签,那么会加入button默认值
3:插槽的替换:<slot><button>按钮</button></slot>
假如cpm组件里面,在父组件使用的时候,里面没有有标签,那么会其他的标签作为整体把button替换了
<div id="app">
<!-- 在组件内部,添加button,替代带那个slot标签 -->
<cpm><button>按钮</button></cpm>
<cpm><span>我啊</span></cpm>
<cpm>
<i>我</i>
<div>123</div>
</cpm>
</div>
<template id="cpm">
<div>
<h2>我是组件插槽的基本使用</h2>
<p>WPS组件</p>
<slot><button>默认按钮</button></slot>
</div>
</template>
const vm = new Vue({
el: "#app",
data: {},
components: {
cpm: {
template: "#cpm"
}
}
});
(2):具名插槽的使用
具名插槽:
1:就是给标签起一个名字 比如 左边
2:使用的时候,需要替换那个插槽,就再父组件使用组件的时候,把插槽内的标签添加slot=“要修改的标签”
比如: 标题
<div id="app">
<!-- 在组件内部,添加button,替代带那个slot标签 -->
<cpm><span slot="center">标题</span></cpm>
<cpm><button slot="center">按钮</button></cpm>
</div>
<template id="cpm">
<div>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
<!-- <slot>11</slot> -->
</div>
const vm = new Vue({
el: "#app",
data: {},
components: {
cpm: {
template: "#cpm"
}
}
});
(3):作用域
<!-- 父组件 作用域在父组件内 -->
<div id="app">
<cpm v-show="isShow"></cpm>
</div>
<!-- 子组件 作用域在子组件内,所以这个isShow为false -->
<template id="cpm">
<div>
<h2>我是子组件</h2>
<p>我是内容</p>
<button v-show="isShow">阿牛</button>
</div>
</template>
const vm = new Vue({
el: "#app",
data: {
msg: "你好啊",
isShow: true
},
components: {
cpm: {
template: "#cpm",
data() {
return {
isShow: false
}
}
}
}
})
(4):作用域插槽的使用
/*作用域插槽:
父组件替换插槽标签,但是内容由子组件来提供
案例:子组件有着以下数据: pLanguages:['JS','PY','C',"C++"]
1:需要在某些界面以水平方向一一展示
2:某些界面是以列表形式展示
3:某些界面直接展示一个数组
内容在子组件,希望父组件怎么展示? --- 利用slot作用域插槽就可以了
*/
/*
步骤:
1:在子组件内部使用一个插槽作用域,由于是获取数据,定义为data
2:在父组件内部使用子组件的时候,在子组件内部,定义一个template标签,并且通过slot-scope="slot" 来引用插槽的数据
3:由于数据存在了slot.data,使用它即可
*/
<div id="app">
<cpm></cpm>
<cpm>
<!-- 目的:就是获取子组件的pLanguages 使用template标签里面定义slot-scope="slot" 来引用插槽的数据 -->
<template slot-scope="slot">
<!-- <span v-for="item in slot.data">{{item + ' '}}</span> -->
<span>{{slot.data.join('-')}}</span>
</template>
</cpm>
<cpm>
<template slot-scope="slot">
<ul>
<li>{{slot.data}}</li>
</ul>
</template>
</cpm>
</div>
<template id="cpm">
<div>
<slot :data="pLanguages">
<ul>
<li v-for="item in pLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>
const vm = new Vue({
el: "#app",
data: {
},
components: {
cpm: {
template: "#cpm",
data() {
return {
pLanguages: ['JS', 'PY', 'C', "C++"]
}
}
}
}
})