# 第三章 Vue脚手架

# 初始化脚手架

# 说明

  1. Vue 脚手架是 Vue官方提供的标准化开发工具 (开发平台)。

  2. 最新的版本是 4 .x。

  3. 文档: https://cli.vuejs.org/zh/ (opens new window)

# 具体步骤

第一步 (仅第一次执行):全局安装@vue/cli。

npm install -g @vue/cli
1

第二步 :切换到你要创建项目的目录 ,然后使用命令创建项目

vue create xxxx
1

第三步 :启动项目

npm run serve
1

备注:

  1. 如出现下载缓慢请配置 npm 淘宝镜像 :npm config set registry https://registry.npm.taobao.org
  2. Vue 脚手架隐藏了所有webpack 相关的配置 ,若想查看具体的webpakc配置,请执行:vue inspect > output.js

关于不同版本的Vue:

  1. vue.js与vue.runtime.xxx.js的区别:

​ (1) vue.js是完整版的Vue,包含:核心功能+模板解析器。

​ (2) vue.runtime.xxx.js是运行版的Vue,只包含:核心功能,没有模板解析器。

  1. 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容。

# 模板项目的结构

├── node_modules
├── public
│    ├── favicon.ico: 页签图标
│    └── index.html: 主页面
├── src
│    ├── assets: 存放静态资源
│    │    └── logo.png
│    │── component: 存放组件
│    │    └── HelloWorld.vue
│    │── App.vue: 汇总所有组件
│    │── main.js: 入口文件
├── .gitignore: git 版本管制忽略的配置
├── babel.config.js: babel 的配置文件
├── package.json: 应用包配置文件
├── README.md: 应用描述文件
├── package-lock.json:包版本控制文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# ref 与 props

# ref属性

作用: 用于给节点打标识

读取方式:this.$refs.xxx

案例:

点击查看代码
// App.vue
<template>
	<div>
		<h1 v-text="msg" ref="title"></h1>
		<button ref="btn" @click="showDOM">点我输出上方的DOM元素</button>
		<Website ref="sch"/>
	</div>
</template>

<script>
	//引入Website组件
	import Website from './components/Website'

	export default {
		name:'App',
		components:{ Website },
		data() {
			return {
				msg:'欢迎学习Vue!'
			}
		},
		methods: {
			showDOM(){
				console.log(this.$refs.title) //真实DOM元素
				console.log(this.$refs.btn) //真实DOM元素
				console.log(this.$refs.sch) //School组件的实例对象(vc)
			}
		},
	}
</script>

// Website.vue
<template>
	<div class="website">
		<h2>网站名称:{{name}}</h2>
		<h2>网站地址:{{address}}</h2>
	</div>
</template>

<script>
	export default {
		name:'Website',
		data() {
			return {
				name:'凹凸学习',
				address:'https://aotuxx.cn'
			}
		},
	}
</script>

<style>
	.website{
		background-color: orange;
	}
</style>
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

# props配置

作用: 用于父组件给子组件传递数据

读取方式一: 只指定名称

props: ['name', 'age', 'setName']
1

读取方式二: 指定名称和类型

props: {
    name: String,
    age: Number,
    setNmae: Function
}
1
2
3
4
5

读取方式三: 指定名称、类型 、必要性、默认值

props: {
	name: {
		type: String, 
		required: true, 
		default: ''
	}
}

1
2
3
4
5
6
7
8

案例:

点击查看代码
// App.vue
<template>
	<div>
		<Blogger name="凹凸曼" sex="" :age="18"/>
	</div>
</template>

<script>
	import Blogger from './components/Blogger'

	export default {
		name:'App',
		components:{Blogger}
	}
</script>

// Blogger.vue
<template>
	<div>
		<h1>{{msg}}</h1>
		<h2>姓名:{{name}}</h2>
		<h2>性别:{{sex}}</h2>
		<h2>年龄:{{myAge+1}}</h2>
		<button @click="updateAge">尝试修改收到的年龄</button>
	</div>
</template>

<script>
	export default {
		name:'Blogger',
		data() {
			console.log(this)
			return {
				msg:'我是凹凸学习站长',
				myAge:this.age
			}
		},
		methods: {
			updateAge(){
				this.myAge++
			}
		},
		//简单声明接收
		// props:['name','age','sex'] 

		//接收的同时对数据进行类型限制
		/* props:{
			name:String,
			age:Number,
			sex:String
		} */

		//接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
		props:{
			name:{
				type:String, //name的类型是字符串
				required:true, //name是必要的
			},
			age:{
				type:Number,
				default:99 //默认值
			},
			sex:{
				type:String,
				required:true
			}
		}
	}
