<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【干貨】Vue2.x 組件通信方式詳解,這篇講全了

      前言

      vue是數據驅動視圖更新的框架, 我們平時開發,都會把頁面不同模塊拆分成一個一個vue組件, 所以對于vue來說組件間的數據通信非常重要,那么組件之間如何進行數據通信的呢?

      首先我們需要知道在vue中組件之間存在什么樣的關系, 才更容易理解他們的通信方式。

      一般我們分為如下關系:

      父子組件之間通信
      非父子組件之間通信(兄弟組件、隔代關系組件、跨層級組件等)

      vue如何進行組件間的通信

      Vue2.x 組件通信共有12種

      1. props
      2. $emit / v-on
      3. .sync
      4. v-model
      5. ref
      6. $children / $parent
      7. $attrs / $listeners
      8. provide / inject
      9. EventBus
      10. Vuex
      11. $root
      12. slot
      13. 路由傳參
      14. observable

      父子組件通信可以用:

      • props
      • $emit / v-on
      • $attrs / $listeners
      • ref
      • .sync
      • v-model
      • $children / $parent

      兄弟組件通信可以用:

      • EventBus
      • Vuex
      • $parent

      跨層級組件通信可以用:

      • provide/inject
      • EventBus
      • Vuex
      • $attrs / $listeners
      • $root

      Vue2.x 組件通信使用寫法

      下面把每一種組件通信方式的寫法一一列出

      1. props

      父組件向子組件傳送數據,這應該是最常用的方式了

      子組件接收到數據之后,不能直接修改父組件的數據。會報錯,所以當父組件重新渲染時,數據會被覆蓋。如果子組件內要修改的話推薦使用 computed

      格式:

      // 數組:不建議使用
      props:[]
      
      // 對象
      props:{
       inpVal:{
        type:Number, //傳入值限定類型
        // type 值可為String,Number,Boolean,Array,Object,Date,Function,Symbol
        // type 還可以是一個自定義的構造函數,并且通過 instanceof 來進行檢查確認
        required: true, //是否必傳
        default:200,  //默認值,對象或數組默認值必須從一個工廠函數獲取如 default:()=>[]
        validator:(value) {
          // 這個值必須匹配下列字符串中的一個
          return ['success', 'warning', 'danger'].indexOf(value) !== -1
        }
       }
      }
      

      事例:

      // Parent.vue 傳送
      <template>
          <child :msg="msg"></child>
      </template>
      
      // Child.vue 接收
      export default {
        // 寫法一 用數組接收
        props:['msg'],
        // 寫法二 用對象接收,可以限定接收的數據類型、設置默認值、驗證等
        props:{
            msg:{
                type:String,
                default:'這是默認數據'
            }
        },
        mounted(){
            console.log(this.msg)
        },
      }
      

      注意:

      prop 只可以從上一級組件傳遞到下一級組件(父子組件),即所謂的單向數據流。而且 prop 只讀,不可被修改,所有修改都會失效并警告。

      • 第一,不應該在一個子組件內部改變 prop,這樣會破壞單向的數據綁定,導致數據流難以理解。如果有這樣的需要,可以通過 data 屬性接收或使用 computed 屬性進行轉換。
      • 第二,如果 props 傳遞的是引用類型(對象或者數組),在子組件中改變這個對象或數組,父組件的狀態會也會做相應的更新,利用這一點就能夠實現父子組件數據的“雙向綁定”,雖然這樣實現能夠節省代碼,但會犧牲數據流向的簡潔性,令人難以理解,最好不要這樣去做。
      • 想要實現父子組件的數據“雙向綁定”,可以使用 v-model 或 .sync。

      props與$emit

      2. $emit / v-on

      子傳父的方法,子組件通過派發事件的方式給父組件數據,或者觸發父組件更新等操作

      // Child.vue 派發
      export default {
        data(){
            return { msg: "這是發給父組件的信息" }
        },
        methods: {
            handleClick(){
                this.$emit("sendMsg",this.msg)
            }
        },
      }
      // Parent.vue 響應
      <template>
          <child v-on:sendMsg="getChildMsg"></child>
          // 或 簡寫
          <child @sendMsg="getChildMsg"></child>
      </template>
      
      export default {
          methods:{
              getChildMsg(msg){
                  console.log(msg) // 這是父組件接收到的消息
              }
          }
      }
      

      3. v-model

      和 .sync 類似,可以實現將父組件傳給子組件的數據為雙向綁定,子組件通過 $emit 修改父組件的數據

      // Parent.vue
      <template>
          <child v-model="value"></child>
      </template>
      <script>
      export default {
          data(){
              return {
                  value:1
              }
          }
      }
      
      // Child.vue
      <template>
          <input :value="value" @input="handlerChange">
      </template>
      export default {
          props:["value"],
          // 可以修改事件名,默認為 input
          model:{
              // prop:'value', // 上面傳的是value這里可以不寫,如果屬性名不是value就要寫
              event:"updateValue"
          },
          methods:{
              handlerChange(e){
                  this.$emit("input", e.target.value)
                  // 如果有上面的重命名就是這樣
                  this.$emit("updateValue", e.target.value)
              }
          }
      }
      </script>
      

      4. ref

      ref 如果在普通的DOM元素上,引用指向的就是該DOM元素;

      如果在子組件上,引用的指向就是子組件實例,然后父組件就可以通過 ref 主動獲取子組件的屬性或者調用子組件的方法

      // Child.vue
      export default {
          data(){
              return {
                  name:"RDIF"
              }
          },
          methods:{
              someMethod(msg){
                  console.log(msg)
              }
          }
      }
      
      // Parent.vue
      <template>
          <child ref="child"></child>
      </template>
      <script>
      export default {
          mounted(){
              const child = this.$refs.child
              console.log(child.name) // RDIF
              child.someMethod("調用了子組件的方法")
          }
      }
      </script>
      

      5. .sync

      可以幫我們實現父組件向子組件傳遞的數據 的雙向綁定,所以子組件接收到數據后可以直接修改,并且會同時修改父組件的數據

      // Parent.vue
      <template>
          <child :page.sync="page"></child>
      </template>
      <script>
      export default {
          data(){
              return {
                  page:1
              }
          }
      }
      
      // Child.vue
      export default {
          props:["page"],
          computed(){
              // 當我們在子組件里修改 currentPage 時,父組件的 page 也會隨之改變
              currentPage {
                  get(){
                      return this.page
                  },
                  set(newVal){
                      this.$emit("update:page", newVal)
                  }
              }
          }
      }
      </script>
      

      6. $attrs / $listeners

      多層嵌套組件傳遞數據時,如果只是傳遞數據,而不做中間處理的話就可以用這個,比如父組件向孫子組件傳遞數據時。

      $attrs:包含父作用域里除 class 和 style 除外的非 props 屬性集合。通過 this.$attrs 獲取父作用域中所有符合條件的屬性集合,然后還要繼續傳給子組件內部的其他組件,就可以通過 v-bind="$attrs"。

      場景:如果父傳子有很多值,那么在子組件需要定義多個 props

      解決:$attrs獲取子傳父中未在 props 定義的值

      // 父組件
      <home title="這是標題" width="80" height="80" imgUrl="imgUrl"/>
      
      // 子組件
      mounted() {
        console.log(this.$attrs) //{title: "這是標題", width: "80", height: "80", imgUrl: "imgUrl"}
      },
      

      相對應的如果子組件定義了 props,打印的值就是剔除定義的屬性。

      props: {
        width: {
          type: String,
          default: ''
        }
      },
      mounted() {
        console.log(this.$attrs) //{title: "這是標題", height: "80", imgUrl: "imgUrl"}
      },
      

      $listeners:包含父作用域里 .native 除外的監聽事件集合。如果還要繼續傳給子組件內部的其他組件,就可以通過 v-on="$linteners"。

      場景:子組件需要調用父組件的方法

      解決:父組件的方法可以通過 v-on="$listeners" 傳入內部組件——在創建更高層次的組件時非常有用

      // 父組件
      <home @change="change"/>
      
      // 子組件
      mounted() {
        console.log(this.$listeners) //即可拿到 change 事件
      }
      

      如果是孫組件要訪問父組件的屬性和調用方法,直接一級一級傳下去就可以。

      7. $children / $parent

      $children:獲取到一個包含所有子組件(不包含孫子組件)的 VueComponent 對象數組,可以直接拿到子組件中所有數據和方法等。

      $parent:獲取到一個父節點的 VueComponent 對象,同樣包含父節點中所有數據和方法等

      // Parent.vue
      export default{
          mounted(){
              this.$children[0].someMethod() // 調用第一個子組件的方法
              this.$children[0].name // 獲取第一個子組件中的屬性
          }
      }
      
      // Child.vue
      export default{
          mounted(){
              this.$parent.someMethod() // 調用父組件的方法
              this.$parent.name // 獲取父組件中的屬性
          }
      }
      

      $children$parent 并不保證順序,也不是響應式的,只能拿到一級父組件和子組件。

      8. provide / inject

      provide / inject 為依賴注入,主要為高階插件/組件庫提供用例。說是不推薦直接用于應用程序代碼中,但是在一些插件或組件庫里卻是被常用,所以我覺得用也沒啥,還挺好用的。

      provide:可以讓我們指定想要提供給后代組件的數據或方法

      inject:在任何后代組件中接收想要添加在這個組件上的數據或方法,不管組件嵌套多深都可以直接拿來用

      要注意的是 provide 和 inject 傳遞的數據不是響應式的,也就是說用 inject 接收來數據后,provide 里的數據改變了,后代組件中的數據不會改變,除非傳入的就是一個可監聽的對象

      所以建議還是傳遞一些常量或者方法

      // 父組件
      export default{
          // 方法一 不能獲取 this.xxx,只能傳寫死的
          provide:{
              name:"RDIF",
          },
          // 方法二 可以獲取 this.xxx
          provide(){
              return {
                  name:"RDIF",
                  msg: this.msg // data 中的屬性
                  someMethod:this.someMethod // methods 中的方法
              }
          },
          methods:{
              someMethod(){
                  console.log("這是注入的方法")
              }
          }
      }
      
      // 后代組件
      export default{
          inject:["name","msg","someMethod"],
          mounted(){
              console.log(this.msg) // 這里拿到的屬性不是響應式的,如果需要拿到最新的,可以在下面的方法中返回
              this.someMethod()
          }
      }
      

      9. EventBus

      EventBus 是中央事件總線,不管是父子組件,兄弟組件,跨層級組件等都可以使用它完成通信操作。

      • 聲明一個全局Vue實例變量 EventBus , 把所有的通信數據,事件監聽都存儲到這個變量上;
      • 類似于 Vuex。但這種方式只適用于極小的項目;
      • 原理就是利用on和emit 并實例化一個全局 vue 實現數據共享;
      • 可以實現平級,嵌套組件傳值,但是對應的事件名eventTarget必須是全局唯一的;

      定義方式有三種:

      // 方法一
      // 抽離成一個單獨的 js 文件 Bus.js ,然后在需要的地方引入
      // Bus.js
      import Vue from "vue"
      export default new Vue()
      
      // 方法二 直接掛載到全局
      // main.js
      import Vue from "vue"
      Vue.prototype.$bus = new Vue()
      
      // 方法三 注入到 Vue 根對象上
      // main.js
      import Vue from "vue"
      new Vue({
          el:"#app",
          data:{
              Bus: new Vue()
          }
      })
      

      使用如下,以方法一按需引入為例:

      // 在需要向外部發送自定義事件的組件內
      <template>
          <button @click="handlerClick">按鈕</button>
      </template>
      import Bus from "./Bus.js"
      export default{
          methods:{
              handlerClick(){
                  // 自定義事件名 sendMsg
                  Bus.$emit("sendMsg", "這是要向外部發送的數據")
              }
          }
      }
      
      // 在需要接收外部事件的組件內
      import Bus from "./Bus.js"
      export default{
          mounted(){
              // 監聽事件的觸發
              Bus.$on("sendMsg", data => {
                  console.log("這是接收到的數據:", data)
              })
          },
          beforeDestroy(){
              // 取消監聽
              Bus.$off("sendMsg")
          }
      }
      

      以方法二直接掛載在全局:

      // 在 main.js
      Vue.prototype.$eventBus=new Vue()
      
      // 傳值組件
      this.$eventBus.$emit('eventTarget','這是eventTarget傳過來的值')
      
      // 接收組件
      this.$eventBus.$on("eventTarget",v=>{
        console.log('eventTarget',v);//這是eventTarget傳過來的值
      })
      

      10. Vuex

      • Vuex 是狀態管理器,集中式存儲管理所有組件的狀態。
      • 適合數據共享多的項目里面,因為如果只是簡單的通訊,使用起來會比較重。
      state:定義存貯數據的倉庫 ,可通過this.$store.state 或mapState訪問。
      getter:獲取 store 值,可認為是 store 的計算屬性,可通過this.$store.getter 或 mapGetters訪問。
      mutation:同步改變 store 值,為什么會設計成同步,因為mutation是直接改變 store 值,vue 對操作進行了記錄,如果是異步無法追蹤改變,可通過mapMutations調用。
      action:異步調用函數執行mutation,進而改變 store 值,可通過 this.$dispatch或mapActions訪問。
      modules:模塊,如果狀態過多,可以拆分成模塊,最后在入口通過...解構引入。
      

      這一塊內容過長,如果基礎不熟的話可以看這個Vuex,然后大致用法如下:

      比如創建這樣的文件結構

      Vuex

      index.js 里內容如下

      import Vue from 'vue'
      import Vuex from 'vuex'
      import getters from './getters'
      import actions from './actions'
      import mutations from './mutations'
      import state from './state'
      import user from './modules/user'
      
      Vue.use(Vuex)
      
      const store = new Vuex.Store({
        modules: {
          user
        },
        getters,
        actions,
        mutations,
        state
      })
      export default store
      

      然后在 main.js 引入

      import Vue from "vue"
      import store from "./store"
      new Vue({
          el:"#app",
          store,
          render: h => h(App)
      })
      

      然后在需要的使用組件里

      import { mapGetters, mapMutations } from "vuex"
      export default{
          computed:{
              // 方式一 然后通過 this.屬性名就可以用了
              ...mapGetters(["引入getters.js里屬性1","屬性2"])
              // 方式二
              ...mapGetters("user", ["user模塊里的屬性1","屬性2"])
          },
          methods:{
              // 方式一 然后通過 this.屬性名就可以用了
              ...mapMutations(["引入mutations.js里的方法1","方法2"])
              // 方式二
              ...mapMutations("user",["引入user模塊里的方法1","方法2"])
          }
      }
      
      // 或者也可以這樣獲取
      this.$store.state.xxx
      this.$store.state.user.xxx
      

      組件通信

      11. $root

      $root 可以拿到 App.vue 里的數據和方法

      // 父組件
      mounted(){
        console.log(this.$root) //獲取根實例,最后所有組件都是掛載到根實例上
        console.log(this.$root.$children[0]) //獲取根實例的一級子組件
        console.log(this.$root.$children[0].$children[0]) //獲取根實例的二級子組件
      }
      

      12. slot

      將父組件的 template 傳入子組件
      分類:
      A.匿名插槽(也叫默認插槽): 沒有命名,有且只有一個;

      // 父組件
      <todo-list> 
          <template v-slot:default>
             任意內容
             <p>我是匿名插槽 </p>
          </template>
      </todo-list> 
      
      // 子組件
      <slot>我是默認值</slot>
      //v-slot:default寫上感覺和具名寫法比較統一,容易理解,也可以不用寫
      

      B.具名插槽: 相對匿名插槽組件slot標簽帶name命名的;

      // 父組件
      <todo-list> 
          <template v-slot:todo>
             任意內容
             <p>我是匿名插槽 </p>
          </template>
      </todo-list> 
      
      //子組件
      <slot name="todo">我是默認值</slot>
      

      C.作用域插槽: 子組件內數據可以被父頁面拿到(解決了數據只能從父頁面傳遞給子組件)

      // 父組件
      <todo-list>
       <template v-slot:todo="slotProps" >
         {{slotProps.user.firstName}}
       </template> 
      </todo-list> 
      //slotProps 可以隨意命名
      //slotProps 接取的是子組件標簽slot上屬性數據的集合所有v-bind:user="user"
      
      // 子組件
      <slot name="todo" :user="user" :test="test">
          {{ user.lastName }}
       </slot> 
      data() {
          return {
            user:{
              lastName:"Zhang",
              firstName:"yue"
            },
            test:[1,2,3,4]
          }
        },
      // {{ user.lastName }}是默認數據  v-slot:todo 當父頁面沒有(="slotProps")
      

      13、路由傳參

      1.方案一

      // 路由定義
      {
        path: '/describe/:id',
        name: 'Describe',
        component: Describe
      }
      // 頁面傳參
      this.$router.push({
        path: `/describe/${id}`,
      })
      // 頁面獲取
      this.$route.params.id
      

      2.方案二

      // 路由定義
      {
        path: '/describe',
        name: 'Describe',
        component: Describe
      }
      // 頁面傳參
      this.$router.push({
        name: 'Describe',
        params: {
          id: id
        }
      })
      // 頁面獲取
      this.$route.params.id
      

      3.方案三

      // 路由定義
      {
        path: '/describe',
        name: 'Describe',
        component: Describe
      }
      // 頁面傳參
      this.$router.push({
        path: '/describe',
          query: {
            id: id
        `}
      )
      // 頁面獲取
      this.$route.query.id
      

      4.三種方案對比

      方案二參數不會拼接在路由后面,頁面刷新參數會丟失
      方案一和三參數拼接在后面,丑,而且暴露了信息

      14、Vue.observable

      用法:讓一個對象可響應。Vue 內部會用它來處理 data 函數返回的對象;
      返回的對象可以直接用于渲染函數和計算屬性內,并且會在發生改變時觸發相應的更新;
      也可以作為最小化的跨組件狀態存儲器,用于簡單的場景。
      通訊原理實質上是利用Vue.observable實現一個簡易的 vuex

      // 文件路徑 - /store/store.js
      import Vue from 'vue'
      
      export const store = Vue.observable({ count: 0 })
      export const mutations = {
        setCount (count) {
          store.count = count
        }
      }
      
      //使用
      <template>
          <div>
              <label for="bookNum">數 量</label>
                  <button @click="setCount(count+1)">+</button>
                  <span>{{count}}</span>
                  <button @click="setCount(count-1)">-</button>
          </div>
      </template>
      
      <script>
      import { store, mutations } from '../store/store' // Vue2.6新增API Observable
      
      export default {
        name: 'Add',
        computed: {
          count () {
            return store.count
          }
        },
        methods: {
          setCount: mutations.setCount
        }
      }
      </script>
      

      參考資料

      vue.js: https://v2.cn.vuejs.org/

      vuex是什么:https://v3.vuex.vuejs.org/zh/

      工作中要使用Git,看這篇文章就夠了:http://www.guosisoft.com/article/detail/410508049313861

      企業數字化轉型如何做?看過來:http://www.guosisoft.com/article/detail/408745545576517

      結語

      如果本文對你有一點點幫助,點個贊支持一下吧,你的每一個【贊】都是我創作的最大動力 _

      更多技術文章請往:http://www.guosisoft.com/article,大家一起共同交流和進步呀


      前往了解國思RDIF低代碼開發平臺:http://www.guosisoft.com
      國思RDIF低代碼開發平臺

      posted @ 2023-04-27 11:13  .NET快速開發框架  閱讀(753)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 1精品啪国产在线观看免费牛牛| 狠狠躁日日躁夜夜躁欧美老妇 | 亚洲婷婷综合色高清在线| 成人精品自拍视频免费看| 东阿县| 国产亚洲一区二区三区四区| 木里| 人妻系列无码专区无码中出 | 无码人妻精品一区二区三区下载| 国产精品亚洲二区在线看| 久久精品国产99久久六动漫| 日韩丝袜亚洲国产欧美一区| 久久无码专区国产精品| 一本久道中文无码字幕av| 亚洲天堂成人网在线观看| 国产精品日韩中文字幕熟女| 中文字幕午夜福利片午夜福利片97| 狠狠做五月深爱婷婷天天综合| 亚洲欧洲日产国码久在线| 熟妇人妻激情偷爽文| 四虎永久在线精品免费看| 久久亚洲精品情侣| 国产最大成人亚洲精品| 97人妻无码一区| 国产精品福利自产拍久久| 国产福利精品一区二区| 91亚洲国产成人精品性色| 亚洲午夜成人精品电影在线观看 | 久久久精品94久久精品| 九九热精品免费在线视频| 婷婷成人丁香五月综合激情| 亚洲aⅴ无码专区在线观看q| 国产成人亚洲日韩欧美| 少妇极品熟妇人妻无码| 亚洲午夜福利网在线观看| 大胸美女被吃奶爽死视频| 欧美成人精品三级在线观看| 国产欧美日韩高清在线不卡 | 国产三级视频网站| 久久亚洲中文无码咪咪爱| 色婷婷综合久久久中文字幕|