1.生命周期
1)初始化显示
beforeCreate() created() beforeMount() mounted() //这些方法只执行一次
2) 更新状态: this.xxx = value
beforeUpdate() updated() //可执行多次
3) 销毁 vue实例:vm.$destory()
beforeDestory() destoryed() //只执行一次
常用的生命周期方法
created()/mounted(): 发送ajax请求, 启动定时器等异步任务
beforeDestory(): 做收尾工作, 如: 清除定时器
2.组件间通信
除路由组件外,数据定义在哪个组件,更新数据的行为(方法)就应该定义在哪个组件
2.1 props
父子组件间通信的基本方式
<!--父组件:App.vue->
<TodoList :items="items" :del="del"/>
//子组件TodoList.vue
props:{
// 声明接收标签属性 会成为当前组件对象的属性
items:Array,
del:Function
}
缺点:
隔层组件间传递: 必须逐层传递(麻烦)
兄弟组件间: 必须借助父组件(麻烦)
2.2 自定义事件
父子组件的通信方式
<!--父组件:App.vue->
<TodoHeader @add="add"/> <!--父组件中绑定监听-->
//子组件TodoHeader.vue
methods:{
addItem() {
const name = this.name.trim(); //注意需要this
if (!name) {
alert("need input!");
return;
}
const Item = {
state:false,name};
this.$emit('add',Item); //子组件中触发事件
this.name = "";
}
}
缺点:不适合隔层组件和兄弟组件间的通信
2.3 pubsub
(消息订阅与发布)适合于任何关系的组件间通信
//TodoList的父组件App.vue
<TodoList :items="items"/>
。。。
import PubSub from 'pubsub-js'
。。。
mounted(){
//执行异步代码
PubSub.subscribe('del', (msg, index) => {
//订阅消息,类似绑定事件监听 这里的msg参数没啥用但必须要有
this.del(index) //此处的this为当前vm组件对象
});
// 回调函数中的this是当前的,若改成 => 函数则没有this 故 =>函数中的this为引用外部的
//TodoList的子组件(即App.vue的孙组件)TodoItem.vue
delItem(){
const index = this.index;
if (window.confirm(`确认删除${
this.item.name}么?`)) {
// this.del(index);
PubSub.publish("del", index); //发布消息,类似于触发事件
}
}
2.4 slot
通信是带数据的页面标签 注意: 标签是在父组件中解析 即若用到的相关属性计算属性,都需在父组件
<!--父组件:App.vue-->
<TodoFooter>
<span slot="size">已完成{
{
completeSize}} / 全部{
{
items.length}}</span>
</TodoFooter>
<!--子组件:TodoFoot.vue-->
<span>
<slot name="size"></slot> <!--变量槽占位-->
<!-- 相当于<span>已完成{
{
completeSize}} / 全部{
{
todos.length}}</span>-->
</span>
2.5 路由组件
多组件共享状态(数据的管理),组件间的关系也没有限制,功能比pubsub强大, 更适用于vue项目
//别的路由组件需用props接收为自身属性再使用,类似组件间props方式通信
3 AIOS
//Main.vue
<template>
<h2 v-if="firstView">输入用户名搜索</h2>
<h2 v-else-if="loading">loading。。。</h2>
<h2 v-else-if="errorMsg">{
{
errorMsg}}</h2>
<div v-else class="row">
<div class="card" v-for="(user,index) in users" :key="index">
<a :href="user.url" target="_blank">
<img :src="user.avatar_url" style='width: 100px'/>
</a>
<p class="card-text">{
{
user.name}}</p>
</div>
</div>
</template>
。。。
import PubSub from "pubsub-js"
import axios from "axios"
。。。
mounted() {
PubSub.subscribe("search",(msg,searchName)=>{
// 订阅消息(search)
const url = `https://api.github.com/search/users?q=${
searchName}`;
this.firstView = false;
this.loading = true;
this.users = [];
this.errorMsg = "";
axios.get(url).then(response=>{
//访问成功
const result = response.data; // 得到返回结果数据
const users = result.items.map(item => ( //这个括号 ( 很重要,标识返回的是对象
{
url: item.html_url,
avatar_url: item.avatar_url,
name: item.login
}
));
// let users = result.items.map(item => {
// let json = {};
// json.url = item.html_url;
// json.avatar_url = item.avatar_url;
// json.name = item.login;
// // console.log(json);
// return json;
// });
this.loading = false;
this.users = users;
}).catch(error=>{
//访问失败
this.loading = false;
this.errorMsg = "请求失败";
})
})
}
//Seaarch.vue
methods:{
doSearch() {
const searchName = this.searchName.trim();
if (searchName) {
PubSub.publish("search", searchName) // 发布一个search的消息
}
}
}
附录
watch:{
items:{
deep:true, // 深度监视
// handler: function (value) {
// console.log(JSON.stringify(value));
// // window.localStorage.setItem("Items_key", JSON.stringify(value)); //将数据(json)保存到localStorage
// storageUtil.saveItems(value);
// }
handler: storageUtil.saveItems //handler的值应该是一个函数, 且函数应该要有一个形参(接收items最新的值)
}
}
}
add(item) {
this.items.unshift(item) //从前面添加 从后面添加则push
},
del(index){
this.items.splice(index, 1);
},
delCompleted() {
this.items = this.items.filter(item=>!item.state); //过滤器,改变总项数 而map是不改变总项数,对每一项的信息进行筛选保留
},
selAll(isCheck) {
//全选/全不选
this.items.forEach(item => item.state=isCheck) //迭代器
}
completedSize() {
const items = this.items;
return items.reduce((preTotal,item)=>preTotal+(item.state?1:0),0) //累加器
}