一、组件的通信
1、为什么通信?
- 组件是一个聚合体,合并项目后,各个组件之间需要建立联系
2、分类
<1>父子组件通信
- data选项为什么是一个函数?
- 因为组件是一个聚合体,也是一个整体,它需要一个独立的作用空间,它的数据是需要独立的。目前JS最大的特点是函数式编程,而函数恰好提供了一个独立作用域,所以data在除了根组件外的组件里都是函数
- 为什么data函数需要一个返回值,并且返回的是对象?
- Vue通过es5的Object.definedPerproty属性对一个对象进行getter和setter设置,而data选项作为Vue深入响应式核心的选项
- 过程:
- 父组件将自己的数据同v-bind绑定在子组件上
- 子组件通过props选项接收
- 数据验证
- props属性数据验证
- 验证数据类型
- 验证数据大小(返回判断条件)
- 第三方验证
- TypeScript
- Vue-validator 插件
- props属性数据验证
<template id="father">
<div>
<p>父组件</p>
<Son :num='num'></Son>
</div>
</template>
<template id="son">
<div>
<p>子组件</p>
<p>父组件给了我{{num}}</p>
</div>
</template>
Vue.component("Father", {
template: "#father",
data() {
return {
num: 100
}
}
})
Vue.component("Son", {
template: "#son",
// props: ['num']
// props: {
// num: Number
// }
props: {
num: {
validator(val) {
return val > 200 //数据验证
}
}
}
})
<2>子父组件通信
- 通过自定义事件$emit
- 事件的发布(通过绑定元素实现)
- 事件的订阅(通过this.$emit触发)
<div id="app">
<Father></Father>
</div>
<template id="father">
<div>
<p>父组件</p>
<p>子组件给了我{{fNum}}</p>
<Son @give='fn'></Son>
</div>
</template>
<template id="son">
<div>
<p>子组件</p>
<p></p>
<button @click='giveNum'>给父组件num</button>
</div>
</template>
Vue.component("Father", {
template: "#father",
data() {
return {
fNum: 0
}
},
methods: {
fn(val) {
this.fNum = val;
}
}
})
Vue.component("Son", {
template: "#son",
data() {
return {
num: 1234
}
},
methods: {
giveNum() {
this.$emit("give", this.num);
}
}
})
<3>非父子组件通信
- 通信方式1:
<template id="father">
<div>
<p>父组件</p>
<Son @fn="fn"></Son>
<Daughter ref="daughter"></Daughter>
</div>
</template>
<template id="son">
<div>
<p>子组件1</p>
<button @click="send">给子组件2发消息</button>
</div>
</template>
<template id="daughter">
<div>
<p>子组件2</p>
<p v-show='flag'>子组件1给了我发消息了</p>
</div>
</template>
Vue.component("Father", {
template: "#father",
methods: {
fn() {
this.$refs.daughter.changeFlag() //!!!!!!!!!
}
}
})
Vue.component("Son", {
template: "#son",
methods: {
send() {
this.$emit('fn')//!!!!!!!!
}
}
})
Vue.component("Daughter", {
template: "#daughter",
data() {
return {
flag: false
}
},
methods: {
changeFlag() {
this.flag = !this.flag
}
}
})
- 通信方式2:bus
<template id="father">
<div>
<p>这是父组件</p>
<Son></Son>
<Daughter></Daughter>
</div>
</template>
<template id="son">
<div>
<p>这是子组件1</p>
<button @click="send">给子组件2发送消息</button>
</div>
</template>
<template id="daughter">
<div>
<p>这是子组件2</p>
<p v-if='flag'>我收到了子组件1传来的消息</p>
</div>
</template>
var bus = new Vue();//!!!!!!!!!!!!!
Vue.component("Father", {
template: "#father",
})
Vue.component("Son", {
template: "#son",
methods: {
send() {
bus.$emit("get")//!!!!!!!!!!!!1
}
}
})
Vue.component("Daughter", {
template: "#daughter",
data() {
return {
flag: false
}
},
mounted() { //表示组件挂载结束。可在视图中看到该组件
var that = this;
bus.$on("get", function () {//!!!!!!!
return that.flag = !that.flag;
})
}
})
<4>非常规通信
- 可以实现子父通信
- 方式1:
- 父组件通过v-bind绑定一个方法给子组件
- 子组件通过props选项接收这个方法,然后直接调用
<template id="father"> <div> <p>这是父组件</p> <p>{{fnum}}</p> <Son :fn="fn"></Son> </div> </template> <template id="son"> <div> <p>这是子组件</p> <button @click="fn(num)">给父组件发消息</button> </div> </template>
Vue.component("Father", {
template: "#father",
data() {
return {
fnum: 0
}
},
methods: {
fn(val) {
this.fnum = val
}
}
})
Vue.component("Son", {
template: "#son",
data() {
return {
num: 12345
}
},
props: ['fn']
})
- 方式2:
- 父组件通过v-bind绑定一个对象类型数据给子组件
- 子组件直接调用,如果更改这个数据,父组件的数据也更改(因为引用同一个地址,但违背了单向数据流)
<template id="father">
<div>
<p>这是父组件</p>
<p>{{fnum.num}}</p>
<Son :fnum="fnum"></Son>
</div>
</template>
<template id="son">
<div>
<p>这是子组件</p>
<input type="text" name="" id="" v-model="fnum.num">
</div>
</template>
Vue.component("Father", {
template: "#father",
data() {
return {
fnum: {
num: 1112222
}
}
}
})
Vue.component("Son", {
template: "#son",
props: ["fnum"]
})
二、slot 插槽
1、分类:
- 普通插槽
- 具名插槽 (给slot加一个name属性)
//Vue2.5的使用形式
<div d="app">
<Hello>
<header slot="header"></header>
<footer slot="footer"></footer>
</Hello>
</div>
<template id="hello">
<div>
<slot name="header"></slot>
<slot name="footer"></slot>
</div>
</template>
2、v-slot指令:可以将组件的数据在组件的内容中使用
//Vue2.6x的使用形式
//v-slot指令
<div id="app">
<Hello>
<template v-slot:csq="Orange">
<div>
<p>我在里面</p>
{{Orange.info}}
</div>
</template>
</Hello>
</div>
<template id="hello">
<div>
<p>我在外面</p>
<slot :info="info" name="csq"></slot>
</div>
</template>
Vue.component("Hello", {
template: "#hello",
data() {
return {
info: "发送进来了"
}
}
})
三、过渡效果
Vue框架使用css3和js实现过度效果
1、实现方式
- 在 CSS 过渡和动画中自动应用 class
Vue内部提供了<transition></transition>
使用transition组件包裹过渡元素,会自动给过渡元素添加6个类名,8个钩子函数
默认类名以v开头
如果有name属性,则以name属性值开头 - 可以配合使用第三方 CSS 动画库,如 Animate.css
引入animate外部文件
在animate官网查找动画效果,作为类名成对加在transition组件上 - 在过渡钩子函数中使用 JavaScript 直接操作 DOM
Vue提供了8个JS钩子,需要自定义JS动画 - 可以配合使用第三方 JavaScript 动画库,如 Velocity.js
四、过滤器
1、作用
对已存在的数据做数据格式化
2、定义
//全局定义
//Vue.filter(过滤器名称:function(){
//}
//局部定义
filters: {
'imgFilter': function ( val ) { //val表示需要格式化的数据
return val.replace( 'w.h', '128.180')
}
},
3、使用
<img :src = "item.img | imgFilter "/>
五、自定义指令
1、 定义形式
- 全局定义
- 局部定义
//Vue.directive("自定义指令名",选项)
Vue.directive("focus",{
bind(el,binding,vnode,oldVnode){
//当自定义指令和元素绑定时触发
},
inserted(el,binding,vnode,oldVnode){
//当自定义指令绑定的元素插入到页面时触发
},
updated () {
// 当自定义指令的元素或是他的子元素发生变化式触发
},
componentUpdate () {
//当自定义指令的元素或是他的虚拟子节点 发生变化式触发
},
unbind () {
// 当自定义指令绑定的元素解绑时触发
}
})
2、使用
// Vue.directive('focus',{
// inserted ( el,binding,vnode,oldVnode ) {
// if ( binding.modifiers.a ) {
// el.style.background = 'red'
// } else {
// el.style.background = 'blue'
// }
// el.value = binding.expression
// el.focus()
// },
// })
new Vue({
el: '#app',
directives: {
'focus': {
inserted ( el ) {
el.focus()
}
}
}
})
六、swiper
swiper是一个实现滑动操作的第三方库
官网:swiper官网