<progress id="7nnbd"><big id="7nnbd"><em id="7nnbd"></em></big></progress>

<big id="7nnbd"><meter id="7nnbd"></meter></big>
<progress id="7nnbd"><meter id="7nnbd"><cite id="7nnbd"></cite></meter></progress><meter id="7nnbd"></meter>

      <address id="7nnbd"></address>

          為了賬號安全,請及時綁定郵箱和手機立即綁定

          Vue倔強青銅-入門和組件化通信

          2019.03.16 23:38 7064瀏覽

          入門

          作為前端最容易上手的框架,Vue入門其實沒啥說的,我放一段清單的代碼,大家能看懂就說明能上手了

          todos

          <template>
            <div id="app">
              <h1>{{title}}</h1>
              <div>
                <input type="text" v-model="val">
                <button @click="add">添加</button>
                <button @click="clear">清空</button>
              </div>
              <ul>
                <li v-for="todo in todos" :key="todo.title" :class="{done:todo.done}">
                  <input type="checkbox" v-model="todo.done">
                  {{todo.title}}
                </li>
              </ul>
              <p>{{active}} / {{all}}</p>
            </div>
          </template>
          
          <script>
          export default {
            name: "app",
            data() {
              return {
                title: "蝸牛老濕很騷氣",
                val: "",
                todos: []
              };
            },
            mounted() {
              const todos = localStorage.getItem("todos");
              if (todos) {
                this.todos = JSON.parse(todos);
              } else {
                this.todos = [
                  { title: "吃飯", done: true },
                  { title: "睡覺", done: false },
                  { title: "寫代碼", done: false }
                ];
              }
            },
            computed: {
              active() {
                return this.todos.filter(v => !v.done).length;
              },
              all() {
                return this.todos.length;
              }
            },
            watch: {
              todos: {
                deep: true,
                handler(todos) {
                  localStorage.setItem("todos", JSON.stringify(todos));
                }
              }
            },
            methods: {
              clear() {
                this.todos = this.todos.filter(v => !v.done);
              },
              add() {
                if (this.val) {
                  this.todos.push({ title: this.val, done: false });
                  this.val = "";
                }
              }
            }
          };
          </script>
          <style>
          li.done {
            color: red;
            text-decoration: line-through;
          }
          </style>
          

          大概包含的內容如下,對這個例子熟悉后,才是我們的正文,如果上面代碼有沒看懂的地方,快去Vuejs官網回顧一下吧

          1. 變量渲染
          2. 循環渲染
          3. class渲染
          4. 計算屬性
          5. 監聽器
          6. 綁定事件
          7. 生命周期

          組件化

          Vue單文件組件。Vue的單文件組件相信大家都體驗過,通過vue-cli初始化的項目自動就支持了,新建Child1.vue

          <template>
              <div>Child1</div>
          </template>
          <script>
          export default {
              
          }
          </script>
          
          
          

          App中使用

          <template>
            <div id="app">
              <Child1></Child1>
            </div>
          </template>
          
          <script>
          import Child1 from '@/components/Child1'
          export default {
            name: "app",
            components:{Child1}
          
          }
          
          </script>
          

          下面就迎來了第一個常見問題, 如果組件多了,他們之間如何通信嘮嗑呢,不要小看這個問題,騷氣的面試官,比如我,就經常喜歡問,下面我們來演示一下Vue組件之間常用的通信收件

          1. 父傳子組件

          父子組件傳值,最簡單的就是通過props傳遞,話不多說看代碼

          // App
          <template>
            <div id="app">
              <Child1 :title="title1"></Child1>
            </div>
          </template>
          
          <script>
          import Child1 from '@/components/Child1'
          export default {
            name: "app",
            data(){
              return {
                title1:'我是你爸爸'
              }
            },
            components:{Child1}
          
          }
          </script>
          
          // Child1
          <template>
              <div>
                  <h2>Child2</h2>
                  <div>{{title}}</div>
              </div>
          </template>
          <script>
          export default {
              props:['title']
              
          }
          </script>
          
          
          

          2. 子傳父

          Vue更推薦單向數據流,所以子組件像修改傳遞的數據,需要通知父組件來修改,使用$emit觸發父元素傳遞的事件

          <template>
            <div id="app">
              <h2>Parent</h2>
              <h3>{{msg}}</h3>
              <Child1 :title="title1" @getmsg="getmsg"></Child1>
            </div>
          </template>
          
          <script>
          import Child1 from '@/components/Child1'
          export default {
            name: "app",
            data(){
              return {
                msg:'',
                title1:'我是你爸爸'
              }
            },
            methods:{
              getmsg(msg){
                console.log(msg)
                this.msg = msg
              }
            },
            components:{Child1}
          
          }
          
          </script>
          <style>
          
          div{
            border:1px red solid;
            padding:20px;
          }
          </style>
          
          // child1
          <template>
              <div>
                  <h2>Child2</h2>
                  <p>{{title}}</p>
                  <button @click="toParent">傳遞到父元素</button>
              </div>
          </template>
          <script>
          export default {
              props:['title'],
              methods:{
                  toParent(){
                      this.$emit('getmsg','爸爸,我知道錯了')
                  }
              }
              
          }
          </script>
          

          image-20190315144914257

          3. 兄弟組件

          兄弟組件不能直接通信,只需要父元素搭個橋即可,大家自己體驗即可

          4. 祖先后代 provide & inject

          props一層層傳遞,爺爺給孫子還好,如果嵌套了五六層還這么寫,感覺自己就是一個沙雕,所以這里介紹一個 稍微冷門的API, provice/inject,類似React中的上下文,專門用來跨層級提供數據

          現在很多開源庫都使用這個api來做跨層級的數據共享,比如element-ui的tabsselect

          
          
          <script>
          import Child1 from '@/components/Child1'
          export default {
            name: "app",
            provide:{
              woniu:'我是蝸牛'
            },
            components:{Child1}
          
          }
          
          </script>
          <style>
          
          // 子孫元素
          <template>
              
              <div>
                  <h3>Grandson1</h3>
                  <p>
                      祖先元素提供的數據 : {{woniu}}
                  </p>
              </div>
          </template>
          <script>
          export default {
              
              inject:['woniu']
          }
          </script>
          

          image-20190315145836185

          但是provider和inject不是響應式的,如果子孫元素想通知祖先,就需要hack一下,Vue1中有dispatch和boardcast兩個方法,但是vue2中被干掉了,我們自己可以模擬一下

          原理就是可以通過this.KaTeX parse error: Expected 'EOF', got '和' at position 7: parent和?this.children來獲取父組件和子組件,我們遞歸一下就可以了

          5. dispatch

          遞歸獲取$parent即可 比較簡單

          <button @click="dispatch('dispatch','哈嘍 我是GrandGrandChild1')">dispatch</button>
          
            methods: {
          
              dispatch(eventName, data) {
                let parent = this.$parent
                // 查找父元素
                while (parent ) {
                  if (parent) {
                    // 父元素用$emit觸發
                    parent.$emit(eventName,data)
                    // 遞歸查找父元素
                    parent = parent.$parent
                  }else{
                    break
          
                  }
                }
           
              }
            }
          

          dispatch

          注意只向上傳遞了,并沒有影響別的元素

          6. boardcast

          和dispatch類似,遞歸獲取$children 來向所有子元素廣播

          <button @click="$boardcast('boardcast','我是Child1')">廣播子元素</button>
          
          function boardcast(eventName, data){
            this.$children.forEach(child => {
              // 子元素觸發$emit
              child.$emit(eventName, data)
              if(child.$children.length){
                // 遞歸調用,通過call修改this指向 child
                boardcast.call(child, eventName, data)
              }
            });
          }
          {
            methods: {
          
              $boardcast(eventName, data) {
                boardcast.call(this,eventName,data)
              }
            }
          }
          

          boardcast

          7. 全局掛載dispatch和boardcast

          想用的時候,需要自己組件內部定理dispatch和boardcast太煩了,我們掛載到Vue的原型鏈上,豈不是很high,找到main.js

          Vue.prototype.$dispatch =  function(eventName, data) {
            let parent = this.$parent
            // 查找父元素
            while (parent ) {
              if (parent) {
                // 父元素用$emit觸發
                parent.$emit(eventName,data)
                // 遞歸查找父元素
                parent = parent.$parent
              }else{
                break
              }
            }
          }
          
          Vue.prototype.$boardcast = function(eventName, data){
            boardcast.call(this,eventName,data)
          }
          function boardcast(eventName, data){
            this.$children.forEach(child => {
              // 子元素觸發$emit
              child.$emit(eventName, data)
              if(child.$children.length){
                // 遞歸調用,通過call修改this指向 child
                boardcast.call(child, eventName, data)
              }
            });
          }
          
          

          這樣組件里直接就可以用了 無壓力

          8. 沒啥關系的組件:event-bus

          如果倆組件沒啥關系呢,我們只能使用訂閱發布模式來做,并且掛載到Vue.protytype之上,我們來試試,我們稱呼這種機制為總線機制,也就是喜聞樂見的 event-bus

          
          class Bus{
            constructor(){
              // {
              //   eventName1:[fn1,fn2],
              //   eventName2:[fn3,fn4],
              // }
              this.callbacks = {}
            }
            $on(name,fn){
              this.callbacks[name] = this.callbacks[name] || []
              this.callbacks[name].push(fn)
            }
            $emit(name,args){
              if(this.callbacks[name]){
                // 存在 遍歷所有callback
                this.callbacks[name].forEach(cb=> cb(args))
              }
            }
          }
          
          Vue.prototype.$bus = new Bus()
          

          使用

          // 使用
          eventBus(){
              this.$bus.$emit('event-bus','測試eventBus')
          }
          
          // 監聽
          this.$bus.$on("event-bus",msg=>{
              this.msg = '接收event-bus消息:'+ msg
          })
          

          eventbus

          9. vuex

          總結了那么多,其實最佳實踐就是vuex,這個后面再專門寫文章學習吧

          看完這個文章,Vue組件化通信應該就難不住你了,也恭喜你度過青銅,正式邁入Vue秩序白銀級別

          ···············································
          歡迎關注課程:

          點擊查看更多內容

          本文原創發布于慕課網 ,轉載請注明出處,謝謝合作

          30人點贊

          若覺得本文不錯,就分享一下吧!

          評論

          相關文章推薦

          正在加載中
          意見反饋 幫助中心 APP下載
          官方微信

          舉報

          0/150
          提交
          取消
          五福彩票 晋城 | 吕梁 | 广安 | 晋江 | 台湾台湾 | 七台河 | 三亚 | 金华 | 宿州 | 东莞 | 澳门澳门 | 湘潭 | 咸宁 | 海南 | 白城 | 凉山 | 宜春 | 辽阳 | 灵宝 | 诸城 | 宜宾 | 邯郸 | 曹县 | 安阳 | 徐州 | 牡丹江 | 郴州 | 昆山 | 德州 | 杞县 | 甘南 | 大庆 | 海拉尔 | 东方 | 遂宁 | 滨州 | 新泰 | 深圳 | 固原 | 基隆 | 南阳 | 灌南 | 宁波 | 图木舒克 | 酒泉 | 清徐 | 绥化 | 福建福州 | 石狮 | 玉环 | 汕头 | 博罗 | 三门峡 | 三明 | 清徐 | 达州 | 双鸭山 | 克孜勒苏 | 鄂尔多斯 | 霍邱 | 山西太原 | 日喀则 | 西藏拉萨 | 昌吉 | 无锡 | 神农架 | 景德镇 | 乌兰察布 | 内蒙古呼和浩特 | 晋中 | 揭阳 | 平凉 | 沧州 | 达州 | 阿里 | 枣阳 | 兴安盟 | 诸城 | 肇庆 | 温岭 | 荣成 | 惠东 | 汉川 | 吉林长春 | 曹县 | 鸡西 | 黔东南 | 鄢陵 | 贵港 | 章丘 | 喀什 | 金坛 | 咸阳 | 江苏苏州 | 宁德 | 江苏苏州 | 达州 | 天长 | 吴忠 | 淮南 | 象山 | 乐平 | 启东 | 乐山 | 泸州 | 阳江 | 阜阳 | 大同 | 吉林长春 | 库尔勒 | 钦州 | 宜春 | 石嘴山 |