</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
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
65
66
67
68
69

# 混入

混入 (opens new window) (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

例子:

export const mixin = {
	methods: {
		showName(){
			alert(this.name)
		}
	},
	mounted() {
		console.log('你好啊!')
	},
}
export const mixin2 = {
	data() {
		return {
			x:100,
			y:200
		}
	},
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

局部使用:

new Vue({
    mixins: [mixin],
    methods: {}
})
1
2
3
4

全局使用:

Vue.mixin(mixin)
Vue.mixin(mixin2)
1
2

请谨慎使用全局混入,因为它会影响每个单独创建的 Vue 实例 (包括第三方组件)。大多数情况下,只应当应用于自定义选项,就像上面示例一样。推荐将其作为插件发布,以避免重复应用混入。

# 插件

  1. Vue 插件是一个包含 install 方法的对象

  2. 通过 install 方法给 Vue或 Vue实例添加方法, 定义全局指令等

例子:

plugins.js

点击查看代码
const permission = 'china'

export default {
  install(Vue, p1, p2, p3) {
    
    // console.log(Vue)
    console.log(p1, p2, p3)

    // 全局过滤器
    Vue.filter('mySubstr', function(value) {
      return value.slice(0, 5)
    })

    // 定义全局指令
    Vue.directive('permission', {
      // 指令与元素成功绑定时调用
      bind(el, binding) {
        // console.log('bind', binding)
        // console.log('directive中的this', this)
        const { value } = binding
        if (!value.includes(permission)) {
          el.remove()
        }
      },
      // 指令所在元素被插入页面时调用
      inserted(el, binding) {
        // console.log('inserted', binding)
        const { value } = binding
        if (!value.includes(permission)) {
          el.remove()
        }
      },
      // 指令所在的模板被重新解析时调用
      update(el, binding) {
        // console.log('update', binding)
      }
    })

    // 定义混入
    Vue.mixin({
      data() {
        return {
          cn: '我是中国人,我爱中国!'
        }
      }
    })

    //给Vue原型上添加一个方法(vm和vc就都能用了)
	Vue.prototype.say = ()=>{alert('我是中国人,我爱中国!')}
  }
}
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

main.js

import Vue from 'vue'
import App from './App.vue'
// 引入插件
import plugins from './plugins'

Vue.config.productionTip = false

// 使用插件
Vue.use(plugins, 1, 2, 3)

new Vue({
  render: h => h(App),
}).$mount('#app')
1
2
3
4
5
6
7
8
9
10
11
12
13

App.vue

点击查看代码
<template>
  <div id="app">
    <h1>{{cn | mySubstr}}</h1>
    <school name="北大" address="北京" />
    <hr>
    <student name="韦神" sex=""></student>
    <student name="韦神" sex=""></student>
    <button v-permission="['china']" @click="say">犯我中华者虽远必诛</button>
  </div>
</template>

<script>
import School from './components/school'
import Student from './components/student'

export default {
  name: 'App',
  components: {
    School,
    Student
  },
  mounted() {
    console.log('App...');
  },
}
</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

School.vue

点击查看代码
<template>
  <div>
    <h1>学校:{{name}}</h1>
    <h1>地址:{{address}}</h1>
  </div>
</template>

<script>

export default {
  name: 'School',
  props: ['name', 'address'],
  data() {
    return {
      c: 'C'
    }
  },
  mounted() {
    console.log('School...');
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Student.vue

点击查看代码
<template>
  <div>
    <h1>姓名:{{name}}</h1>
    <h1>性别:{{sex}}</h1>
  </div>
</template>

<script>

export default {
  name: 'Student',
  props: ['name', 'sex'],
  data() {
    return {
      b: 'B'
    }
  },
  mounted() {
    console.log('Student...');
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# scoped样式

单文件组件 (opens new window)让你可以在同一个文件里完全控制 CSS,将其作为组件代码的一部分。

<style scoped>
  @media (min-width: 250px) {
    .list-container:hover {
      background: orange;
    }
  }
</style>
1
2
3
4
5
6
7

这个可选 scoped attribute 会自动添加一个唯一的 attribute (比如 data-v-21e5b78) 为组件内 CSS 指定作用域,编译的时候 .list-container:hover 会被编译成类似 .list-container[data-v-21e5b78]:hover

最后,Vue 的单文件组件里的样式设置是非常灵活的。通过 vue-loader,你可以使用任意预处理器、后处理器,甚至深度集成 CSS Modules——全部都在 <style> 标签内。

# 组件化编码流程

  1. 实现静态组件 :抽取组件 ,使用组件实现静态页面效果

  2. 展示动态数据 :

    a 数据的类型、名称是什么?

    b 数据保存在哪个组件?

  3. 交互——从绑定事件监听开始

# 浏览器本地存储

浏览器本地存储提供两个(localStoragesessionStorage)存储数据的对象。

共同特点:两者中的键值对总是以字符串的形式存储。

区别在于:存储在 localStorage 的数据可以长期保留;而当页面会话结束——也就是说,当页面被关闭时,存储在 sessionStorage 的数据会被清除 。

# localStorage

// 存字符串
localStorage.setItem('msg','hello,vue')
// 取数据
localStorage.getItem('msg')

// 存对象
let person = { name:'aotuman', age: 18 }
// 需要将对象转为json字符串存储
localStorage.setItem('person', JSON.stringify(person))
// 取出来的值时json字符串
const result = localStorage.getItem('person')
// 将json字符串转化为对象
const p = JSON.parse(result)
1
2
3
4
5
6
7
8
9
10
11
12
13

# sessionStorage

// 存字符串
sessionStorage.setItem('msg','hello,vue')
// 取数据
sessionStorage.getItem('msg')

// 存对象
let person = { name:'aotuman', age: 18 }
// 需要将对象转为json字符串存储
sessionStorage.setItem('person', JSON.stringify(person))
// 取出来的值时json字符串
const result = sessionStorage.getItem('person')
// 将json字符串转化为对象
const p = JSON.parse(result)
1
2
3
4
5
6
7
8
9
10
11
12
13

# Vue中的自定义事件

# 绑定事件监听

<Header @addTodo="addTodo"/>
// 或者
<Header ref="header"/>
this.$refs.header.$on('addTodo', this.addTodo)

1
2
3
4
5

# 触发事件

this.$emit('addTodo', todo)
1

# 案例

App.vue

点击查看代码
<template>
	<div class="app">
		<h1>{{msg}},学生姓名是:{{studentName}}</h1>

		<!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
		<School :getSchoolName="getSchoolName"/>

		<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on) -->
		<!-- <Student @aotuxx="getStudentName" @demo="m1"/> -->

		<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) -->
		<Student ref="student" @click.native="show"/>
	</div>
</template>

<script>
	import Student from './components/Student'
	import School from './components/School'

	export default {
		name:'App',
		components:{School,Student},
		data() {
			return {
				msg:'你好啊!',
				studentName:''
			}
		},
		methods: {
			getSchoolName(name){
				console.log('App收到了学校名:',name)
			},
			getStudentName(name,...params){
				console.log('App收到了学生名:',name,params)
				this.studentName = name
			},
			m1(){
				console.log('demo事件被触发了!')
			},
			show(){
				alert(123)
			}
		},
		mounted() {
			this.$refs.student.$on('aotuxx', this.getStudentName) //绑定自定义事件
			// this.$refs.student.$once('aotuxx',this.getStudentName) //绑定自定义事件(一次性)
		},
	}
</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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

Student.vue

点击查看代码
<template>
	<div class="student">
		<h2>学生姓名:{{name}}</h2>
		<h2>学生性别:{{sex}}</h2>
		<h2>当前求和为:{{number}}</h2>
		<button @click="add">点我number++</button>
		<button @click="sendStudentlName">把学生名给App</button>
		<button @click="unbind">解绑aotuxx事件</button>
		<button @click="death">销毁当前Student组件的实例(vc)</button>
	</div>
</template>

<script>
	export default {
		name:'Student',
		data() {
			return {
				name:'张三',
				sex:'男',
				number:0
			}
		},
		methods: {
			add(){
				console.log('add回调被调用了')
				this.number++
			},
			sendStudentlName(){
				//触发Student组件实例身上的atguigu事件
				this.$emit('aotuxx',this.name,666,888,900)
				// this.$emit('demo')
				// this.$emit('click')
			},
			unbind(){
				this.$off('aotuxx') //解绑一个自定义事件
				// this.$off(['aotuxx','demo']) //解绑多个自定义事件
				// this.$off() //解绑所有的自定义事件
			},
			death(){
				this.$destroy() //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效。
			}
		},
	}
</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
33
34
35
36
37
38
39
40
41
42
43
44

School.vue

点击查看代码
<template>
	<div class="school">
		<h2>学校名称:{{name}}</h2>
		<h2>学校地址:{{address}}</h2>
		<button @click="sendSchoolName">把学校名给App</button>
	</div>
</template>

<script>
	export default {
		name:'School',
		props:['getSchoolName'],
		data() {
			return {
				name:'清华大学',
				address:'北京',
			}
		},
		methods: {
			sendSchoolName(){
				this.getSchoolName(this.name)
			}
		},
	}
</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

# 全局事件总线

# 理解

  1. Vue 原型对象上包含事件处理的方法

(1)$on(eventName, listener): 绑定自定义事件监听

(2)$emit(eventName, data): 分发自定义事件

(3)$off(eventName): 解绑自定义事件监听

(4)$once(eventName, listener): 绑定事件监听,但只能处理一次

  1. 所有组件实例对象的原型对象的原型对象就是 Vue的原型对象

(1)所有组件对象都能看到 Vue原型对象上的属性和方法

(2)Vue.prototype.$bus = new Vue(),所有的组件对象都能看到$bus这个属性对象

  1. 全局事件总线

(1)包含事件处理相关方法的对象(只有一个)

(2)所有的组件都可以得到

# 指定事件总线对象

new Vue({
    beforeCreate () { // 尽量早的执行挂载全局事件总线对象的操作
    	Vue.prototype.$globalEventBus = this
    },
}).$mount('#root')

1
2
3
4
5
6

# 绑定事件

this.$globalEventBus.$on('deleteTodo', this.deleteTodo)
1

# 分发事件

this.$globalEventBus.$emit('deleteTodo', this.index)
1

# 解绑事件

this.$globalEventBus.$off('deleteTodo')
1

# 案例

main.js:安装全局事件总线

new Vue({
	el:'#app',
	render: h => h(App),
	beforeCreate() {
		Vue.prototype.$bus = this //安装全局事件总线
	},
})
1
2
3
4
5
6
7

School.vue:绑定事件

点击查看代码
<template>
	<div class="school">
		<h2>学校名称:{{name}}</h2>
		<h2>学校地址:{{address}}</h2>
	</div>
</template>

<script>
	export default {
		name:'School',
		data() {
			return {
				name:'凹凸学校',
				address:'北京',
			}
		},
		mounted() {
			// console.log('School',this)
			this.$bus.$on('hello',(data)=>{
				console.log('我是School组件,收到了数据',data)
			})
		},
		beforeDestroy() {
             // 解绑事件	
			this.$bus.$off('hello')
		},
	}
</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

Student.vue:分发事件

点击查看代码
<template>
	<div class="student">
		<h2>学生姓名:{{name}}</h2>
		<h2>学生性别:{{sex}}</h2>
		<button @click="sendStudentName">把学生名给School组件</button>
	</div>
</template>

<script>
	export default {
		name:'Student',
		data() {
			return {
				name:'张三',
				sex:'男',
			}
		},
		mounted() {
			// console.log('Student',this.x)
		},
		methods: {
			sendStudentName(){
				this.$bus.$emit('hello', this.name)
			}
		},
	}
</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

# 消息订阅与发布

# 理解

  1. 这种方式的思想与全局事件总线很相似

  2. 它包含以下操作:

    (1) 订阅消息——对应绑定事件监听

    (2) 发布消息——分发事件

    (3) 取消消息订阅——解绑事件监听

  3. 需要引入一个消息订阅与发布的第三方实现库: PubSubJS (opens new window)

# 使用PubSubJS

  1. 在线文档: https://github.com/mroderick/PubSubJS

  2. 下载: npm install -S pubsub-js

  3. 相关语法

    (1) import PubSub from 'pubsub-js' // 引入

    (2) PubSub.subscribe('msgName', functon(msgName, data){ })

    (3) PubSub.publish('msgName', data): 发布消息, 触发订阅的回调函数调用

    (4) PubSub.unsubscribe(token): 取消消息的订阅

# 案例

消息在兄弟组件School和Student上传递。

School.vue

点击查看代码
<template>
	<div class="school">
		<h2>学校名称:{{name}}</h2>
		<h2>学校地址:{{address}}</h2>
	</div>
</template>

<script>
	import pubsub from 'pubsub-js'
	export default {
		name:'School',
		data() {
			return {
				name:'凹凸学校',
				address:'北京',
			}
		},
		mounted() {
			// console.log('School',this)
			/* this.$bus.$on('hello',(data)=>{
				console.log('我是School组件,收到了数据',data)
			}) */
			this.pubId = pubsub.subscribe('hello', (msgName, data) => {
				console.log(this)
				// console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)
			})
		},
		beforeDestroy() {
			// this.$bus.$off('hello')
			pubsub.unsubscribe(this.pubId)
		},
	}
</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
33

Student.vue

点击查看代码
<template>
	<div class="student">
		<h2>学生姓名:{{name}}</h2>
		<h2>学生性别:{{sex}}</h2>
		<button @click="sendStudentName">把学生名给School组件</button>
	</div>
</template>

<script>
	import pubsub from 'pubsub-js'
	export default {
		name:'Student',
		data() {
			return {
				name:'张三',
				sex:'男',
			}
		},
		mounted() {
			// console.log('Student',this.x)
		},
		methods: {
			sendStudentName(){
				// this.$bus.$emit('hello',this.name)
				pubsub.publish('hello', 666)
			}
		},
	}
</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

# 过度与动画

# vue动画的理解

  1. 操作 css 的 trasition 或 animation

  2. vue 会给目标元素添加/移除特定的 class

  3. 过渡的相关类名 :

    (1)xxx-enter-active: 指定显示的 transition

    (2) xxx-leave-active: 指定隐藏的 transition

    (3)xxx-enter/xxx-leave-to: 指定隐藏时的样式

# 基本过渡动画的编码

  1. 在目标元素外包裹<transition name="xxx">

  2. 定义 class 样式

    a) 指定过渡样式: transition

    b) 指定隐藏时的样式: opacity/其它

# 案例:

App.vue

点击查看代码

<template>
	<div>
		<Test/>
		<Test2/>
		<Test3/>
	</div>
</template>

<script>
	import Test from './components/Test'
	import Test2 from './components/Test2'
	import Test3 from './components/Test3'

	export default {
		name:'App',
		components:{Test,Test2,Test3},
	}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Test.vue

点击查看代码
<template>
	<div>
		<button @click="isShow = !isShow">显示/隐藏</button>
		<transition name="hello" appear>
			<h1 v-show="isShow">你好啊!</h1>
		</transition>
	</div>
</template>

<script>
	export default {
		name:'Test',
		data() {
			return {
				isShow:true
			}
		},
	}
</script>

<style scoped>
	h1{
		background-color: orange;
	}

	.hello-enter-active{
		animation: atguigu 0.5s linear;
	}

	.hello-leave-active{
		animation: atguigu 0.5s linear reverse;
	}

	@keyframes atguigu {
		from{
			transform: translateX(-100%);
		}
		to{
			transform: translateX(0px);
		}
	}
</style>
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

Test2.vue

点击查看代码
<template>
	<div>
		<button @click="isShow = !isShow">显示/隐藏</button>
		<transition-group name="hello" appear>
			<h1 v-show="!isShow" key="1">欢迎您!</h1>
			<h1 v-show="isShow" key="2">凹凸学习</h1>
		</transition-group>
	</div>
</template>

<script>
	export default {
		name:'Test',
		data() {
			return {
				isShow:true
			}
		},
	}
</script>

<style scoped>
	h1{
		background-color: orange;
	}
	/* 进入的起点、离开的终点 */
	.hello-enter,.hello-leave-to{
		transform: translateX(-100%);
	}
	.hello-enter-active,.hello-leave-active{
		transition: 0.5s linear;
	}
	/* 进入的终点、离开的起点 */
	.hello-enter-to,.hello-leave{
		transform: translateX(0);
	}

</style>
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

Test3.vue

点击查看代码
<template>
	<div>
		<button @click="isShow = !isShow">显示/隐藏</button>
		<transition-group 
			appear
			name="animate__animated animate__bounce" 
			enter-active-class="animate__swing"
			leave-active-class="animate__backOutUp"
		>
			<h1 v-show="!isShow" key="1">个人学习网站</h1>
			<h1 v-show="isShow" key="2">凹凸学习 [https://aotuxx.cn]</h1>
		</transition-group>
	</div>
</template>

<script>
	import 'animate.css'
	export default {
		name:'Test',
		data() {
			return {
				isShow:true
			}
		},
	}
</script>

<style scoped>
	h1{
		background-color: orange;
	}
	
</style>
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