Vue 组件间通讯

作者: zidea | 来源:发表于2019-06-16 20:57 被阅读11次
    vuejs

    最近回顾前端,先是 React 现在因工作需又要开始 vue 了。开发过程中多半时间我们需要结构,有层次有上下级,有秩序。有了秩序也就是约束,有了约束也就是有了规则。从而减少我们思考时间。因为麦当劳只是在 10 点半前提供早餐,我们就无需考虑在 10 点半后买到经济实惠的早餐。


    mc 早餐

    但有时候我们还需要打破秩序,逆流而上。做 web 开发有一段时间,最近遇到复杂业务还是有点摸不到头脑,再加上时间紧任务重往往写出繁琐难懂 code。一直在想如何能够轻松地开发出流畅 web。

    其实 web 应用中,数据流是从服务端流出在流回到服务端,知道程序启动了这个数据就开始流动。但是有的人会问,那么从服务端获取列表数据展示,数据也没有流回到服务端,这样可以想象为原封不动地流回到服务端。希望我们多一点想象。

    我们应用是界面是一颗 UI 树,每一个节点可能是原生 DOM 或是自定义 component ,component 也是 DOM 组成。树接口是非线性的,但是也是有层次的。我们控制数据在这棵树上流动。数据让我们应用之树变得绚丽多彩,数据是 UI 树的血液,数据让 UI 树有了生命力。

    我们将树进行划分区域来控制数据,我们控制数据流动范围,控制数据流动方向。

    数据多数流三种方式,框架都应该给出这种三种流动方式给出答案

    • 从父级向子级传递数据
    • 从子级向父级传递数据
    • 跨越多重级别传递数据

    从父组件向子组件传递数据(props)

    <template>
        <div>
            <div class="text-4xl text-white bg-blue-200">{{title}}</div>
        </div>
    </template>
    
    • 在子组件中定义 props 可以接受从父级传过来变量
    • 父组件
    <template>
        <div >
            <Title class="text-lg" title="user list"/>
            <div class="" v-for="user in users" :key="user.id">
                <User message="hello" v-bind:user="user"/>
            </div>
        </div>
    </template>
    
    • 父级调用子组件(User) 可以通过属性 message 传递字符串 hello 给子组件,这种方式我们只能传递字符串。如果传递 data 中一个对象 user 这种方式是无法接受到 user 而是接受到 ”user“ 的字符串。这时候我们就需要用到动态绑定。

    动态绑定

    • 下面示例是一个在父级获取用户列表然后将列表中 User 对象传递给 User 组件显示出来用户信息。
    父组件
    <template>
        <div >
            <div class="" v-for="user in users" :key="user.id">
                <User message="hello" v-bind:user="user"/>
            </div>
        </div>
    </template>
    
    <script>
    import axios from "axios";
    import User from "../components/User.vue";
    export default {
      name: "Users",
      components: {
        User
      },
      data: () => {
        return {
          users: []
        };
      },
      created() {
        axios.get("https://jsonplaceholder.typicode.com/users").then(response => {
          console.log(response.data);
          this.users = response.data;
        });
      }
    };
    </script>
    
    <style>
    </style>
    
    
    • v-bind:user 这种方式可以将 user 对象传递给子组件 User
    子组件
    <template>
        <div>
            <p>{{user.name}}</p>
            <p>{{user.email}}</p>
        </div>
    </template>
    
    <script>
    export default {
      name: "User",
      props: ["user", "message"],
      data: () => {
        return {};
      }
    };
    </script>
    
    <style>
    </style>
    

    我们可以为 prop 定义类型,定义了类型也就是约束少了一些选择,选择少了我们就更明确我们能够得到什么 string 类型必填的 title 的属性。

    export default {
      name: "Title",
      props: {
        title: {
          type: String,
          required: true
        }
      }
    };
    

    从子组件向父组件传递数据(事件)

    父组件

    这个实例是这样的,一个课程列表,列表中每个课程都有一个等级,通过 rating 属性来表示为 1 - 5 。我们选择了一个课程,这是现实该课程的等级,等级信息是从父级组件 Tuts
    传递给 Rating 子组件,不过在子组件如果修改了 Rating 反过来也会修改父级组件中的该对象的 Rating 的值,也就是(从子组件向父组件传递数据)

    <template>
        <div class="flex flex-row justify-center align-center">
            <div class="flex flex-col">
                <div class="mr-12" v-for="tut in tuts" :key="tut.id" @click="setSelectedTut(tut)">
                <div >{{tut.name}}({{tut.rating}})</div>
             </div>
            </div>
            <Rating v-if="selectedTut" :selectedTutRating="selectedTut.rating" v-on:ratingUpdated="changeDisplayRating"/>
        </div>
    </template>
    
    <script>
    const tutList = [
      { id: 0, name: "angularjs", rating: 3 },
      { id: 1, name: "react", rating: 1 },
      { id: 2, name: "vue", rating: 5 }
    ];
    import Rating from "../components/Rating.vue";
    export default {
      name: "tuts",
      data() {
        return {
          tuts: [],
          selectedTut: null
        };
      },
      mounted() {
        this.tuts = this.getTuts();
      },
      methods: {
        setSelectedTut(tut) {
          this.selectedTut = tut;
        },
        changeDisplayRating(val) {
          this.tuts[this.selectedTut.id].rating = val;
        },
        getTuts() {
          return [...tutList];
        }
      },
      components: {
        Rating
      }
    };
    </script>
    
    <style>
    </style>
    
    
    • 先来看父组件如何向子组件传递数据,数据中有两个数据 tuts 课程列表和 selectedTut 表示选中的课程,在 mouted 阶段获取 tuts 数据,如果没有选择任何课程,selectedTut 默认为空,通过 v-if 控制 Rating 子组件显示,没有选择也就意味不会显示 Rating。如果有选择,这回通过 :selectedTutRating 将课程的等级数据传递给子组件 Rating 进行显示。
    • 在 setSelectedTut 这个方法在选择课程后会把选择课程设置为 selectedTut。
    子组件代码
    <template>
        <div class="inline-block md:inline-flex">
            <form action="">
                <div><input type="radio" value="1" id="oneStarts" v-model="tutRating"><label for="oneStarts">1</label></div>
                <div><input type="radio" value="2" id="twoStarts" v-model="tutRating"><label for="twoStarts">2</label></div>
                <div><input type="radio" value="3" id="threeStarts" v-model="tutRating"><label for="threeStarts">3</label></div>
                <div><input type="radio" value="4" id="fourStarts" v-model="tutRating"><label for="fourStarts">4</label></div>
                <div><input type="radio" value="5" id="fiveStarts" v-model="tutRating"><label for="fiveStarts">5</label></div>
            </form>
        </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          tutRating: null
        };
      },
      props: {
        selectedTutRating: {
          type: Number,
          required: false
        }
      },
      mounted() {
        this.tutRating = this.selectedTutRating;
      },
      methods: {
        clearRating() {
          this.tutRating = null;
        }
      },
      watch: {
        tutRating: function(newRating, oldRating) {
          let success = true;
          if (success) {
            this.$emit("ratingUpdated", newRating);
          }
        },
        selectedTutRating: function(newRating, oldRating) {
          this.tutRating = newRating;
        }
      }
    };
    </script>
    
    <style>
    </style>
    
    • 在子组件中关键是用了 watch 监控 tutRating 和 selectTutRating 进行控制,当我们在 Rating 进行选择就是通过 tutRating 方法中 $emit 发送给用户新选择的等级给父组件的
      v-on:ratingUpdated="changeDisplayRating" 父组件是通过监听ratingUpdated 来从子组件中获取等级数据来实现从子组件到父组件传递数据的。

    相关文章

      网友评论

        本文标题:Vue 组件间通讯

        本文链接:https://www.haomeiwen.com/subject/iyrgfctx.html