关于vue.js:vue嵌套组件传参

vue父子组件参数传递

咱们个别应用prop给子组件传递参数,在子组件中应用$emit触发父组件中监听的事件,并且能够附带参数。

比方咱们封装了一个名为 NestedDir 的子组件(嵌套目录的意思),内容如下(用到了element ui组件):

<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>

能够看出这个 NestedDir 接管父级传来的 nested 数组类型的数据,并且它的外部点击 新增目录、新增文件,能够触发 父级 监听的 change 事件。比拟非凡的是这个组件中调用了本人:

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

因为咱们会传递给它的 nested 数据结构大略是上面的样子:

[{
    "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": []
}]

父组件中调用:

<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="名称">
          <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
    }
  },
  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: ''
      }
    },
    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() {
      let obj = {}
      this.arr.forEach(item => {
        if (item.pid) {
          obj[item.pid].children.push(item)
        } else {
          item.children = []
          obj[item.id] = item
        }
      })
      return Object.values(obj)
    }
  }
}
</script>

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

渲染出的页面是上面的样子:

深层递归组件事件失落

这样咱们结构出了一个实践上能够有限嵌套的目录构造,然而通过测试发现 在二级目录上的新增按钮点击是没有任何反馈的,起因是咱们在 NestedDir 中调用了它本人导致事件失落,因为它无奈触发父级的父级的监听事件。

todo 如何解决?

$attrs

$listeners

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理