【Vue】组件间五大通信+ajax异步通信axios

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 集中式状态管理插件——Vuex

link
多组件共享状态(数据的管理),组件间的关系也没有限制,功能比pubsub强大, 更适用于vue项目
//别的路由组件需用props接收为自身属性再使用,类似组件间props方式通信

2.6 v-model的方式

<SingleUpload v-model="dataForm.logo"></SingleUpload>
...
import SingleUpload from "@/components/upload/singleUpload.vue";
...
import SingleUpload from "@/components/upload/singleUpload.vue";

在子组件中可以下面的方式this.$emit(‘input’, val),去改变父组件中v-model和子组件中的value值为val

/home/xu/PersonProjects/FrontEndProjects/renren-fast-vue/src/components/upload/singleUpload.vue

props: {
      value: String  // 声明接收标签属性
    },
    ...
methods: {
   this.$emit('input', val)
  },
}

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) //累加器
}

版权声明:本文为qq_40265247原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。