(没有新的api)利用自定义事件,实现兄弟组件之间的通信。
复习VueComponet
需要有$on(绑定事件,触发事件时的回调)、$emit(触发事件)。
$on、$emit、$off都在Vue的原型对象上。vm和vc都能看见。
利用beforeCreate钩子: 此时数据还没解析,数据代理、监测没开始。
main.js:
/*
const Demo = Vue.extend({});//Demo:一个Vuecomponent构造函数
const d = new Demo();//new调用,生成vc实例
Vue.prototype.x = d;//x是一个vc实例*/
//创建vue实例对象
new Vue({
//将App组件放入容器中
render: h => h(App),
beforeCreate() {
//安装全局事件总线
Vue.prototype.$bus = this;//$bus是一个vm实例,$bus是它的名字,$bus在Vue原型对象上,vc能够看见,没有必要new一个vc
},
}).$mount('#app')
school.vue
schoolname:{{ name }}
schoolage{{ schoolage }}
student.vue
{{ msg }}
stuname:{{ name }}
stuage:{{ stuage }}
让app能够直接和item通信。之前是把app上的函数一直传递下去,item接收,触发函数。
现在app收数据,item传id。给app绑定事件,事件回调。item传入id触发事件。
此时勾选、删除,触发事件的是$bus,vm
App.vue
mounted() {
this.$bus.$on('checkTodo',this.checkTodo)
this.$bus.$on('deleteTodo',this.deleteTodo)
},
beforeDestroy() {
this.$bus.$off('checkTodo');
this.$bus.$off('deleteTodo');
},
item.vue
pubsub.js库 :
回调函数为普通函数时,this为undefined,所以需要写成箭头函数,使this为当前vc。
或者把回调定义在外部
student.vue
methods: {
sendStudentName(){
pubsub.publish('hello',this.name)
}
},
school.vue
mounted(){
/*//console.log('school',this.$bus);
//给$bus绑定hello事件、事件回调在school上
this.$bus.$on('hello',(data)=>{
//写成箭头函数,使this是当前组件
this.stuname = data;
});*/
//订阅一个消息
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)
})
},
beforeDestroy() {
//取消订阅
pubsub.unsubsribe(this.pubId)
},
app和item之间的通信用pubsub:
item.vue
methods: {
handleCheck(id){
//通知app组件将id对应的todo对象done取反
//this.checkTodo(id);
this.$bus.$emit("checkTodo",id);
},
handleDelete(id){
if(confirm('确定要删除吗?')){
//通知app组件将id对应的todo对象删除
//this.deleteTodo(id);
/*this.$bus.$emit("deleteTodo",id);*/
pubsub.publish('deleteTodo',id);
}
},
},
app.vue
//删除对象
deleteTodo(_,id){
this.todos = this.todos.filter( todo => todo.id !== id);
},
mounted() {
this.$bus.$on('checkTodo',this.checkTodo)
/*this.$bus.$on('deleteTodo',this.deleteTodo)*/
this.pubId = pubsub.subscribe('deleteTodo',this.deleteTodo);
},
beforeDestroy() {
this.$bus.$off('checkTodo');
/*this.$bus.$off('deleteTodo');*/
pubsub.unsubscribe(this.pubId);
},
添加响应式的属性:
给item添加按钮,绑定事件回调handleEdit。handleEdit(todo)中判断有没有isEdit这个属性,有就修改(出现input框,span消失),没有就添加todo.isEdit = true属性。
然后给input框绑定失去焦点事件,修改todo.isEdit = false;,然后触发update事件并传递数据到app,this.$bus.$emit('updateTodo',todo.id,e.target.value),app触发事件回调updateTodo,修改todo的title属性。
需要点击编辑,input框自动获取焦点:
此时执行完46行,并没有立刻重新解析模板,而是执行51行,然后再解析模板。
执行51行的时候,因为通过v-show控制(display:none 隐藏了),input框并没有出现在页面上,隐藏了调focus不能获取焦点。
app.vue
item.vue
实现反弹
transition标签:
Hello!
Hello!
axios(对xhr封装):
fetch:(兼容性)
此时跨域了。同源策略:1.协议名字,2.主机名字,3.端口号。
请求发送了,服务器接收了,并交给了浏览器,但浏览器没有呈现出来。
利用8080代理服务器解决跨域问题。
把请求发给8080代理服务器,然后转发给5000.
当请求的资源8080代理服务器本身就有,就不会转发给5000.
public文件夹下的文件,8080都有。
第一种只能配置一个代理,并且不能灵活的控制走不走代理。
SearchOption发送请求获取数据,需要传递给List。触发事件。(全局事件总线)
List绑定事件和事件回调,调用回调获取数据后需要处理数据,v-for遍历 key为login(唯一标识)。
SearchOption发请求:
methods: {
search(){
//ES6模板字符串
axios.get(`https://api.github.com/search/users?q=${this.keyword}`).then(
response =>{
//请求成功并获取了数据
console.log('请求成功了');
//触发事件
this.$bus.$emit('getUsers',response.data.items)
},
error =>{
console.log('请求失败了',error.message);
}
)
}
},
List处理数据:
点击搜索按钮,触发事件传递参数,请求成功,再次触发事件,传递参数。
methods: {
search(){
//请求前更新List数据
this.$bus.$emit('search',{isFirst:false,isLoading:true,errMsg:'',users:[]});
//ES6模板字符串
axios.get(`https://api.github.com/search/users?q=${this.keyword}`).then(
response =>{
//请求成功并获取了数据
console.log('请求成功了');
//触发事件
this.$bus.$emit('search',{isLoading:true,errMsg:'',users:response.data.items})
},
error =>{
console.log('请求失败了',error.message);
this.$bus.$emit('search',{isLoading:false,errMsg:error.message,users:[]})
}
)
}
},
data(){
return{
info:{
isFirst:true,
isLoading:false,
errMsg:'',
users:[]
}
}
},
mounted() {
//绑定事件和事件回调函数
this.$bus.$on('search',(dataObj)=>{
//通过字面量的形式合并对象,用dataObj的属性去替换this.info的属性,没有的不变。
this.info = {...this.info,...dataObj}
})
},