组件的概念
组件是一个html 、 css 、js 、img 等的一个聚合体
组件的作用
- 为了将来项目的维护、更新变得更简单
- 代码的复用
组件的拓展
通过Vue.extend()来拓展的
ƒ Vue (options) {
if (!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword');
}
this._init(options);
}
ƒ VueComponent (options) {
this._init(options);
}
组件的注册
- 全局注册
var Hello = Vue.extend({ template: '<div> hello 组件 </div>',//定义一个组件的模板 }) /* 组件的全局注册 */ // Vue.component( 组件名,组件的选项 ) /* 组件的命名: 1. 大驼峰命名法: Hello HeadTitle 2. 小写加 - : head-title 备注: 如果js中定义的是大驼峰,那么html结构中要使用小写带- */ Vue.component('Hello',Hello )
- 局部注册
var Hello = Vue.extend({ template: '<div> 晚上嗨起来 </div>' }) new Vue({ el: '#app', /* 局部注册 - components选项 */ components: { // 组件名: 组件的选项 'Hello': Hello } })
组件的选项
- components:局部注册
- template:定义组件模板
- template标签的直接子元素只能有一个
- data:数据
- 面试题: data选项为什么是函数?
- 组件是一个整体,那么它的数据也应该是独立的,函数形式可以给一个独立作用域
- 返回值为什么是对象呢?
- 我们vue特点是什么呢? 深入响应式,data选项要做劫持【 es5的Object.defineProperty的getter和setter设置 】
- 面试题: data选项为什么是函数?
- methods:方法
- computed:计算属性
- watch:侦听属性
is属性
html中哪些规定了自己的直接子元素的标签,是不能直接放组件的,但可以通过is属性来绑定。
组件的嵌套
- 全局嵌套
<body> <div id="app"> <Father></Father> </div> <template id="father"> <div> <h3> father </h3> <hr> <Son/> </div> </template> <template id="son"> <h5> son </h5> </template> </body> <script src="../../../lib/vue.js"></script> <script> /* 组件之间的嵌套要将子组件以标签化的形式放在父组件的模板中使用 */ Vue.component('Father',{ template: '#father' }) Vue.component('Son',{ template: '#son' }) new Vue({ el: '#app' }) </script>
- 局部嵌套
new Vue({ el: '#app', components: { 'Father': { template: '#father', components: { 'Son': { template: '#son' } } } } })
组件的通信
父子组件通信
父组件将自己的数据同 v-bind 绑定在 子组件身上,子组件通过 props属性接收
<body>
<div id="app">
<Father></Father>
</div>
<template id="father">
<div>
<!-- 使用单项数据绑定将一个数据绑定给一个自定义的属性 -->
<Son :aa = "money" />
</div>
</template>
<template id="son">
<div>
<p>老爸给了我 {{ aa }} 块 </p>
<p> {{ aa + 20 }} </p>
</div>
</template>
</body>
<script src="../../../lib/vue.js"></script>
<script>
Vue.component('Father',{
template: '#father',
data () {
return {
money: 4000
}
}
})
Vue.component('Son',{
template: '#son',
/* 子组件通过props选项来接收属性,接收到的属性可以像全局变量一样在组件的模板中使用 */
// props: ['aa']
/* 属性验证 - js是弱类型语言*/
props: {
// 'aa': Number // String Boolean Object Array
'aa': {
validator ( val ) {
return val > 3000
}
}
/* vue3.0使用ts,ts是强类型 */
}
})
new Vue({
el: '#app'
})
</script>
子父组件通信
通过自定义事件
<body>
<div id="app">
<Father></Father>
</div>
<template id="father">
<div>
<h1>Father</h1>
<p> 我儿子给我发了{{ sifangqian }} 块的红包 </p>
<Son @givemoney='get'></Son>
</div>
</template>
<template id="son">
<div>
<h1>Son</h1>
<button @click='give'>发红包</button>
</div>
</template>
</body>
<script src="../../lib/vue.js"></script>
<script>
Vue.component('Father', {
template: '#father',
data() {
return {
sifangqian: 0
}
},
methods: {
get(val) {
this.sifangqian = val
}
}
})
Vue.component('Son', {
template: '#son',
data() {
return {
money: 2000
}
},
methods: {
give() {
this.$emit('givemoney', this.money)
}
}
})
new Vue({
el: '#app'
})
</script>
非父子组件通信-ref绑定
<body>
<div id="app">
<Father></Father>
</div>
<template id="father">
<div>
<h1>Father</h1>
<Sister :k='getSon'></Sister>
<Son ref='son'></Son>
</div>
</template>
<template id="son">
<div>
<h1>Son</h1>
<img v-if='flag' src="https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3872048339,4140466773&fm=26&gp=0.jpg" alt="">
<img v-else src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2438534582,3797477605&fm=26&gp=0.jpg" alt="">
</div>
</template>
<template id="sister">
<div>
<h1>Sister</h1>
<button @click='hite'>hite</button>
</div>
</template>
</body>
<script src="../../lib/vue.js"></script>
<script>
Vue.component('Father', {
template: '#father',
methods: {
getSon() {
this.$refs.son.changeFlag()
}
}
})
Vue.component('Son', {
template: '#son',
data() {
return {
flag: true
}
},
methods: {
changeFlag() {
this.flag = !this.flag
}
}
})
Vue.component('Sister', {
template: '#sister',
props: ['k'],
methods: {
hite() {
this.k()
}
}
})
new Vue({
el: '#app'
})
</script>
非父子组件通信-bus总线
<body>
<div id="app">
<Father></Father>
</div>
<template id="father">
<div>
<h1>Father</h1>
<Sister></Sister>
<Son></Son>
</div>
</template>
<template id="son">
<div>
<h1>Son</h1>
<img v-if='flag' src="https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3872048339,4140466773&fm=26&gp=0.jpg" alt="">
<img v-else src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2438534582,3797477605&fm=26&gp=0.jpg" alt="">
</div>
</template>
<template id="sister">
<div>
<h1>Sister</h1>
<button @click='hite'>hite</button>
</div>
</template>
</body>
<script src="../../lib/vue.js"></script>
<script>
var bus = new Vue()
Vue.component('Father', {
template: '#father',
})
Vue.component('Son', {
template: '#son',
data() {
return {
flag: true
}
},
mounted() {
var _this = this
bus.$on('cry', function() {
_this.flag = !_this.flag
})
}
})
Vue.component('Sister', {
template: '#sister',
methods: {
hite() {
bus.$emit('cry')
}
}
})
new Vue({
el: '#app'
})
</script>
组件上实现原生事件
绑定时使用.native修饰符
<Hello :name = "name" @click.native = "changeName"></Hello>
动态组件
<!-- component是vue内置组件,并且这个组件是可以改变的 -->
<component :is = "val"></component>
动态缓存
<keep-alive :include = "val">
<component :is = "val"></component>
</keep-alive>
过渡效果
Vue框架使用css3过渡效果或是js动画
Vue内部提供了一个叫做transition的过渡组件
使用transition包裹过渡元素,那么会自动添加 6 个类名 8个钩子函数
- 默认 类名 开头 v
- 如果有name属性,那么使用 这个name属性值作为类名开头
- 实现方式
- 在 CSS 过渡和动画中自动应用 class 【 自己写 】
- 可以配合使用第三方 CSS 动画库,如 Animate.css
- 在过渡钩子函数中使用 JavaScript 直接操作 DOM
- 可以配合使用第三方 JavaScript 动画库,如 Velocity.js
- 第一种 [ 在 CSS 过渡和动画中自动应用 class 【 自己写 】 ]
- 第二种: animate.css 【 推荐 】
<div id="app"> <button @click = "changeFlag"> changeFlag </button> <!-- mode 有两个值 in-out out-in --> <transition name = "xige" mode = "in-out" enter-active-class = "animated fadeIn" leave-active-class = "animated fadeOut" > <p v-if = "flag"></p> </transition> </div>
- 第三种: Vue提供了8个javascript钩子,我们需要自定义js动画
- 第四种: 使用第三方插件: Velocity.js
过滤器
- 作用
是对已经有的数据做数据格式化 - 使用格式
已有数据 | 过滤器名称(arg1,arg2) - 定义
<body> <div id="app"> <button @click='getTime'>getTime</button> <p> {{ time | showTime('-') }} </p> </div> </body> <script src="../../lib/vue.js"></script> <script> // 全局定义 // Vue.filter('showTime', function(val, type) { // var date = new Date(val) // if (val) { // return date.getFullYear() + type + (date.getMonth() + 1) + type + date.getDate() // } else { // return '' // } // }) new Vue({ el: '#app', data: { time: '' }, methods: { getTime() { this.time = new Date() } }, // 局部定义 filters: { showTime(val, type) { var date = new Date(val) if (val) { return date.getFullYear() + type + (date.getMonth() + 1) + type + date.getDate() } else { return '' } } } })
插槽
- 普通插槽
<div id="app"> <Hello> <p> 你好 </p> </Hello> </div> <template id="hello"> <div> <h3> hello组件 </h3> <!-- 插槽,给组件的内容预留一个空间 --> <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> <slot name = "footer"></slot> </div> </template>
- 作用域插槽
<div id="app"> <Hello> <template v-slot:default = "scope"> <p> {{ scope.money }} </p> </template> </Hello> </div> <template id="hello"> <div> <slot :money = "money"></slot> </div> </template>