视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
vue递归组件实战之简单树形控件实例代码
2020-11-27 21:51:45 责编:小采
文档


1、递归组件-简单树形控件预览及问题

 

在编写树形组件时遇到的问题:

  • 组件如何才能递归调用?
  • 递归组件点击事件如何传递?
  • 2、树形控件基本结构及样式

    <template>
     <ul class="vue-tree">
     <li class="tree-item">
     <div class="tree-content"><!--节点内容-->
     <div class="expand-arrow"></div><!--展开或收缩节点按钮-->
     <div class="tree-label">小学</div><!--节点文本内容-->
     </div>
     <ul class="sub-tree"><!--子节点-->
     <li class="tree-item expand">
     <div class="tree-content">
     <div class="expand-arrow"></div>
     <div class="tree-label">语文</div>
     </div>
     </li>
     <li class="tree-item">
     <div class="tree-content">
     <div class="expand-arrow"></div>
     <div class="tree-label">数学</div>
     </div>
     </li>
     </ul>
     </li>
     </ul>
    </template>
    
    <style lang="stylus">
    .vue-tree{
     list-style: none;
     padding: 0;
     margin: 0;
     .tree-item{
     cursor: pointer;
     transition: background-color .2s;
     .tree-content{
     position: relative;
     padding-left: 28px;
     &:hover{
     background-color: #f0f7ff;
     }
     }
     .expand-arrow{
     position: absolute;
     top: 0;
     left: 0;
     width: 28px;
     height: 28px;
     cursor: pointer;
     &::after{
     position: absolute;
     top: 50%;
     left: 50%;
     display: block;
     content: ' ';
     border-width: 5px;
     border-style: solid;
     border-color: transparent;
     border-left-color: #ccc;
     margin: -5px 0 0 -2.5px;
     transition: all .2s;
     }
     }
     &.expand{
     &>.tree-content{
     background-color: #f0f7ff;
     &>.expand-arrow{
     &::after{
     transform: rotate(90deg);
     margin: -2.5px 0 0 -5px;
     }
     }
     }
     }
     .tree-label{
     height: 28px;
     line-height: 28px;
     font-size: 14px;
     }
     .sub-tree{
     display: none;
     list-style: none;
     padding: 0 0 0 28px;
     margin: 0;
     }
     &.expand>.sub-tree{
     display: block;
     }
     &.no-child{
     &>.tree-content{
     &>.expand-arrow{
     display: none;
     }
     }
     }
     }
    }
    </style>

    3、组件目录及数据结构

    目录结构

    vue-tree

    VueTree.vue
    TreeItem.vue

    树形控件数据结构

    let treeData = [
     {
     text: "一级", // 显示的文字
     expand: false, // 默认是否展开
     children: [ // 子节点
     {
     text: "一级-1",
     expand: false,
     },
     {
     text: "一级-2",
     expand: false,
     children: [
     {
     text: "一级-2-1",
     expand: false,
     },
     {
     text: "一级-2-2",
     expand: false,
     }
     ]
     }
     ]
     }
    ];
    

    3.1、 TreeItem.vue 代码

    <template>
     <li class="tree-item" :class="{expand: isExpand, 'no-child': !treeItemData.children || treeItemData.children.length === 0}">
     <div class="tree-content" @click="_clickEvent">
     <div class="expand-arrow" @click.stop="expandTree()"></div>
     <div class="tree-label">{{treeItemData.text}}</div>
     </div>
     <ul class="sub-tree" v-if="treeItemData.children && treeItemData.children.length > 0">
     <!--TreeItem组件中调用TreeItem组件-->
     <TreeItem
     v-for="item in treeItemData.children"
     :tree-item-data="item"
     :key="uuid()"
     :tree-click-event="treeClickEvent"></TreeItem>
     </ul>
     </li>
    </template>
    
    <script>
     export default {
     name: "TreeItem",
     props: {
     treeItemData: {
     type: Object,
     default(){
     return {};
     }
     },
     // 节点点击事件
     treeClickEvent: {
     type: Function,
     default() {
     return function () {};
     }
     }
     },
     data(){
     return {
     // 节点是否展开
     isExpand: this.treeItemData.expand || false
     }
     },
     methods: {
     // 展开/收缩
     expandTree(flag){
     if(!this.treeItemData.children || this.treeItemData.children.length === 0){
     return;
     }
     if(typeof flag === 'undefined'){
     flag = !this.isExpand;
     }else{
    
     flag = !!flag;
     }
     this.isExpand = flag;
     },
     // 创建一个唯一id
     uuid(){
     let str = Math.random().toString(32);
     str = str.substr(2);
     return str;
     },
     // 节点点击事件
     _clickEvent(){
     // 如果有传递事件函数,则调用事件函数并传递当前节点数据及组件
     if(this.treeClickEvent && typeof this.treeClickEvent === 'function'){
     this.treeClickEvent(this.treeItemData, this);
     }
     }
     }
     }
    </script>

    3.1.1、解决 组件如何才能递归调用? 问题

    在组件模板内调用自身 必须明确定义组件的name属性 ,并且递归调用时组件名称就是name属性。如在 TreeItem.vue 组件中组件的name名称为'TreeItem',那么在template中调用时组件名称就必须是 <TreeItem> 。

    当然也可以全局注册组件,具体可以查看vue官方文档 递归组件

    3.1.2、解决 递归组件点击事件如何传递? 问题

    我这里的解决方案是使用 props 将事件函数传递进来,在点击节点的时候调用事件函数,并把相应的数据传递进去。

    之前也尝试过使用 $emit 的形式并把数据传递过去,由于是递归组件,这样一直 $emit ,到最外层时传递的数据就变了,比如传递是第3层节点的数据,到最后执行时数据就变成第1层节点的数据了

    4、 VueTree.vue 组件

    <template>
     <ul class="vue-tree">
     <TreeItem
     v-for="(item, index) in treeData"
     :key="index"
     :treeItemData="item"
     :tree-click-event="treeClickEvent"></TreeItem>
     </ul>
    </template>
    
    <script>
     import TreeItem from "./TreeItem";
     export default {
     name: "VueTreeMenu",
     components: {
     TreeItem
     },
     props: {
     // 树形控件数据
     treeData: {
     type: Array,
     default(){
     return [];
     }
     },
     // 节点点击事件
     treeClickEvent: {
     type: Function,
     default() {
     return function () {};
     }
     }
     }
     }
    </script>
    
    <style lang="stylus">
    .vue-tree{
     list-style: none;
     padding: 0;
     margin: 0;
     .tree-item{
     cursor: pointer;
     transition: background-color .2s;
     .tree-content{
     position: relative;
     padding-left: 28px;
     &:hover{
     background-color: #f0f7ff;
     }
     }
     .expand-arrow{
     position: absolute;
     top: 0;
     left: 0;
     width: 28px;
     height: 28px;
     cursor: pointer;
     &::after{
     position: absolute;
     top: 50%;
     left: 50%;
     display: block;
     content: ' ';
     border-width: 5px;
     border-style: solid;
     border-color: transparent;
     border-left-color: #ccc;
     margin: -5px 0 0 -2.5px;
     transition: all .2s;
     }
     }
     &.expand{
     &>.tree-content{
     background-color: #f0f7ff;
     &>.expand-arrow{
     &::after{
     transform: rotate(90deg);
     margin: -2.5px 0 0 -5px;
     }
     }
     }
     }
     .tree-label{
     height: 28px;
     line-height: 28px;
     font-size: 14px;
     }
     .sub-tree{
     display: none;
     list-style: none;
     padding: 0 0 0 28px;
     margin: 0;
     }
     &.expand>.sub-tree{
     display: block;
     }
     &.no-child{
     &>.tree-content{
     /*padding-left: 0;*/
     &>.expand-arrow{
     display: none;
     }
     }
     }
     }
    }
    </style>

    5、使用树形组件

    <template>
     <div class="app" id="app">
     <VueTree :tree-data="treeData2" :tree-click-event="treeClickEvent"></VueTree>
     </div>
    </template>
    
    <script>
    import VueTree from "./components/vue-tree/VueTree";
    
    export default {
     name: 'app',
     data(){
     return {
     treeData2: [
     {
     text: "一级", // 显示的文字
     expand: false, // 默认是否展开
     children: [
     {
     text: "二级-1",
     expand: false,
     },
     {
     text: "二级-2",
     expand: false,
     children: [
     {
     text: "三级-1",
     expand: false,
     },
     {
     text: "三级-2",
     expand: false,
     children: [
     {
     text: "四级-1",
     expand: false,
     }
     ]
     }
     ]
     }
     ]
     },
     {
     text: "一级-2",
     expand: false
     }
     ]
     }
     },
     methods: {
     treeClickEvent(item, treeItem){
     console.log(item);
     }
     },
     components: {
     VueTree
     }
    }
    </script>

    总结

    以上所述是小编给大家介绍的vue递归组件实战之简单树形控件实例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
    如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

    下载本文
    显示全文
    专题