如何用vue实现树形菜单?

       在公司培训了2周,布置的作业是从树形,grid分页以及echarts中选一个。由于都不是很熟,就挑了第一个。本来想在网上找找参考,然后模仿着做一个,但是网上的代码多少参差不齐,写到一半没了,所以只要自己写篇博客,记录下实现过程。

一、准备工作:

1.此次树形是用vue实现的,电脑需提前配置好node.js和vue.js,具体怎么配置,这里不作说明。

      1)如果不记得自己有没有安装,可以win+R调出运行窗口,输入cmd,按enter

   

    2)输入node -v和vue -V(注意vue中的-V是大写的)

node -v

vue -V

    

     如果显示了版本号,则意为已安装。

 2.引用奥森图标,进入官网下载包

   

3.需要对vue和webpack有基本的了解

  一切准备就绪后,那么我们就开始吧

二、安装

1.首先在本地创建一个文件夹,命名为vue-tree,进入命令行窗口,然后进入到vue-tree文件夹所在位置

2.安装vue-cli,用cnpm更快

 npm i -g vue-cli

     

     

然后创建一个webpack项目并且下载依赖

vue init webpack vue-tutorial

  

进入到vue-tutorial文件夹里,cd vue-tutorial

npm i

然后

npm run dev

这时我们就可以在localhost:8080中查看我们的应用了。

 三、代码展示

下面进入重点啦~

1.打开你的main.js文件

然后在src/components文件夹下新建2个vue文件,同时新建一个common文件夹,在里面新增一个vue文件,具体看图(这里的font-aswesome是我下载的一个压缩包),layout负责布局展示,index负责树形展示,treeMenu负责渲染。

我们先配置好main.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Layout from './components/layout.vue'
import IndexPages from './common/index.vue'
import myTree from './components/treeMenu.vue'
Vue.use(VueRouter)
let router = new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/',
            component: IndexPages
        }
    ]
})

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<Layout/>',
  components: { Layout }
})

 2.打开layout.vue文件,开始编写(这段样式用的慕课一位讲师的)。其他的组件将在<router-view></router-view>中被渲染出来。

/**
 * 页面的入口,负责页面的布局
 */

<template>
  <div>
    <div class="app-head">
      <div class="app-head-inner">
        <img src="../assets/logo.png">
         <div class="head-nav">
          <ul class="nav-list">
            <li>登录</li>
            <li class="nav-pile">|</li>
            <li>注册</li>
            <li class="nav-pile">|</li>
            <li>关于</li>
          </ul>
        </div>
      </div>
    </div>

    <div class="container">
      <router-view></router-view>
    </div>

    <div class="app-foot">
      <p>© 2017 cindy</p>
    </div>
  </div>
</template>

<script>

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
  display: block;
}
body {
  line-height: 1;
}
ol, ul {
  list-style: none;
}

a {
  color: inherit;
  text-decoration: none;
}
body {
  background: #f0f2f5;
  font-family: "Helvetica Neue",Helvetica,Arial,"Hiragino Sans GB","Hiragino Sans GB W3","Microsoft YaHei UI","Microsoft YaHei","WenQuanYi Micro Hei",sans-serif;
  font-size: 14px;
  color: #444;
}
.app-head {
  background: #363636;
  color: #b2b2b2;
  height: 90px;
  line-height: 90px;
  width: 100%;
}
.app-head-inner {
  width: 1200px;
  margin: 0 auto;
}
.app-head-inner img {
  width: 50px;
  margin-top: 20px;
}
.head-nav {
  float: right;
}
.head-nav ul {
  overflow: hidden;
}
.head-nav li {
  cursor: pointer;
  float: left;
}
.nav-pile {
  padding: 0 10px;
}
.app-foot {
  text-align: center;
  height: 80px;
  width: 100%;
  line-height: 80px;
  background: #e3e4e8;
  clear: both;
  margin-top: 30px;
}
.container {
  width: 1200px;
  height: 470px;
  margin: 0 auto;
}
ul li {
  padding-left: 10px;
}

</style>

 3.打开index.vue文件,代码如下,树形主要在<ul v-for="menuItem in theModel"> <myTree class="item" :model="menuItem"></myTree> </ul>实现。

/**
 * 树形和echarts的展示
 */
<template>
  <div class="index-wrap">
    <div class="index-left">
      <div class="index-left-block">
        <h2>树形侧边导航栏</h2>
        <ul v-for="menuItem in theModel">
          <myTree class="item" :model="menuItem"></myTree>
        </ul>
      </div>
    </div>
    <div class="index-right">
      <div class="index-right-block">
      </div>
    </div>
  </div>
</template>

