亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

vue嵌套組件傳參實(shí)例分享

 更新時(shí)間:2024年07月01日 10:40:50   作者:???????老  
這篇文章主要介紹了vue嵌套組件傳參實(shí)例分享,本文以一個(gè)vue遞歸組件為例,探究多層嵌套后事件無(wú)法觸發(fā)的問(wèn)題,我們可以通過(guò)查看一Demo,便于快速了解,下文列舉例子需要的小伙伴可以參考一下

前言:

假設(shè)我們已經(jīng)了解vue組件常見(jiàn)的有父子組件通信,兄弟組件通信。而父子組件通信很簡(jiǎn)單,父組件會(huì)通過(guò) props 向下傳數(shù)據(jù)給子組件,當(dāng)子組件有事情要告訴父組件時(shí)會(huì)通過(guò) $emit 事件告訴父組件。那么當(dāng)兩個(gè)組件之間不是父子關(guān)系,怎樣傳遞數(shù)據(jù)呢?

先來(lái)看一下這個(gè)例子:

遞歸嵌套組件參數(shù)傳遞

我們封裝了一個(gè)名為 NestedDir 的子組件(嵌套目錄的意思),內(nèi)容如下(用到了element ui組件):

<!-- NestedDir.vue -->
<template>
  <ul class="nest_wrapper">
    <li v-for="(el, index) in nested" :key="index">
      <div v-if="el.type ==='dir'" class="dir">
        <p>{{el.name}}</p>
        <div class="btn_group">
          <el-button type="warning" size="mini" @click="add({id: el.id, type: 'dir'})">新增目錄</el-button>
          <el-button type="warning" size="mini" @click="add({id: el.id, type: 'file'})">新增文件</el-button>
        </div>
      </div>
      <div v-if="el.type ==='file'" class="file">
        <p>{{el.name}}</p>
      </div>
      <NestedDir v-if="el.children" :nested="el.children"/>
    </li>
  </ul>
</template>

<script>
export default {
  name: "NestedDir",
  props: {
    nested: {
      type: Array,
    }
  },
  methods: {
    add(el) {
      this.$emit('change', el)
    }
  }
}
</script>

可以看出這個(gè) NestedDir 接收父級(jí)傳來(lái)的 nested 數(shù)組類(lèi)型的數(shù)據(jù),并且它的內(nèi)部點(diǎn)擊 新增目錄、新增文件,可以觸發(fā) 父級(jí) 監(jiān)聽(tīng)的 change 事件。比較特殊的是這個(gè)組件中調(diào)用了自己:

<NestedDir v-if="el.children" :nested="el.children"/>

不過(guò)要注意的是調(diào)用自己的時(shí)候我們并沒(méi)有在它上面監(jiān)聽(tīng)它內(nèi)部傳來(lái)的change事件,這也是導(dǎo)致二級(jí)目錄點(diǎn)擊新增按鈕無(wú)效的原因。

我們傳遞給它的 nested 數(shù)據(jù)結(jié)構(gòu)大概是下面的樣子:

[{
    "id": 1,
    "name": "目錄1",
    "type": "dir",
    "children": [{
        "id": 2,
        "name": "目錄3",
        "type": "dir",
        "children": [],
        "pid": 1
    }, {
        "id": 3,
        "name": "文件2",
        "type": "file",
        "pid": 1
    }]
}, {
    "id": 4,
    "name": "目錄2",
    "type": "dir",
    "children": []
}, {
    "id": 5,
    "name": "文件1",
    "type": "file",
    "children": []
}]

父組件中調(diào)用 NestedDir:

