赞
踩
近期在进行vue的学习,自研的vue项目需要一个tree组件。由于在学习阶段,不想‘拿来主义’,拿别人写好的组件使用,对于处于学习阶段的开发者来说不是一件好事,虽然拿别人开发好的东西过来用可以快速进行业务开发,但阻绝了学习者锻炼自身开发技能的机会。‘拿来主义’的学习方式,与其说是学习一门语言,不如说是学习一种成熟组件的使用方式。自己动手写一写还是非常有利于自身水平提升的。于是,开始动手自己写vue-tree组件。
- <template>
- <div class='cus_vtree_wrap' @click.capture='clickNodeWrap'>
- <v-tree-item :treeData='treeData' @clickNodeCom='clickNode' :checkBox='checkBox' :class='{tree_root_lonely:treeData.length === 1}' @toggleCheckBox="checkBoxFun"></v-tree-item>
- </div>
- </template>
-
- <script>
- export default{
- name:'vue-tree',
- props:['treeData','checkBox'],
- data(){
- return {
- //userData:this.treeData
- }
- },
- mounted(){
- this.initData(true,true,true);
- },
- updated(){
- this.initData(true,true,true);
- },
- methods:{
- initData(expandInit,activeInit,checkedInit){
- var self = this;
- var modifyDataFun = function(datas){
- if(datas){
- datas.forEach( (m,index) => {
- if(expandInit){
- self.$set(m,'expand',true);
- }
- if(activeInit){
- self.$set(m,'active',false);
- }
- if(checkedInit){
- self.$set(m,'checked',false);
- self.$set(m,'partchecked',false);
- }
- if(index === datas.length - 1){
- self.$set(m,'last',true);
- }
- if(m.children){
- modifyDataFun(m.children);
- }
- });
- }
- }
- modifyDataFun(this.treeData);
- },
- clickNode(data){
- this.$emit('clickNode',data);
- },
- clickNodeWrap(){
- this.initData(false,true,false);
- },
- checkBoxFun(item){
-
- },
- getCheckedNodes(){
- var resultArr = [];
- var getCheckedNodesFun = (datas) => {
- if(datas){
- datas.forEach((m)=>{
- if(m.checked === true){
- resultArr.push(m);
- }
- if(m.children){
- getCheckedNodesFun(m.children);
- }
- })
- }
- };
- getCheckedNodesFun(this.treeData);
- return resultArr;
- },
- getRoot(){
- return this.treeData[0];
- },
- findNode(selectedId){
- var result;
- var findNodeFun = (datas) => {
- if(datas){
- try{
- datas.forEach((m) => {
- if(m.id === selectedId){
- result = m;
- throw new Error('stop');
- }
- if(m.children){
- findNodeFun(m.children);
- }
-
- });
- }catch(e){
-
- }
-
- }
- };
- findNodeFun(this.treeData);
- return result;
- },
- setSelectedNode(node,clickDiv){
- var select;
- var that = this;
- var setSelectedFun = (datas) => {
- if(datas){
- datas.forEach((m) => {
- if(m.id === node.id){
- m.active = true;
- select = m;
- if(clickDiv) {
- var dom = document.getElementById(m.id);
- if(dom && dom.className.indexOf('cus_item_content') > -1){
- dom.click();
- }else {
- var doms = document.getElementsByClassName('cus_item_content');
- for(var y = 0 ; y < doms.length ;y ++){
- if(doms[y].id === m.id){
- doms[y].click();
- break;
- }
- }
- }
-
- }
- }else {
- m.active = false;
- }
- if(m.children){
- setSelectedFun(m.children);
- }
- });
- }
- };
- setSelectedFun(this.treeData);
- return select;
- },
- getSelectedNode(){
- var resultNode = null;
- var getSelectedFun = (datas) => {
- if(datas){
- datas.forEach((m) => {
- if(m.active === true){
- resultNode = m;
- return;
- }
- if(m.children){
- getSelectedFun(m.children)
- }
- })
- }
- };
- getSelectedFun(this.treeData);
- return resultNode;
- },
- getParentNode(node){
- var resultNode = null;
- var getParentNode = (datas,parent) => {
- if(datas){
- try{
- datas.forEach( (m) => {
- if(node && m.id === node.id){
- resultNode = parent;
- throw new Error("Stop");
- }
- if(!resultNode && m.children){
- getParentNode(m.children,m);
- }
- } );
- }catch(e){
-
- }
-
- }
- }
- getParentNode(this.treeData,null);
- return resultNode;
- },
- getParentNodesArr(node){
- var resultArr = [];
- var parentNode ;
- var getParent = (target) => {
- parentNode = this.getParentNode(target);
- if(parentNode){
- resultArr.push(parentNode);
- getParent(parentNode);
- }
- };
- getParent(node);
- return resultArr;
-
- }
- },
- components:{'v-tree-item':{
- name:'v-tree-item',
- template:'<ul class="cus_tree_ul" :class="{cus_tree_ulLine:(treeData && treeData.length)}"><li v-for="item in treeData"><div class="cus_item_content" :title="item.text" @click="clickNode(item)" :id= item.id :class="{active:item.active}">'+
- '<span class="treeExpandBtn" @click.stop="toggleNode(item)" :class="{butopen:item.expand && item.children,btnclose:!item.expand && item.children,line: !item.last && !item.children,lastLine:item.last&&!item.children}"></span><span class="tree-icon" :class="item.icon"></span>'+
- '<span v-if="checkBox" @click="checkBoxClick(item)" class="cus_chekcbox" :class="{cus_chekcbox_checked:item.checked,cus_chekcbox_part_checked:item.partchecked}"></span>{{item.text}}</div>'+
- '<v-tree-item :treeData="item.children" v-if="item.expand" @clickNodeCom="clickNodeCom" :checkBox="checkBox" :class="{cus_checkbox_allchecked:item.checked}" @toggleCheckBox="checkBoxFun(item)" ></v-tree-item> </li></ul>',
-
- methods:{
- clickNode(item){
- item.active = true;
- this.$emit('clickNodeCom',item);
- },
- toggleNode(item){
- item.expand = !item.expand;
- item.active = true;
- },
- clickNodeCom(data){
- this.$emit('clickNodeCom',data);
- },
- checkBoxClick(item){
-
- item.partchecked = false;
- item.checked = !item.checked;
- //设置子元素是否勾选
- var checkChildFun = (childrenDatas) => {
- childrenDatas.forEach((m) => {
- m.checked = item.checked;
- if(m.children){
- checkChildFun(m.children);
- }
- })
- }
- if(item.children){
- checkChildFun(item.children);
- }
-
-
- this.$emit('toggleCheckBox');
- },
- checkBoxFun(item){
- var checkedNum = 0;
- var partCheckedNum = 0;
- item.children.forEach((li) => {
-
- if(li.checked === true){
- checkedNum++;
- }else if(li.partchecked === true){
- partCheckedNum++;
- }
- })
- if(checkedNum === item.children.length){ //全选
- item.checked = true;
- item.partchecked = false;
- }else if(checkedNum > 0 || partCheckedNum > 0){ //部分勾选
- item.checked = false;
- item.partchecked = true;
- }else{ //没有勾选
- item.checked = false;
- item.partchecked = false;
- }
-
- this.$emit('toggleCheckBox')
- },
-
- },
- props:['treeData','checkBox']
- }}
-
- }
- </script>
-
- <style>
- .cus_vtree_wrap>ul:first-child{
- background-image:none;
- }
- ul.cus_tree_ul{
- padding-left:16px;
- background-image:url('../images/index.gif');
- background-position:4px 10px;
- background-repeat:repeat-y;
- }
- li:last-child>ul.cus_tree_ul:last-child{
- background-image:none;
- }
-
- ul.cus_tree_ul li{
- text-align:left;
- cursor:pointer;
- list-style:none;
-
- }
-
- .cus_item_content span.treeExpandBtn{
- display:inline-block;
- width:18px;
- height:18px;
- margin-right:6px;
- background-image:url('../images/zTreeStandard.png');
-
- }
-
- .cus_vtree_wrap>ul> li:first-child>.cus_item_content>span.treeExpandBtn.butopen{
- background-position:-92px 0px
- }
- li .cus_item_content span.treeExpandBtn.butopen{
- background-position:-92px -18px
- }
- li:last-child .cus_item_content span.treeExpandBtn.butopen{
- background-position:-92px -36px
- }
- .cus_vtree_wrap ul.tree_root_lonely>li>.cus_item_content>span.treeExpandBtn.butopen{
- background-position:-92px -54px
- }
-
- .cus_vtree_wrap>ul> li:first-child>.cus_item_content>span.treeExpandBtn.btnclose{
- background-position:-74px -0px
- }
- li .cus_item_content span.treeExpandBtn.btnclose{
- background-position:-74px -18px
- }
- li:last-child .cus_item_content span.treeExpandBtn.btnclose{
- background-position:-74px -36px
- }
- .cus_vtree_wrap ul.tree_root_lonely>li>.cus_item_content>span.treeExpandBtn.btnclose{
- background-position:-74px -54px
- }
-
- .cus_item_content span.treeExpandBtn.lastLine{
- background-position:-56px -36px
- }
- .cus_item_content span.treeExpandBtn.line{
- background-position:-56px -18px
- }
-
- .cus_item_content .cus_chekcbox{
- display:inline-block;
- width:14px;
- height:14px;
- margin-right:6px;
- background-image:url('../images/zTreeStandard.png');
- background-position:-0px -0px
- }
- .cus_item_content .cus_chekcbox.cus_chekcbox_checked{
- background-position:-14px -0px
- }
- .cus_item_content .cus_chekcbox.cus_chekcbox_part_checked{
- background-position:0px -42px
- }
-
- ul.cus_tree_ul li .cus_item_content{
- padding:4px;
- white-space: nowrap;
- overflow-x:hidden;
- }
- ul.cus_tree_ul li .cus_item_content:hover{
- background:#8f83e1;
- color:white
- }
- ul.cus_tree_ul li .cus_item_content.active{
- background:#7663f8;
- color:white;
- }
-
- .folder{
- display:inline-block;
- width:16px;
- height:16px;
- margin-right:6px;
- background-image:url('../images/zTreeStandard.png');
- background-position:-110px -0px
- }
- .file{
- display:inline-block;
- width:18px;
- height:18px;
- margin-right:6px;
- background-image:url('../images/zTreeStandard.png');
- background-position:-110px -30px
- }
- </style>
安装:npm install vue-tree-jf --save
引用:
- import vueTree from 'vue-tree-jf'
-
- Vue.use(vueTree);
-
-
- .....
- <vue-tree :treeData='datas' ref='vtree' @clickNode ='clickNode' ></vue-tree>
-
参数 | 类型 | 默认值 | 描述 |
treeData | Array | 数据源,包含'id','text','icon','children'属性。 示例:[ {text:'xiaoming', id:'1', icon:'folder', children:[ {text:'1-1', id:'1-1', icon:'folder', children:[ {text:'1-1-1', id:'1-1-1', icon:'file', },{text:'1-1-2', id:'1-1-2', icon:'file' }] },{ text:'1-2', id:'1-2', icon:'folder', }] } ] | |
checkBox | Boolen | false | 是否显示checkbox |
transitionTime | Number | 200 | 折叠动画时间,单位ms |
expand | Boolean | true | 初始化时是否展开节点 |
参数名称 | 类型 | 默认值 | 描述 |
text | String | 节点名称 | |
id | String | 节点id | |
icon | String | 节点图标 | |
children | Array | 节点的子节点 |
方法名称 | 参数 | 返回值 | 描述 |
getSelectedNode | - | 返回选中的tree节点 | |
getCheckedNodes | - | 返回多选的tree节点 | 在多选属性checkbox为true时有效。 |
getRoot | - | 获取树根节点。 | |
findNode | nodeId | 节点id | 获根据id获取选中节点数据。 |
setSelectedNode | node,ifClick | node:节点数据,包含id字段即可。 ifClick:是否触发点击事件 | 设置树节点选中。 |
getParentNode | node | node:节点对象(包含id属性即可) | 获取父节点数据。 |
getParentNodesArr | node | node:节点对象(包含id属性即可) | 获取所有祖先节点数据数组。 |
事件名称 | 参数 | 参数说明 | 描述 |
clickNode | node | 当前点击节点的数据 | 节点点击时触发 |
更新版本(1.0.7):
1.修改选中样式;
2.新增折叠动画特效,通过transitionTime控制折叠动画时间
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。