Vue实例的生命周期
生命周期:从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称生命周期 生命hz周期钩子:生命周期事件的别名而已
组件创建期间的4个钩子函数
beforeCreate
:实例刚在内存中被创建出来,此时,还没有初始化好 data和methods属性created
:实例已经在内存中创建好,此时data和methods也已经创建好。但,此时还没有开始编译模板beforeMount
:此时已经完成了模板编译,但是还没有挂载到页面中mounted
:此时,已将将编译好的模板,挂载到页面指定的容器中显示。它是实例创建期间的最后一个生命周期函数,当执行完mounted就表示实例已经被完全创建好了。此时,如果没有其他操作的话,这个实例就在内存中。此时,组件脱离了创建阶段,进入运行阶段。所以,如果要操作页面上的DOM 节点,最早可以在mounted中进行。
组件运行阶段的钩子函数
-
beforeUpdate
:状态更新之前执行此函数,此时data中的状态值是最新的,但是页面上显示的数据还是旧的,因此此时还没有开始重新渲染DOM节点 -
updated
:实例更新完毕之后调用此函数,此时data中的状态值和页面上显示的数据,都已经完成了更新,页面也已经被重新渲染好了 这两个事件,会根据data数据的改变,有选择的触发0次或多次。
组件销毁阶段的钩子函数
beforeDestory
:实例销毁之前调用。在这一步,实例(包括:过滤器、指令、Data、methods等)仍然完全可用。
destoryed
:Vue实例销毁之后调用。调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
例如: v-if 绑定了一个Data的值是true, 通过调用方法,设置为false,此时会执行销毁钩子函数。
用户离开页面的时候,也会调用
//通常用来销毁一些监听事件和定时函数:
destroyed() {
window.removeEventListener('resize', this.resizeWin)
}
你也可以手动调用 $destoryed
进行销毁。
Vue 组件
组件ed 出现,是为了拆分Vue实例的代码量,能够让我们以不同的组件,来划分不同的功能模块,将来需要什么样的功能,就可以去调用对应的组件即可。
- 模块化:从代码逻辑的角度进行划分,方便代码的分层开发,保证每个功能模块的职能单一;
- 组件化:从UI界面的角度进行划分,方便UI组件的重用;
全局组件定义的三种方式
(1)使用Vue.extend来创建全局的Vue组件
代码语言:javascript复制var com1 = Vue.extend({
template: '<h3>使用Vue.extend创建的组件</h3>' //指定组件要展示的html结构
})
//使用Vue.component('组件名称',创建出来的组件模板对象)
//如果使用 Vue.component定义全局组件的时候,组件名称使用了 驼峰命名,则在引用组件的时候,需要把大写的驼峰改成小写的字母,同时,两个单词之间,使用 '-'连接;
//如果不使用 驼峰,则直接拿名称来使用即可;
Vue.component('myCom1',com1);
Vue.component('mycom1',com1);//不使用驼峰
代码语言:javascript复制<div id="app">
<!--如果要使用组件,直接把组件名称以html标签的形式,引入到页面中,名称以小写加'-'连接命名-->
<my-com1></my-com1>
<!--<mycom1></mycom1>不使用驼峰的方式-->
</div>
合并使用: Vue.component 第一个参数:组件名称,将来在引用组件的时候,就是一个标签形式来引入它的;第二个参数:Vue.extend创建的组件,其中template就是组件要展示的HTML内容
代码语言:javascript复制Vue.component('mycom1',Vue.extend({
template: '<h3>使用Vue.extend创建的组件</h3>'
}))
- (2)字面量对象
Vue.component('mycom2',{
//注意:不论哪种方式创建出来的组件,组件的template属性指向的模板内容,必须有且只有唯一一个根元素
template: '<div><h3>使用Vue.component创建的组件</h3><span>123</spann></div>'
})
代码语言:javascript复制<mycom2></mycom2>
- (3)template元素
Vue.component('mycom3',{
template: '#tmp1'
})
代码语言:javascript复制<div id="app">
<mycom3></mycom3>
</div>
//在被控制的 #app 外面,使用 template 元素,定义组件的html模板结构
<template id="tmp1">
<div>
<h1>
通过template元素,在外部定义的组件结构
</h1>
</div>
</template>
定义实例内部私有组件
components属性
代码语言:javascript复制var vm = new Vue({
el: '#app1',
components: {
login: {
template: '<h1>app1的私有组件login</h1>'//可将其使用<template></template>方式定义
}
}
})
代码语言:javascript复制<div id="app1">
<login></login>
</div>
组件里的data要定义为一个function
- 组件可以有自己的data
- 组件的data和实例的data有点不同,实例中的data可以为一个对象,但是组件中的data必须是一个方法,为了保持组件之间的独立性
- 组件中的data除了必须为一个方法,还必须返回一个对象
- 组件的data数据,使用方式和实例的方式一样
Vue.component('mycom1',{
template: '<h1>{{msg}}</h1>',//使用data
data: function() {
return {
msg: '组件中的data'
}
},
methods: {
add() {
}
}
})
组件切换的方式
(1)指令方式 v-if, v-else
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
<script src="../lib/vue.js"></script>
</head>
<body>
<div id="app">
<a @click.prevent="flag=true">登录</a>
<a @click.prevent="flag=false">注册</a>
<login v-if="flag"></login>
<register v-else="flag"></register>
</div>
<script>
Vue.component('login',{
template: '<h3>登录组件</h3>'
})
Vue.component('register',{
template: '<h3>注册组件</h3>'
})
var vm = new Vue({
el: '#app',
data: {
flag: true
}
})
</script>
</body>
</html>
(2)使用vue 提供 component 来展示对应名称的组件
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
<script src="../lib/vue.js"></script>
</head>
<body>
<div id="app">
<a @click.prevent="flag='login'">登录</a>
<a @click.prevent="flag='register'">注册</a>
<!-- vue 提供 component 来展示对应名称的组件 -->
<!-- component 是一个占位符, :is 属性,可以用来指定要展示的组件的名称 -->
<component :is="comName"></component>
</div>
<script>
Vue.component('login',{
template: '<h3>登录组件</h3>'
})
Vue.component('register',{
template: '<h3>注册组件</h3>'
})
var vm = new Vue({
el: '#app',
data: {
comName: 'login'
}
})
</script>
</body>
</html>
组件切换动画 < transition >及其mode属性
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
<script src="../lib/vue.js"></script>
<style>
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(150px);
}
.v-enter-active,
.v-leave-active {
transition: all .5s ease;
}
</style>
</head>
<body>
<div id="app">
<a @click.prevent="flag='login'">登录</a>
<a @click.prevent="flag='register'">注册</a>
<!-- 通过 mode 属性设置组件切换时候的模式 -->
<transition mode="out-in">
<component :is="flag"></component>
</transition>
</div>
<script>
Vue.component('login',{
template: '<h3>登录组件</h3>'
})
Vue.component('register',{
template: '<h3>注册组件</h3>'
})
var vm = new Vue({
el: '#app',
data: {
flag: 'login'
}
})
</script>
</body>
</html>
Vue 把一个完整的动画,使用钩子函数,拆分为两部分。
父子组件之间的传值
(1)父组件向子组件传值
- 父组件中使用v-bind属性绑定
- 子组件中使用props定义父组件传递过来的名称
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
<script src="../lib/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 父组件,可以在引用子组件的时候,通过属性绑定的(v-bind:)形式,把需要传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用 -->
<com1 v-bind:parentmsg="msg"></com1>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: '父组件数据'
},
methods: {},
components: {
com1: {
// 注意:组件中所有props中的数据,都是通过父组件传递给子组件的
//props中的数据,都是只读的,重新赋值会报错。建议放在data属性中
props: ['parentmsg'],//把父组件传递过来的parentmsg属性,先在props数组中定义,才能使用这个数据
template: '<h1>这是子组件 --- {{ parentmsg }} </h1>'
}
}
})
</script>
</body>
</html>
(2)父组件把方法传递给子组件:通过事件调用方式
- 事件绑定机制
- 子组件方法中使用
this.$emit('name',参数列表)
调用父组件方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
<script src="../lib/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 父组件向子组件传递方法,使用的是事件绑定机制:v-on,
当我们自定义了一个事件属性后,
那么子组件就能够通过某些方式来调用传递金曲的这个方法了 -->
<com2 v-on:func="show"></com2>
</div>
<template id="tmpl">
<div>
<h1>这是个子组件</h1>
<input type="button" value="触发父组件传递过来的func方法" @click="myclick">
</div>
</template>
<script>
// 定义一个字面量类型
var com2 = {
template: '#tmpl', //通过制定一个 ID,表示说要去加载这个制定ID的template元素中的内容,当作组件的HTML结构
data() {
return {
msg: {name:'imagincode'}
}
},
methods: {
myclick() {
//当点击子组件的按钮时候,如何拿到父组件传递过来的func方法,并调用这个方法?
//emit : 触发、调用
this.$emit('func',this.msg)//给父组件传递参数
}
},
}
var vm = new Vue({
el: '#app',
data: {
msg: '父组件数据',
datamsgFromChild: null
},
methods: {
show(data) {
console.log('调用父组件的show方法' data)
this.datamsgFromChild = data;//父组件拿到子组件传递过来的值
}
},
components: {
com2
}
})
</script>
</body>
</html>
refs 获取DOM元素和组件
ref是reference的缩写
代码语言:javascript复制<h2 id="id-h2" ref="h2el"></h2> //DOM
<Login ref="mylogin"></Login> //组件
this.$refs.h2el; //获取DOM
this.$refs.mylogin; //获取组件的引用
Watch , Methods, Computed
使用Watch监听路由地址的改变
代码语言:javascript复制watch: {
'$route.path': function(newVal,oldVal) {
console.log(oldVal '-->' newVal)
}
}
Computed 计算属性
在computed中,可以定义一些属性,这些属性,叫做【计算属性】,计算属性的本质,就是一个方法。只不过,在使用这些计算属性的时候,是把它们的名称,直接当做属性来使用,并不会把计算属性当做方法去调用
代码语言:javascript复制data: {
firstname: '',
lastname: ''
},
computed: {
'fullname': function() {
return this.firstname '-' this.lastname
}
}
- 计算属性,在引用的时候,一定不要加()去调用,直接把它当做普通属性来使用。
- 计算属性内部所用到的任何data中的数据发生了变化,就会重新计算这个属性的值。
- 计算属性的求值结果会被缓存起来,方便下次直接使用。如果计算属性方法中,所依赖的任何数据,都没有发生过变化,则不会重新对计算属性求值。
Watch , Methods, Computed的对比
computed
属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用。methods
方法表示一个具体的操作,主要用于书写业务逻辑。watch
是一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作。可以看做是computed
和methods
的结合体。