vue动画及组件

vue动画

transition

img

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./animate.min.css">
<style lang="scope">
.box{
width: 200px;
height: 200px;
background-color: pink;
}
/*
v-enter 隐藏到显示
v-enter-to 隐藏到显示的过程
v-enter-from 隐藏到
*/
.v-enter,.v-leave{
transition: 1s all;
}
</style>
</head>

<body>
<!--

-->
<div id="app">
<h1>你好 {{names}}</h1>
<button @click="isShow=!isShow">button</button>
<transition enter-to-class="animated fadeInLeft" leave-to-class="animated fadeOutRight">
<div class="box" v-show="isShow">div</div>
</transition>
</div>
<script src="./lib/vue.js"></script>
<script>
Vue.config.productionTip = false

const vm = new Vue({
el: '#app',
data: {
names: '袁同学!',
isShow: true,
}
})
</script>
</body>

</html>

动态添加li的缓动效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./animate.min.css">
</head>
<body>
<div id="app">
<h1>你好 {{names}}</h1>
<input type="text" v-model="item" @keydown.enter="add">
<ul>
<transition-group duration="1000" enter-to-class="animated fadeInLeft" leave-to-class="animated fadeOutRight" appear>
<li v-for="(v,index) in arr" :key="index">{{v}}</li>
</transition-group>
</ul>
</div>
<script src="./lib/vue.js"></script>
<script>
Vue.config.productionTip = false

const vm = new Vue({
el: '#app',
data: {
names: '袁同学!',
arr:[3,2,3,4,5],
item:''
},
methods: {
add(){
if(this.item){
this.arr.push(this.item)
}
this.item = ''
}
},
})
</script>
</body>
</html>

Vue中的组件

概述

组件是一个对象,是模块化的体现,包含了html,css,js,组件的设计是为了复用

全局组件

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<div id="app">
<!-- 将组件名当做标签名使用使用-来分割驼峰命名 -->
<!-- 可以是双标签也可以是单标签 -->
<first-component></first-component>
</div>
<script src="./lib/vue.js"></script>
<script>
Vue.config.productionTip = false
// 声明全局组件 Vue.component声明(组件名,组件内容)
let firstComponent = Vue.component('firstComponent',{
template:`
<h3>{{msg}}</h3>
`,//组件内对外暴露的标签只有一个
data(){
return {
msg:'你好!'
}
}
})

const vm = new Vue({
el: '#app',
data: {
names: '袁同学!',
}
})
</script>

局部组件

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<div id="app">
<!-- 将组件名当做标签名使用使用-来分割驼峰命名 -->
<last-component></last-component>
</div>
<script src="./lib/vue.js"></script>
<script>
Vue.config.productionTip = false

// 局部组件使用
let lastComponent = {
name:'lastComponent',
template:`
<h3>{{msg}}</h3>
`,
data(){
return{
msg:'hello'
}
},
}
const vm = new Vue({
el: '#app',
data: {
names: '袁同学!',
},
// 注册组件
components:{
// 组件名:组件对象
lastComponent
}
})
</script>

组件使用的注意事项

  • 组件内部的属性和vue实例的属性是一致的(Vue实例是最大的组件)
  • 组件内部的data是一个函数,通过对象的形式返回数据(如果是对象的形式可能会和其他组件的data产生冲突,导致对象覆盖问题,从而造成全局污染)
  • 组件内的显示利用template属性,template对外暴露的元素根节点只能有一个,否则会报错
  • 组件的使用直接把组件名当做标签名(不能使用驼峰命名法,使用-来分割驼峰)
  • 组件的使用可以是单标签也可以是双标签

组件切换

利用内置组件component中的is来切换

1
<component></component>

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<div id="app">
<h1>你好 {{names}}</h1>
<button @click="name=(name=='one'?'two':'one')">toggle</button>
<component :is="name"></component>
</div>
<script src="./lib/vue.js"></script>
<script>
Vue.config.productionTip = false
let one = {
name: 'one',
template: `
<div>组件one</div>
`
}
let two = {
name: 'two',
template: `
<div>组件two</div>
`
}
const vm = new Vue({
el: '#app',
data: {
names: '袁同学!',
name: 'one'
},
components: {
one,
two
}
})
</script>

组件之间的关系

主要关系
  • 父子关系
  • 兄弟关系
组件之间的通信
父传子(props)

利用子组件的props属性,可以接受父组件所有的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<div id="app">
<parent></parent>
</div>
<script src="./lib/vue.js"></script>
<script>
Vue.config.productionTip = false

