组件通信、过滤器、自定义指令等
组件的通信
组件是一个聚合体,合并项目,组件之间通过数据通信建立联系。
父子组件通信
<template id="father">
<div>
<h3> 这里是father </h3>
<!-- 父组件将自己的数据绑定给子组件身上 -->
<Son :money = "money"></Son>
</div>
</template>
<template id="son">
<div>
<h3> 这里是son </h3>
<p> 我收到了父亲给的 {{ money }} </p>
</div>
</template>
<script>
Vue.component('Father',{
template: '#father',
data () {
return {
money: 10000
}
}
})
Vue.component('Son',{
template: '#son',
props: ['money'] //子组件通过props属性接受
})
new Vue({
el: '#app'
})
</script>
-
data选项是一个函数
-
组件是一个聚合体,也是一个整体,它需要一个独立的作用空间,也就是它的数据需要是独立的,目前js的最大特点是函数式编程,而函数恰好提供了一个独立作用域,所以我们data在出根组件外都是函数
-
data函数需要一个返回值
- Vue通过es5的Object.definePerproty属性对一个对象进行getter和setter设置,而data选项是作为Vue深入响应式核心的选项
-
过程
-
- 父组件将自己的数据同 v-bind (:)绑定在 子组件身上
- 子组件通过 props属性接收
- props属性数据验证
- 验证数据类型
- 验证数据大小【 判断条件 】
// props: ['money'] // 数据验证 // props: { // 'money': Number // } props: { 'money': { validator ( val ) { // 验证函数 return val > 2000 } } }
- 第三方验证:
- TypeScript [ TS ]
- 插件 vue-validator 等
-
子父组件通信
<body>
<div id="app">
<Father></Father>
</div>
<template id="father">
<div>
<h3> 这里是father </h3>
<p> 我现在有 {{ gk }} </p>
<Son @give = "fn"></Son>
</div>
</template>
<template id="son">
<div>
<h3> 这里是son </h3>
<button @click = "giveHongbao"> 给父亲红包 </button>
</div>
</template>
</body>
<script>
Vue.component('Father',{
template: '#father',
data ( ) {
return {
gk: 0
}
},
methods: {
fn ( val ) {
this.gk = val
}
}
})
Vue.component('Son',{
template: '#son',
data () {
return {
money: 5000 //要传给父组件的数据
}
},
methods: {
giveHongbao () {
this.$emit('give',this.money) //触发give事件,传入的参数为this.money
}
}
})
new Vue({
el: '#app'
})
</script>
- 是通过自定义事件
- 事件的发布
- 通过绑定元素身上实现
- 事件的订阅
- 通过this.$emit触发
- 事件的发布
非父子组件通信
- ref链
<body>
<div id="app">
<Father></Father>
</div>
</body>
<template id="father">
<div>
<h3> 这里是父组件 </h3>
<Girl @fn = "fn"></Girl>
<!-- 父组件获得son组件 -->
<Son ref = "son"></Son>
</div>
</template>
<template id="son">
<div>
<h3> 这里是son组件 </h3>
<p v-show = "flag"> o(╥﹏╥)o o(╥﹏╥)o o(╥﹏╥)o o(╥﹏╥)o o(╥﹏╥)o o(╥﹏╥)o </p>
</div>
</template>
<template id="girl">
<div>
<h3> 这里是girl组件 </h3>
<button @click = "kick"> 揍 </button>
</div>
</template>
<script>
Vue.component('Father',{
template: '#father',
methods: {
fn () {
this.$refs.son.changeFlag() //获得son组件,通过this.$refs.son访问
}
}
})
Vue.component('Son',{
template: '#son',
data () {
return {
flag: false
}
},
methods: {
changeFlag () {
this.flag = !this.flag
}
}
})
Vue.component('Girl',{
template: '#girl',
methods: {
kick () {
this.$emit('fn') //调用父组件中的fn方法
}
}
})
new Vue({
el: '#app'
})
</script>
- 自己的数据自己更改,son组件中的flag需要用son组件中的方法changeFlag修改.
- 属性绑定,父组件获得son组件
- 父组件中定义一个方法fn,调用son组件中的changeFlag方法,用$refs
- Girl组件通过方法调用this.$emit(‘fn’)调用父组件中的fn方法,修改son组件中的flag数据
- bus事件总线
//html部分与上方一样
var bus = new Vue() //定义全局bus
Vue.component('Father',{
template: '#father'
})
Vue.component('Son',{
template: '#son',
data () {
return {
flag: false
}
},
mounted () { // 也是一个选项,表示组件挂载结束 , 也就是说我们可以在View视图中看到这个组件了
// bus.$on(自定义事件名称,执行的事件处理程序)
var _this = this
bus.$on('cry',function () {
_this.flag = true
})
}
})
Vue.component('Girl',{
template: '#girl',
methods: {
kick () {
bus.$emit('cry') //调用cry方法
}
}
})
new Vue({
el: '#app'
})
非常规通信方案
- 如果常规方案可以实现,尽量不要用非常规方案。
-
实现子父通信
<body> <div id="app"> <Father></Father> </div> <template id="father"> <div> <h3> father组件 </h3> <p> {{ gk }} </p> <Son :fn = "fn"></Son> </div> </template> <template id="son"> <div> <h3> son组件 </h3> <button @click = "fn( money )"> 给红包 </button> </div> </template> </body> <script> // 父组件通过 v-bind 绑定一个方法给子组件 // 子组件通过 props选项接收这个方法,然后直接调用 Vue.component('Father',{ template: '#father', data () { return { gk: 0 } }, methods: { fn ( val ) { this.gk = val } } }) Vue.component('Son',{ template: '#son', data () { return { money: 1000 } }, props: ['fn'] //获得上方绑定的fn方法 }) new Vue({ el: '#app' }) </script>
-
父组件 通过 v-bind 绑定 一个对象类型数据 给子组件
- 子组件直接使用,如果更改这个数据,那么父组件数据也更改了
- 违背了单向数据流
Vue.component('Father',{ template: '#father', data () { return { money: { num: 1000 } } } }) Vue.component('Son',{ template: '#son', props: ['money'] })
插槽(slot)
普通插槽
<div id="app">
<Hello>
<!-- 电脑要加的内存条 -->
<p> 这是组件的内容 </p>
</Hello>
</div>
<template id="hello">
<div>
<h3> hello </h3>
<p> 又是嗨的一天 </p>
<!-- 电脑中的卡槽 -->
<slot></slot>
</div>
</template>
具名插槽
<div id="app">
<Hello>
<!-- 电脑要加的内存条 -->
<header slot = "header"> 头部 </header>
<footer slot = "footer"> 底部 </footer>
</Hello>
</div>
<template id="hello">
<div>
<slot name = 'header'></slot>
<h3> hello </h3>
<p> 又是嗨的一天 </p>
<!-- 电脑中的卡槽 -->
<slot name = "footer"></slot>
</div>
</template>
-
以上内容是Vue 2.5.x的版本
-
Vue 2.6以上使用v-slot
- 作用:可以将组件的数据在组件的内容中使用
<div id="app"> <Hello> <!-- 此处对应下方name属性 --> <template v-slot:xxx = "slotProps"> <div> {{ slotProps.msg }} </div> </template> </Hello> </div> <template id="hello"> <div> <h3> hello </h3> <p> 又是嗨的一天 </p> <slot :msg = "msg" name = "xxx"></slot> </div> </template>
过渡效果
Vue框架使用css3过渡效果或是js动画
Vue内部提供了一个叫做transition的过渡组件
使用transition包裹过渡元素,那么会自动添加 6 个类名 8个钩子函数
- 默认 类名 开头 v
- 如果有name属性,那么使用 这个name属性值作为类名开头
<div id="app">
<button @click = "flag = !flag"> 点击 </button>
<transition name = "slide-fade">
<p v-if = "flag"> 动画元素 </p>
</transition>
</div>
实现方式
-
第一种 [ 在 CSS 过渡和动画中自动应用 class 【 自己写 】 ]
-
第二种: animate.css 【 推荐 】第三方css动画库
<!-- 需引入animate --> <div id="app"> <button @click = "flag = !flag"> 点击 </button> <transition name = "slide-fade" enter-active-class = "animated bounceIn" leave-active-class = "animated bounceOut" > <p v-if = "flag"> 动画元素 </p> </transition> </div>
-
第三种: Vue提供了8个javascript钩子,我们需要自定义js动画
-
第四种: 使用第三方插件: Velocity.js
自定义指令
<body>
<div id="app">
<input type="text" placeholder="请输入" v-focus = "1000">
</div>
</body>
<script>
// Vue.directive(自定义指令名称,选项)
Vue.directive('focus',{
bind (el,binding,vnode,oldVnode) { // 当自定义指令和元素绑定时触发
},
inserted ( el,binding,vnode,oldVnode ) { // 当自定义指令绑定的元素插入到页面时触发
//初始值为v-focus的属性值
el.value = binding.expression
// 页面开启时自动获得焦点
el.focus()
},
updated () { // 当自定义指令的元素或是他的子元素发生变化式触发
},
componentUpdate () { //当自定义指令的元素或是他的虚拟子节点 发生变化式触发
},
unbind () { // 当自定义指令绑定的元素解绑时触发
}
})
new Vue({
el: '#app',
//上方是全局写法,此处是局部定义
directives: {
'focus': {
bind () {
},
inserted ( el ) {
el.focus()
}
}
}
})
</script>
过滤器
作用:对已有的数据做数据格式化 。
-
使用格式:
- 已有数据 | 过滤器名称(arg1,arg2)
<img :src = "item.img | imgFilter " >
- | 称为管道符
-
定义
// Vue.filter(过滤器名称,function ( val ) {})
// 全局定义
Vue.filter('imgFilter',function ( val ) {
//val就是需要格式化的数据
return val.replace( reg, '……') // 要替换的数据内容
})
new Vue({
el: '#app',
data: {
lists: []
},
filters: { //局部定义
// 过滤器名称:function () {}
'imgFilter': function ( val ) {
return val.replace( reg, '……') // 要替换的数据内容
}
},
methods: {
getList () {
fetch('./data/list.json')
.then( res => res.json())
.then( data => {
this.lists = data.movieList
})
.catch( error => console.log( error ))
}
}