<!-- directory.vue -->
<template>
  <div style="width: 50%;box-shadow: 0 0 4px 2px rgba(0,0,0,.1);margin: 10px auto;padding-bottom: 10px;">
    <!-- 頂部按鈕組 -->
    <div class="btn_group">
      <el-button type="warning" size="mini" @click="showDialog({type: 'dir'})">新增目錄</el-button>
      <el-button type="warning" size="mini" @click="showDialog({type: 'file'})">新增文件</el-button>
    </div>
    <!-- 嵌套組件 -->
    <NestedDir :nested="catalog" @change="handleChange"/>
    <!-- 新增彈出框 -->
    <el-dialog :title="title" :visible.sync="dialogFormVisible" width="300px">
      <el-form :model="form">
        <el-form-item label="名稱(chēng)">
          <el-input v-model="form.name" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="confirm">確 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import NestedDir from "./NestedDir";

export default {
  name: "directory",
  components: {
    NestedDir
  },
  created() {
    this.catalog = this.getTree()
  },
  computed: {
    maxId() {
      return this.arr.lastIndex + 2
    },
    topNodes() {
      this.arr.forEach(item => {
        if (item.children) item.children = []
      })
      return this.arr.filter(item => !item.pid)
    }
  },
  data() {
    return {
      arr: [
        {id: 1, name: '目錄1', type: 'dir', children: []},
        {id: 2, name: '目錄3', type: 'dir', children: [], pid: 1},
        {id: 3, name: '文件2', type: 'file', pid: 1},
        {id: 4, name: '目錄2', type: 'dir', children: []},
        {id: 5, name: '文件1', type: 'file'},
      ],
      title: '',
      dialogFormVisible: false,
      form: {
        id: '',
        name: '',
        type: '',
        pid: ''
      },
      catalog: []
    }
  },
  methods: {
    handleChange(el) {
      this.showDialog(el)
    },
    confirm() {
      this.arr.push({...this.form})
      this.dialogFormVisible = false
      this.catalog = this.getTree()
      this.form = {
        id: '',
        name: '',
        type: '',
        pid: '' , // 父級(jí)的id
      }
    },
    showDialog(el) {
      if (el.type === 'dir') {
        this.title = '新增目錄'
        this.form.children = []
        this.form.type = 'dir'
      } else {
        this.title = '新增文件'
        this.form.type = 'file'
      }
      if (el.id) {
        this.form.pid = el.id
        this.form.id = this.maxId
      } else {
        this.form.id = this.maxId
      }
      this.dialogFormVisible = true
    },
    getTree() {
      this.topNodes.forEach(node => {
        this.getChildren(this.arr, node.children, node.id)
      })
      return this.topNodes
    },
    getChildren(data, result, pid) {
      for (let item of data) {
        if (item.pid === pid) {
          const newItem = {...item, children: []}
          result.push(newItem)
          this.getChildren(data, newItem.children, item.id)
        }
      }
    }
  }
}
</script>

<style scoped>
.btn_group {
  padding: 20px 10px;
  background-color: rgba(87, 129, 189, 0.13);
}
</style>

渲染出的頁(yè)面是下面的樣子:

遞歸組件

深層遞歸組件事件丟失

我們構(gòu)造出了一個(gè)理論上可以無(wú)限嵌套的目錄結(jié)構(gòu),但是經(jīng)過(guò)測(cè)試發(fā)現(xiàn) 在二級(jí)目錄上的 新增按鈕 點(diǎn)擊是沒(méi)有任何反應(yīng)的,原因是我們?cè)?NestedDir 中調(diào)用了它自己并沒(méi)有監(jiān)聽(tīng)內(nèi)部的change事件(上邊提到過(guò)),所以它無(wú)法觸發(fā) 父級(jí)的-父級(jí) 的監(jiān)聽(tīng)事件。

如何解決?

  • 在遞歸調(diào)用的時(shí)候也監(jiān)聽(tīng)一下change事件,并間接傳遞到最外層組件(這個(gè)是最容易想到的方法,但是如果組件嵌套很深,簡(jiǎn)直就是個(gè)噩夢(mèng))
  • EventBus(事件總線(xiàn))

EventBus

什么事EventBus?