// 准备子组件
let child = {
template:`
<h5>
{{msg}}
{{message}}
</h5>
`,
data(){
return{
msg:'子组件'
}
},

//第一种写法,里面为接收的属性名(类似于data中的数据,可以直接使用)
// props:['message'],

// 第二种写法,对象写法,可以指定默认值和类型验证(推荐写法)
props:{
message:{
default:'这是默认值default',//指定默认值
type:String//类型验证
}
}
}
let parent = {
template:`
<h3>
{{msg}}
<child :message='message'></child>
</h3>
`,
data(){
return{
msg:'父组件',
message:'来自父组件的数据'
}
},
components:{
child//在父组件中注册子组件
}
}

const vm = new Vue({
el: '#app',
data: {

},
components:{
parent//在最大的vue实例对象中注册父组件
}
})
</script>
子传父($emit)
  • 在子组件通过$emit来派发对应的事件,并传入数据
  • 父组件通过监听对应的事件执行,来获取数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<div id="app">
<parent></parent>
</div>
<script src="./lib/vue.js"></script>
<script>
Vue.config.productionTip = false

// 准备子组件
let child = {
template:`
<div>
{{msg}}
<button @click="handler">click</button>
</div>
`,
data(){
return{
msg:'子组件',
message:'来自子组件的数据'
}
},
methods: {
handler(){
// 通过执行对应的事件来传递对应的值
// 第一个参数为事件名,第二个为传递的值
this.$emit('sendMsg',this.message)
}
},
}
let parent = {
// 在父组件内,监听对的事件执行
template:`
<div>
{{msg}}
<child @sendMsg="handler"></child>{{args}}
</div>
`,
data(){
return{
msg:'父组件',
args:''
}
},
methods:{
handler(arg){
console.log(arg);
this.args = arg
}
},
components:{
child//在父组件中注册子组件
}
}

const vm = new Vue({
el: '#app',
data: {

},
components:{
parent//在最大的vue实例对象中注册父组件
}
})
</script>
总结
  • 父传子,利用属性进行传值,子组件利用props来接收
  • 如果父组件传递的是一个对象,子组件最好是利用工厂函数来返回一个新对象
  • 如果传值过程中,不希望数据被更改,则最好是利用深拷贝,传递一个全新的对象
  • 子传父,是利用观察者模式进行传值,通过$emit触发发布事件,父组件通过监听事件来获取对应的数据
兄弟组件通信(bus)

方案一:子传父,再父传子(不建议使用)

方案二:bus传值

  • 创建一个公共的bus对象(Vue实例对象)
  • 在需要传值的组件触发 bus.$emit(‘事件名’,数据)
  • 在需要数据的组件监听并接收 bus.$on(‘事件名’,(传来的数据)=>{})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<div id="app">
<first></first>
<last></last>
</div>
<script src="./lib/vue.js"></script>
<script>
Vue.config.productionTip = false
let bus = new Vue()
let first = {
template: `<div>first组件:<button @click="handler">给last组件传值</button></div>`,
data() {
return {
msg: 'first组件的数据'
}
},
methods: {
handler(){
bus.$emit('send',this.msg)
}
},
}
let last = {
template: `<div>last组件:{{arg}}</div>`,
data(){
return{
arg:''
}
},
created(){
bus.$on('send',(arg)=>{
this.arg = arg
console.log(arg);
})
}
}

const vm = new Vue({
el: '#app',
data: {
},
components: {
first,
last
}
})
</script>
provide inject传值

主要是为高阶组件/组件库提供用例,可以用于跨组件传值〈不建议使用),必须基于父子关系〈不管嵌套多少级都传值)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<div id="app">
<parent>

</parent>
</div>
<script src="./lib/vue.js"></script>
<script>
Vue.config.productionTip = false

let child = {
template: `<div>child:{{msg}}</div>`,
inject: ['msg']
}
let parent = {
template: `<div>parent<child></child></div>`,
components: {
child
}

}
const vm = new Vue({
el: '#app',
data: {
msg: 'hello'
},
components: {
parent
},
provide() {
return {
msg: this.msg,
getValue:function(){

}
}
}
})
</script>
ref传值

ref传值主要传递的是当前的组件

ref如果是用于普通的dom元素,那么接受的就是普通的dom对象,如果是组件,则接受的是组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<div id="app">
<child ref="child"></child>
<p ref="ele"></p>
</div>
<script src="./lib/vue.js"></script>
<script>
Vue.config.productionTip = false
let child = {
template:`<div>child组件</div>`,
data(){
return{
msg:'传递的数据',
}
}
}
const vm = new Vue({
el: '#app',
data: {
names: '袁同学!',
value:''
},
components:{
child
},
mounted() {
// 直接获取了整个vue组件和dom
console.log(this.$refs.child.msg,this.$refs.ele);
},
})
</script>