1. vue组件生命周期图
2. 组件生命周期函数
- 刚初始化了一个空的实例对象, 这时候只有默认的一些生命周期函数和默认事件, 其他都未创建。
- 如果要调用 methods 中的方法, 或者操作 data 中的数据, 最早只能在 created 生命周期函数中操作
// 1. 实例创建阶段
new Vue({
el: "#app",
// 在beforeCreate中,data和methods中的数据都还没有初始化
beforeCreate () {}, // 表示实例完全被创建之前, 会执行这个函数
// 在created中,data和methods中的数据都已经初始化好了
created () {} // 表示实例被创建之后, 会执行这个函数
})
// 承接备注:查看Vue生命周期图例, 这里表示Vue开始编译模板, 把Vue代码中的那些指令进行执行, 最终在内存中生成一个编译好的最终模板字符串, 然后把这个字符串渲染为内存中的DOM,此时, 只是在内存中渲染好了模板, 并没有把模板挂载到真正的页面中。
// 2. 运行期间:组件挂载和更新
new Vue({
el: "#app",
// 在beforeMounted执行时,页面中的元素还没有被真正的替换过来,只是之前写的一些模板字符串
beforeMounted () {}, // 组件挂载之前 表示模板已经编译完成,但是还没有把模板渲染到页面中
// 表示模板已经编译完成,内存中的模板已经真实的渲染到了页面中去,已经可以看到渲染好的页面了
// 注意: mounted是实例创建期间的最后一个生命周期函数,当执行完mounted生命周期函数就表示,
// 实例已经被完全创建好了,此时如果没有其他操作的话,这个实例就在内存中一动不动
// 注意: 如果要通过某些插件操作页面上的DOM节点,最早要在mounted生命周期中操作
mounted () {} // 组件挂载完成后
// 上面的是组件的创建阶段,接下来进入组件的运行阶段
// 在这个生命周期函数执行的时候,页面中显示的数据还是旧的,但是data中的数据是最新的,
// 页面尚未和最新的数据保持同步
beforeUpdate () {} // 表示当前界面还没有被更新,数据肯定被更新了
// 查看Vue生命周期图例,这里表示先根据data中最新的数据在内存中重新渲染出一份最新的内存DOM树当最新的
// 内存DOM树更新之后会把最新的内存DOM树重新渲染到真实的页面中去这时候就完成了数据从data(model层)
// 到view(视图层)的更新
updated () {} // 表示当前页面和数据保持同步了,都是最新的
})
// 3. 组件销毁阶段
new Vue({
el: "#app",
// 在这个生命周期函数执行的时候.实例身上所有的data和methods以及过滤器、指令等等都是可用状态,还没有真正的执行销毁的过程
beforeDestroy () {}, // 表示组件即将被销毁之前,此时Vue实例以及数据指令等还是可以使用
// 在这个生命周期函执行的时候,组件中的data和methods以及过滤器、指令等等都已经不可用了
destroyed(){} // 表示组件已经完全被销毁了,此时组件数据等已不可用
})
生命周期函数补充:activated和deactivated函数,这两个生命周期函数是在组件实例被保持了状态使用了keep-alive时,才有效的。当被kepp-alive包裹渲染时,切换路由组件时,档切换到被包裹的组件时,被包裹的组件则处处于活跃状态调用activated,切换到其他组件时,该包裹的组件则处于活跃状态调用deactivated函数。
3. 全局组件和局部组件
3.1 全局组件
-
全局组件:
new Vue
构造函数外定义的就是全局组件,可以在其他的vue实例中都可以使用。 -
注意点:在使用Vue.component定义全局组件的时候,组件名称使用驼峰命名,则在引用组件的时候,需要把大写的驼峰改为小写的字母,同时两个单词之间使用
-
连接
<!---->
<body>
<!-- 只要是vue实例的el指定的范围内都可以访问-->
<div id="app">
<button-counter></button-counter>
</div>
<div id="ppa">
<button-counter></button-counter>
</div>
<!-- 这里不可以访问,因为component创建的组件必须在vue实例el指定的元素范围内使用才可以 -->
<!-- 这里将Vue.component命名的组件 buttonCounter,在引用的时候需要写成 button-counter;最好都采用小写-连接 -->
<button-counter></button-counter>
<script>
Vue.component("buttonCounter", {
data: () => {
return {
count: 0,
};
},
template:
'<button v-on:click="count++">You clicked me {{ count }} times.</button>',
});
var vm1 = new Vue({
el: "#app",
});
var vm2 = new Vue({
el: "#ppa",
});
</script>
</body>
3.2 局部组件
- 局部组件:在构造函数里面直接挂载在vue实例的
components
属性上;components是个对象,可以接受一组自定义的局部组件
<body>
<div id="app">
<local-counter></local-counter>
</div>
<!-- 因为local-counter是局部组件,只能在vm1实例的el范围内使用 -->
<div id="ppa">
<local-counter></local-counter>
</div>
<script>
// local-counter是自定义局部组件名,对应一个对象是其构造选项
var vm1 = new Vue({
el: "#app",
components: {
"local-counter": {
template:
'<button v-on:click="count++">You clicked me {{ count }} times.</button>',
data: function () {
return {
count: 0,
};
},
},
},
});
var vm2 = new Vue({
el: "#ppa",
});
</script>
</body>
4. 父子组件
- 父子组件关系的本质:只要一个组件在另一个组件的template中或者是实例的el绑定标签中。
<!-- 父子组件关系一: -->
<body>
<!-- div#app是父组件的模板 -->
<div id="app">
<cpn></cpn>
</div>
<script>
// cpn的template是子组件cpn的模板,渲染的时候cpn组件会被整个cpn的template模板内容替换
Vue.component('cpn', {
template: `
<div>
<h1>我是子组件</h1>
</div>
`,
})
var vm = new Vue({
el: '#app',
data() {
return {
messageInfo: '我是父组件的message'
}
}
})
</script>
</body>
<!-- 父子孙的组件关系二: -->
<div id="app">
<cpn1></cpn1>
</div>
<script>
// 在vm实例的el绑定的div模板中使用cpn1组件,在cpn1组件的模板中使用cpn2组件
Vue.component('cpn1', {
template: `<div>
<h1>我是cpn1标题1</h1>
<cpn2></cpn2>
</div>`,
})
Vue.component('cpn2', {
template: `<div>
<h1>我是cpn2标题2</h1>
</div>`,
})
var vm = new Vue({
el: '#app',
})
</script>
//
<div id="app">
<cpn1></cpn1>
</div>
<script>
var cpnConstructor = Vue.extend({
template: `<h2>我是cpn2标题2</h2>`
})
// var cpn2 = {
// template: `<h2>我是cpn2标题2</h2>`
// };
Vue.component('cpn1', {
template: `<div>
<h1>我是cpn1标题1</h1>
<cpn2></cpn2>
</div>`,
components: {
cpn2: cpnConstructor // 这里可以放extend的构造器或者直接放cpn2定义的选项对象
}
})
var vm = new Vue({
el: '#app',
})
</script>
5. 父子组件通信
- 背景:子组件虽然在父组件的模板中嵌套,但是子组件不能访问父组件data的数据,父组件也不能访问子组件的data数据;所以父子之间交互数据需要通信了。
- 最常见的应用就是:组件 A 在它的模板中使用了组件 B。它们之间必然需要相互通信:父组件可能要给子组件下发数据,子组件则可能要将它内部发生的事情告知父组件。
- 注意:
1. Prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意间修改了父组件的状态,因为对于传递的引用类型的值,也就是说prop接受到的是对象或者数组,那么父子组件指向的同一块内存,子组件内部修改会影响父组件。
2. 子组件如果需要修改prop,则可以在子组件内部进行一份prop的拷贝
5.1 父组件向子组件传递
- 父组件向子组件传递方式:通过
props
属性 和vm.$attrs
属性 - 命名总结:HTML 特性是不区分大小写的。所以,当使用的不是字符串模板时,camelCase (驼峰式命名) 的 prop 需要转换为相对应的
xxx-ccc (短横线分隔式命名)
;在js中使用驼峰式,html中使用短横线
// 示例1:静态使用props,静态传值vue,注意属性时分隔符不能驼峰式
<div id="app">
<cpn1 my-message="vue"></cpn1>
</div>
<script>
Vue.component('cpn1', {
// 声明props
props: ['myMessage'],
// 就像data一样,props里面的数据也可以在模板中使用,
// 同样也可以在vm实例中通过 this.myMessage 来使用
template: '<h1>hello {{myMessage}}</h1>',
})
var vm = new Vue({
el: '#app',
})
</script>
// hello vue
// 动态props父组件传递数据到子组件
<body>
<div id="app">
<!-- myCpn自定义组件写成my-cpn cpnList是子组件props中声明的属性写成cpn-list,接受父组件传递的属性-->
<!-- v-bind:cpn-list="list" 简写 :cpn-list="list" -->
<!-- cpn-list是子组件props中定义的属性cpnList,用于接收父组件传递来的list -->
<my-cpn :cpn-list="list" :cpn-pers-info="persInfo"></my-cpn>
</div>
<script>
Vue.component('myCpn', {
// 在子组件的模板中使用子组件props中的属性
template: `<div>
<h1>我是子组件myCpn</h1>
<h1>接收到的数据:{{cpnList}}</h1>
<h1>接收到的数据:{{cpnPersInfo}}</h1>
</div>`,
props: ['cpnList', 'cpnPersInfo']
});
var vm = new Vue({
el: "#app",
data() {
return {
list: ['数码', '家电', '旅行'],
persInfo: {
name: 'Bob',
age: 20
},
}
}
});
</script>
</body>
5.2 子组件向父组件传递
- 子组件向父组件传递数据是通过自定义事件
<body>
<!-- 子组件模板 -->
<template id="son">
<div>
<!-- 1. 子组件通过点击事件触发事件函数 -->
<button v-for="item of categories" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
<!-- 父组件模板 -->
<div id="app">
<!-- 3. 父组件通过监听子组件的自定义事件item-click进行处理,注意自定义的事件的函数没有event对象,但是这里默认会将子组件的数据item带过去 -->
<cpn-button @item-click="cpnClick"></cpn-button>
</div>
<script>
// 子组件
Vue.component('cpnButton', {
data() {
return {
categories: [
{ id: '1', name: '家电' },
{ id: '2', name: '科技' },
{ id: '3', name: '户外' },
],
}
},
template: '#son',
methods: {
btnClick(item) {
// 2. 子组件将点击获取到的数据通过 this.$emit(自定义事件名,传递给父组件的数据)发射自定义事件;自定义事件名要小写短横线连接
this.$emit('item-click', item)
}
}
})
// 父组件实例
new Vue({
el: '#app',
methods: {
// 4. 父组件监听的自定义事件函数接收到子组件传递来的item数据
cpnClick(item) {
console.log("---", item)
}
}
})
</script>
</body>
6. 父子组件的访问
6.1 父访问子
- 两种访问方式:通过children或者refs
1. this.$children:是一个包含所有子组件对象的数组
2. this.$refs:默认是`{}`,当在子组件上绑定ref属性时,this.$refs的结构就变成
`{ 绑定的ref属性: 对应的子组件 }`
<!-- this.$children示例 -->
<body>
<div id="app">
<cpn></cpn>
<button @click="btn">按钮</button>
</div>
<template id="cpn">
<div>
<h1>{{message}}</h1>
</div>
</template>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "我是父组件app",
},
methods: {
btn() {
console.log(this.$children[0].message)
this.$children[0].show();
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
message: "我是子组件cpn",
}
},
methods: {
show() {
console.log(this.message);
}
}
}
}
});
</script>
</body>
<!-- this.$refs示例: -->
<body>
<div id="app">
<cpn ref="cpnA"></cpn>
<cpn ref="cpnB"></cpn>
<button @click="showSon">按钮</button>
</div>
<template id="cpn">
<div>
<h1>{{message}}</h1>
</div>
</template>
<script>
var vm = new Vue({
el: "#app",
data() {
return {}
},
methods: {
showSon() {
console.log(this.$refs)
console.log(this.$refs.cpnA)
console.log(this.$refs.cpnB)
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
message: "我是子组件cpn",
}
},
methods: {
show() {
console.log(this.message);
}
}
}
}
});
</script>
</body>
6.2 子访问父
- this.$parent:可以访问到父组件,但是不提倡这样做,这样会破坏子组件的复用性,比如在子组件中修改父组件A的name属性,但是其他B的组件引用这个子组件,B组件中并没有name属性;会导致没有解耦
- this.$root: 会直接访问到根实例
7 动态组件
- ***动态组件定义:通过使用vue内置的
<component>
元素,并对其使用is
特性进行动态绑定,你可以在同一个挂载点动态切换多个组件 - 使用vue内置的
<component>
元素 + 绑定特殊属性is
进而完成动态组件
<!-- 基本使用 -->
<!-- 解析:当用户点击home按钮则在下方的component位置渲染出home组件,点击posts按钮会在下方渲染出posts组件 -->
<body>
<div id='app'>
<div>
<!-- 注意 currentTab = tab是内联js语句,执行后currentTab发生变化触发currentTabComponent -->
<button v-for="tab in tabs" @click="currentTab = tab">
{{ tab }}
</button>
<!-- component为vue的内置组件和特殊属性is搭配起来表示
根据currentTabComponent的变化进而渲染成不同的组件,被渲染出的组件会完全替换内置的component组件
-->
<component :is="currentTabComponent"></component>
</div>
</div>
<script>
Vue.component("home", {
template: "<div>Home component</div>"
});
Vue.component("posts", {
template: "<div>Posts component</div>"
});
new Vue({
el: "#app",
data: {
currentTab: "Home",
tabs: ["Home", "Posts"]
},
computed: {
currentTabComponent: function () {
return this.currentTab.toLowerCase();
}
}
});
</script>
</body>
当在这些组件之间切换的时候,你有时会想保持之前这些组件的状态,以避免反复重渲染导致的性能问题。为了解决这个问题,我们可以用一个 <keep-alive>
元素将其动态组件包裹起来。
<!-- 失活的组件将会被缓存,下次渲染就不会重新创建组件实例,并且组件之前的状态也会被缓存记录!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
8 异步组件
segmentfault.com/a/119000002…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!