它其實(shí)就是一個(gè)Vue實(shí)例,有$emit、$on、$off方法,允許從一個(gè)組件向另一組件傳遞數(shù)據(jù),而不需要借助父組件。具體做法是在一個(gè)組件$emit,在另一個(gè)組件$on,可以像下面這樣做:

// main.js
import Vue from 'vue'
import App from './App.vue'

export const eventBus = new Vue(); // creating an event bus.

new Vue({
  render: h => h(App),
}).$mount('#app')

這樣我們來(lái)改造一下 directory.vue,只需要改動(dòng)srcipt部分:

<script>
import NestedDir from "./NestedDir";
import { eventBus } from "../main";

export default {
  name: "directory",
  components: {
    NestedDir
  },
  created() {
    this.catalog = this.getTree()

    eventBus.$on('change', function (data) {
      // todo 向之前一樣處理即可
    })
  },
  destroyed() {
    eventBus.$off('change')
  },
  computed: {
    maxId() {
      return this.arr.lastIndex + 2
    }
  },
  data() {
    return {
      arr: [
        {id: 1, name: '目錄1', type: 'dir', children: []},
        {id: 2, name: '目錄3', type: 'dir', children: [], pid: 1},
        {id: 3, name: '文件2', type: 'file', pid: 1},
        {id: 4, name: '目錄2', type: 'dir', children: []},
        {id: 5, name: '文件1', type: 'file'},
      ],
      title: '',
      dialogFormVisible: false,
      form: {
        id: '',
        name: '',
        type: '',
        pid: ''
      },
      catalog: []
    }
  },
  methods: {
    handleChange(el) {
      this.showDialog(el)
    },
    confirm() {
      this.arr.push({...this.form})
      this.dialogFormVisible = false
      this.catalog = this.getTree()
      this.form = {
        id: '',
        name: '',
        type: '',
        pid: '' , // 父級(jí)的id
      }
    },
    showDialog(el) {
      if (el.type === 'dir') {
        this.title = '新增目錄'
        this.form.children = []
        this.form.type = 'dir'
      } else {
        this.title = '新增文件'
        this.form.type = 'file'
      }
      if (el.id) {
        this.form.pid = el.id
        this.form.id = this.maxId
      } else {
        this.form.id = this.maxId
      }
      this.dialogFormVisible = true
    },
    getTree() {
      this.topNodes.forEach(node => {
        this.getChildren(this.arr, node.children, node.id)
      })
      return this.topNodes
    },
    getChildren(data, result, pid) {
      for (let item of data) {
        if (item.pid === pid) {
          const newItem = {...item, children: []}
          result.push(newItem)
          this.getChildren(data, newItem.children, item.id)
        }
      }
    }
  }
}
</script>

引入了import { eventBus } from "../main";

在頁(yè)面創(chuàng)建時(shí)加入事件監(jiān)聽(tīng),銷(xiāo)毀時(shí)移除事件監(jiān)聽(tīng):

created() {
  eventBus.$on('change', function (data) {
    this.handleChange(data)
  })
},
destroyed() {
  eventBus.$off('change')
}

NestedDir.vue 中也需要做相應(yīng)改動(dòng),只需要修改methods中的add方法:

import { eventBus } from "../main";

//...略

methods: {
  add(el) {
    // this.$emit('change', el)
    eventBus.$emit('change', el)
  }
}

這樣點(diǎn)擊二級(jí)目錄的新增按鈕,就可以正常觸發(fā)彈出框了。

上面的eventBus只在Vue2中有效,Vue3中已經(jīng)移除了$on, $off 這些方法,所以下一篇文章打算自己做一個(gè)Vue的插件來(lái)處理這種類(lèi)似于Pub/Sub的情況。