<script>
import myTree from '../components/treeMenu.vue'var myData =[{
  'id': '1',
  'menuName': 'echarts',
  'menuCode': '10',
  'children': [
  {
    'menuName': '地图',
    'menuCode': '11',
  },
  {
    'menuName': '柱状图',
    'menuCode': '12',
    'children': [
    {
      'menuName': '交错正负轴标签',
      'menuCode': '121'
    },
    {
      'menuName': '柱状图框选 ',
      'menuCode': '122'
    },
    {
      'menuName': '堆叠柱状图',
      'menuCode': '124'
    }]
  },
  {
    'menuName': '条形图',
    'menuCode': '13'
  }]
},
{
  'id': '2',
  'menuName': '树形结构',
  'menuCode': '21'
},
{
  'id': '3',
  'menuName': 'gird分页',
  'menuCode': '30'
            }]

export default {
  name: 'items',
  props: ['model'],
  components: {
    myTree
  },
  data () {
    return {
      theModel: myData
    }
  }
}
</script>

<style scoped>
.index-wrap {
  width: 1200px;
  margin: 0 auto;
  overflow: hidden;
}
.index-left {
  float: left;
  width: 300px;
  text-align: left;
}
.index-right {
  float: left;
  width: 900px;
}
.index-left-block, .index-right-block{
  height: 450px;
  margin: 15px;
  background: #fff;
  box-shadow: 0 0 1px #ddd;
}

.index-left-block h2,.index-right-block h2 {
  background: #4fc08d;
  color: #fff;
  padding: 20px 20px;
  font-size: 1.5em;
}

.item {
  cursor: pointer;
}
ul{
  line-height: 40px;
  list-style-type: dot;
}

li div:active,li div:hover {
  background: #9FDABE;
  color: #eee;
}

ul li:hover {
  background: #A6C2B0;
}

</style>

4.最重要的一个文件:treeMenu.vue。这个文件里有用到font-awesome,需要大家自行去官网下载。然后将压缩包解压后,放到src的下面。我将文件夹重名为“font-awesome”,然后在<script></script>标签里引用import '../font-awesome/css/font-awesome.min.css'

/**
 * 树的组件,主要功能在这里实现
 * 
 */
<template>
  
  <li>
    <div @click="toggle" @dblclick="changeType">
      <!-- isFolder判断是否存在子级改变图标 -->
      <i v-if="isFolder"uk-animation-="" class="fa " :class="[open?'fa-folder-open':'fa-folder']"></i>
     
      <i v-if="!isFolder" class="fa fa-file-image-o"></i>
      {{ model.menuName }}
      <i v-if="isFolder" class="fa " :class="[open ? 'fa-chevron-down' : 'fa-chevron-right']" style="display: inline-block;float: right;padding:13px 20px 0 0;"></i>
     
      
    </div>

    <ul v-show="open" v-if="isFolder">
      <tree-menu v-for="item in model.children" :model="item"></tree-menu>
      <li class="add" @click="addChild">
        <i class="fa fa-plus-square-o" style="padding-left: 20px;">
          <i style="display: inline-block;padding-left: 20px;">add</i>
        </i>
      </li>
    </ul>
  </li>
</template>

<script>
import '../font-awesome/css/font-awesome.min.css'
import Vue from 'vue'
export default {
  name: 'treeMenu',
  props: ['model'],
  data() {
    return {
      open: false,
    }
  },
  computed: {
   isFolder:function() {
     return this.model.children && this.model.children.length
   }
  },
  methods: {
  toggle: function() {
      if(this.isFolder) {
        this.open = !this.open
      }
   },
    changeType: function() {
      if(!this.isFolder) {
        Vue.set(this.model,'children',[])
        this.addChild()
        this.open = true
      }
    },
    addChild: function() {
      this.model.children.push({
        name:'new stuff'
      })
    }
  }
}
</script>

<style scoped>

ul {
  line-height: 40px;
  list-style-type: dot;
}
li div:active,li div:hover {
  background: #9FDABE;
  color: #eee;
}

ul li:hover {
  background: #A6C2B0;
}


.fa-folder-open, .fa-folder, .fa-file-image-o {

  padding:0 20px;
}



</style>

所以处理完之后,就是这样子的啦(echarts是后面加上去的,可以不用管)

我把代码放到github上了,大家可以下载看看(github上的代码包含了echarts,大家注意搭配我的博客看)

https://github.com/yuegreen/vueTree

官网中也有关于树组件的实现,大家可以去参考参考

https://cn.vuejs.org/v2/examples/tree-view.html

如果对本文章有什么问题和建议,欢迎在评论区讨论~

原文地址:https://www.cnblogs.com/cindy79/p/7229196.html