到此這篇關(guān)于vue嵌套組件傳參實(shí)例分享的文章就介紹到這了,更多相關(guān)vue嵌套組件傳參內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 十分鐘帶你快速上手Vue3過(guò)渡動(dòng)畫(huà)

    十分鐘帶你快速上手Vue3過(guò)渡動(dòng)畫(huà)

    在開(kāi)發(fā)中我們想要給一個(gè)組件的顯示和消失添加某種過(guò)渡動(dòng)畫(huà),可以很好的增加用戶(hù)體驗(yàn),下面這篇文章主要給大家介紹了關(guān)于如何快速上手Vue3過(guò)渡動(dòng)畫(huà)的相關(guān)資料,需要的朋友可以參考下
    2022-02-02
  • 關(guān)于vuejs中v-if和v-show的區(qū)別及v-show不起作用問(wèn)題

    關(guān)于vuejs中v-if和v-show的區(qū)別及v-show不起作用問(wèn)題

    v-if 有更高的切換開(kāi)銷(xiāo),而 v-show 有更高的出事渲染開(kāi)銷(xiāo).因此,如果需要非常頻繁的切換,那么使用v-show好一點(diǎn);如果在運(yùn)行時(shí)條件不太可能改變,則使用v-if 好點(diǎn)
    2018-03-03
  • vue-amap根據(jù)地址回顯地圖并mark的操作

    vue-amap根據(jù)地址回顯地圖并mark的操作

    這篇文章主要介紹了vue-amap根據(jù)地址回顯地圖并mark的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-11-11
  • vue使用$emit時(shí),父組件無(wú)法監(jiān)聽(tīng)到子組件的事件實(shí)例

    vue使用$emit時(shí),父組件無(wú)法監(jiān)聽(tīng)到子組件的事件實(shí)例

    下面小編就為大家分享一篇vue使用$emit時(shí),父組件無(wú)法監(jiān)聽(tīng)到子組件的事件實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • vue proxyTable 接口跨域請(qǐng)求調(diào)試的示例

    vue proxyTable 接口跨域請(qǐng)求調(diào)試的示例

    本篇文章主要介紹了vue proxyTable 接口跨域請(qǐng)求調(diào)試的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • Vue.js實(shí)現(xiàn)圖片的隨意拖動(dòng)方法

    Vue.js實(shí)現(xiàn)圖片的隨意拖動(dòng)方法

    下面小編就為大家分享一篇Vue.js實(shí)現(xiàn)圖片的隨意拖動(dòng)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • vue中ant-design-vue組件的安裝與使用

    vue中ant-design-vue組件的安裝與使用

    Ant Design Vue是使用Vue實(shí)現(xiàn)的遵循Ant Design設(shè)計(jì)規(guī)范的高質(zhì)量UI組件庫(kù),用于開(kāi)發(fā)和服務(wù)于企業(yè)級(jí)中后臺(tái)產(chǎn)品,下面這篇文章主要給大家介紹了關(guān)于vue中ant-design-vue組件安裝與使用的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • vue中如何使用echarts和echarts-gl實(shí)現(xiàn)3D餅圖環(huán)形餅圖

    vue中如何使用echarts和echarts-gl實(shí)現(xiàn)3D餅圖環(huán)形餅圖

    現(xiàn)在vue是很多公司前端的主流框架,我目前所在公司接觸的項(xiàng)目也都是使用vue來(lái)實(shí)現(xiàn)的,很少有完全使用原生的JavaScript來(lái)寫(xiě)項(xiàng)目的了,下面這篇文章主要給大家介紹了關(guān)于vue中如何使用echarts和echarts-gl實(shí)現(xiàn)3D餅圖環(huán)形餅圖的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • vue設(shè)計(jì)一個(gè)倒計(jì)時(shí)秒殺的組件詳解

    vue設(shè)計(jì)一個(gè)倒計(jì)時(shí)秒殺的組件詳解

    這篇文章主要介紹了vue設(shè)計(jì)一個(gè)倒計(jì)時(shí)秒殺的組件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 如何封裝Vue Element的table表格組件

    如何封裝Vue Element的table表格組件

    這篇文章主要介紹了如何封裝Vue Element的table表格組件,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下
    2021-02-02

最新評(píng)論