liger ui组件的抽取与封装

为了让ligerui能更好的工作,我们需要对ligerui的一些常用组件进行封装。首先我们就对最基本的菜单组件进行封装。下面我们先来观察下ligerui中树组件。

       从上面的图片中,我们可以清楚的看到,这就是一棵树。树是一种常用的数据结构,下面引用百度百科的语句:  

树的递归定义:

树(Tree)是n(n≥0)个结点的有限集T,T为空时称为空树,否则它满足如下两个条件:

(1)有且仅有一个特定的称为根(Root)的结点;

(2)其余的结点可分为m(m≥0)个互不相交的子集Tl,T2,…,Tm,其中每个子集本身又是一棵树,并称其为根的子树(Subree)

       下面我们使用接口来描述一颗树。在java中,接口可以很好的描述现实世界中的某种物体具备的行为特点,所以接口非常适合。下面是具体代码:

package net.itaem.ligerui;

import java.util.List;

/**
 * liger ui中菜单模型
 * 这个接口主要用来描述菜单的一些相关操作
 * @date 2014-08-19 10:17 am
 * @author 骆宏
 * @email [email protected]
 *
 * */
public interface ITreeModel {
	/**
	 * 定义一个字符串,用来表示树模型中的菜单节点
	 * */
    String MENU = "menu";

    /**
     * 定义一个字符串,用来表示数模型中的叶子节点
     * */
    String LEAF = "leaf";

    /**
     * 返回当前菜单的结构层次
     * @return 返回菜单的结构层次
     *         如果是叶子节点,那么返回0
     * */
	public int level();

	/**
	 * 返回当前节点的所有子节点,子节点包括了子菜单以及叶子节点
	 * @return 返回当前菜单的全部子节点
	 * */
	public List<ITreeModel> children();

	/**
	 * 返回当前节点的父节点
	 * @return 返回当前节点的父亲节点,如果没有父亲节点,返回null
	 * */
	public ITreeModel parent();

	/**
	 * 返回当前节点的节点类型,这里的节点类型一共有两种,一种是菜单,另外一种是叶子节点
	 * @return 节点类型
	 * @see ITreeModel#MENU
	 * @see ITreeModel#LEAF
	 * */
	public String nodeType();

	/**
	 * 返回当前节点的url
	 * @return 当前节点的url
	 * */
	public String url();

	/**
	 * 放回当前节点的id
	 * @return 当前节点id
	 * */
	public String id();

	/**
	 * 返回节点的名字
	 * @return 节点名字
	 * */
	public String name();

	/**
	 * 当前节点如果是菜单,那么该菜单默认是否展开呢?如果是返回true,代表展开;否则,代表不展开
	 * @return 返回菜单节点的展开状态
	 * */
	public boolean isexpand();

	/**
	 * 设置菜单名字
	 * @param name
	 * */
	public void setName(String name);

	/**
	 * 设置菜单url
	 * @param url
	 * */
	public void setUrl(String url);

	/**
	 * 设置菜单展开状态
	 * @param isexpend
	 * */
	public void setIsexpand(boolean isexpand);

	/**
	 * 设置父节点
	 * @param parent
	 * */
	public void setParent(ITreeModel parent);

	/**
	 * 设置孩子节点
	 * @param children
	 * */
	public void setChildren(List<ITreeModel> children);

	/**
	 * 设置节点id
	 * @param id
	 * */
	public void setId(String id);

	/**
	 * 返回该节点的json数据,包含该节点下面的所有子节点
	 * @return 返回当前节点的json数据
	 * */
	public String toTreeJson();

	/**
	 * 返回从根节点到当前节点的所有节点集合,包含当前节点
	 * @return 返回根节点到当前节点的集合
	 * */
    public List<ITreeModel> route();

    /**
     * 返回以当前节点为根节点的一棵子树
     * @return 返回以当前节点子根节点的子树
     * */
    public List<ITreeModel> subTree();
}

在上面我们只是定义了一个树模型。并没有实现代码,为什么这样子做呢?因为每个框架使用的数据格式都不一样,所以我们流出扩展性。如果我们不适用ligerui,而使用dwz,我们的接口类不需要发生变化,只需要添加一个dwz树模型子类即可,ligerui相关组件的代码就无需修改了。下面使用ligerui实现一个菜单树。具体代码:

package net.itaem.ligerui;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.itaem.vo.MenuVo;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
 * 这里是liger ui树的插件实现类
 * @author 骆宏
 * @date 2014-08-19 19:39 am
 * @email [email protected]
 * */
public class LigerUiTree implements ITreeModel{

	//定义一个level,用来保存树的层次
	private int level = 0;
	//定义一个url,用来保存当前节点的url
	private String url;
	//定义一个id,用来保存当前节点id
	private String id;
	//定义一个isexpend,用来保存节点展开状态
	private boolean isexpand;
	//定义一个name,用来保存节点的名称
	private String name;
	//定义一个parent,用来保存节点的父亲节点
	private ITreeModel parent;
	//定义一个children,用来保存当前节点的所有子节点
	private List<ITreeModel> children;

	public LigerUiTree(){

	}

	/**
	 * 定义一个基本的构造方法,该构造方法的参数都不能为空
	 * @param id 节点id
	 * @param name 节点name
	 * @param url 节点url
	 * */
	public LigerUiTree(String id, String name, String url){
		if(id == null || name == null || url == null) throw new RuntimeException("id name url都不能为空");

		this.id = id;
		this.name = name;
		this.url = url;
	}

	public LigerUiTree(String id, String name, String url, ITreeModel parent) {
		this(id, name, url);
		this.parent = parent;
	}

	public LigerUiTree(String id, String name, String url, List<ITreeModel> children) {
		this(id, name, url);
		this.children = children;
	}

	@Override
	public void setUrl(String url) {
		this.url = url;
	}
	@Override
	public void setId(String id) {
		this.id = id;
	}
	@Override
	public void setIsexpand(boolean isexpand) {
		this.isexpand = isexpand;
	}

    @Override
	public void setName(String name) {
		this.name = name;
	}

	public void setParent(ITreeModel parent) {
		this.parent = parent;
	}

	/**
	 * 这里同时会计算树的层次
	 * 并且这里会同时维护parant - children之间的关联管理,也就是在设置当前节点的子节点时,同时会指点这些子节点的父亲节点为当前节点
	 * */
	public void setChildren(List<ITreeModel> children) {
		if(children == null) return;   //如果为null,do nothing
		this.children = children;

		//设置level,遍历所有的children树,然后取最大值
		int max = -1;
		for(int i=0; i<children.size(); i++){
			children.get(i).setParent(this);   //维护parent-children的相互关联关系
			if(children.get(i).level() > max) max = children.get(i).level();
		}

		//如果添加的节点都是叶子节点,那么当前层次为2
		//否则计算最大的树层次 = 子节点最大的层次 + 1
		if(max != -1 && max != 0){
			level += max + 1;
		}else{
			level = 2;
		}

	}

	@Override
	public int level() {
		//每次要计算树的高度,都必须遍历整棵树的,然后确定树的高度,由于树随时可以被改变,所以这里不适合使用缓存模式
		return level;
	}

	@Override
	public List<ITreeModel> children() {
		return children;
	}

	@Override
	public ITreeModel parent() {
		return parent;
	}

	@Override
	public String nodeType() {
		if(children != null){   //拥有子节点,则代表该节点是菜单
			return MENU;
		}else{
			return LEAF;
		}
	}

	@Override
	public String url() {
		return url;
	}

	@Override
	public String id() {
		return id;
	}

	@Override
	public boolean isexpand() {
		return isexpand;
	}

	@Override
	public String name(){
		return name;
	}

	@Override
	public String toTreeJson() {
		JSONObject json = new JSONObject();
		//生成这个节点的基本数据
		json.put("text", name);
		json.put("isexpand", isexpand);
		json.put("url", url);

		if(parent != null){
			json.put("pid", parent.id());
		}

		//生成这个节点的子菜单数据
		JSONArray childrenJson = new JSONArray();
		if(children != null){
			for(ITreeModel child: children){
				//让每个子menu递归的去生成json数据
				childrenJson.add(toJson(child));
			}
			json.put("children", childrenJson);
		}

		return json.toString();
	}

	 /**
     * 递归入口
     * @see MenuVo#toJson()
     * */
	private String toJson(ITreeModel tree){
		JSONObject json = new JSONObject();
		if(tree.children() != null){
			//生成这个菜单节点的基本数据
			json.put("text", tree.name());
			json.put("id", tree.id());
			if(tree.parent() != null){
			    json.put("pid", tree.parent().id());
		    }
			json.put("isexpand", tree.isexpand());

			//生成这个菜单节点的子菜单数据
			JSONArray childrenJson = new JSONArray();
			if(tree.children() != null){
				for(ITreeModel child: tree.children()){
					//让每个子menu递归的去生成json数据
					childrenJson.add(toJson(child));
				}
				json.put("children", childrenJson);
			}
		}else{   //这个节点不是菜单,是菜单下面的一个具体子节点,该节点已经没有子节点了
			json.put("id", tree.id());
			if(tree.parent() != null){
			    json.put("pid", tree.parent().id());
		    }
			json.put("text", tree.name());
			json.put("url", tree.url());
		}
		return json.toString();
	}

	@Override
	public List<ITreeModel> route() {
		List<ITreeModel> route = new ArrayList<ITreeModel>();
		ITreeModel current = this;
		while(current != null){
			route.add(current);
			current = current.parent();
		}
		java.util.Collections.reverse(route);
		return route;
	}

	@Override
	public List<ITreeModel> subTree() {
		List<ITreeModel> subTree = new ArrayList<ITreeModel>();
		subTree.add(this);
		if(this.children == null) return subTree;

		Iterator<ITreeModel> sti = children.iterator();
		while(sti.hasNext()){
			ITreeModel tm = sti.next();
			subTree.add(tm);
			if(tm.children() != null) subTree.addAll(tm.subTree());
		}

		return subTree;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + (isexpand ? 1231 : 1237);
		result = prime * result + level;
		result = prime * result + (name == null? 0 : name.hashCode());
		result = prime * result + ((url == null) ? 0 : url.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;

		if (obj == null)
			return false;

		if (getClass() != obj.getClass())
			return false;

		LigerUiTree other = (LigerUiTree) obj;

		if (id == null) {
			if (other.id() != null)
				return false;
		} else if (!id.equals(other.id()))
			return false;

		if (isexpand != other.isexpand())
			return false;

		if (level != other.level())
			return false;

		if(name == null){
			if(other.name() != null)
				return false;
		}

		if (url == null) {
			if (other.url() != null)
				return false;
		} else if (!url.equals(other.url()))
			return false;

		return true;
	}

	/**
	 * 返回节点的基本信息
	 * @return
	 * */
	@Override
	public String toString() {
		return "LigerUiTree [name=" + name + ", level=" + level + ", url=" + url + ", id=" + id
				+ ", nodeType=" + nodeType() + ", isexpand=" + isexpand + "]";
	}

}

在LigerUiTree中,我们使用了递归来遍历树。这个代码不难,就是普通的一些树的常用操作。为了测试,我们需要一个工具类,用来输出这个树的数据结果:

package net.itaem.ligerui;

import java.util.List;

/**
 *
 * 这个类用来输出树的结构信息,为了方便测试
 * @author 骆宏
 * @date 2014-08-19
 * @email [email protected]
 * */
public class LigerUiTreeTool {
	/**
	 * 以下面个数来输出树
	 * root
	 *   --child1
	 *   --child2
	 *     --child-child1
	 *     --child-child2
	 *   --child-3
	 * */
	public static void printTree(ITreeModel tree){
		if(tree == null) return;

		if(tree.parent() == null){   //输出根节点的名字
			System.out.println(tree.name());
		}

		List<ITreeModel> children = tree.children();

		if(children != null){
			level++;
			for(int i=0; i<children.size(); i++){
				for(int j=0; j<level; j++){
					System.out.print("  ");
				}

				System.out.println("--" + children.get(i).name());
				if(children.get(i).children() != null)
					printTree(children.get(i));
				else if(i == children.size()-1){
					level = 1;
				}
			}
		}
	}

	//用来辅助输出的一个level,用来计算输出空格
	private static int level = 1;
}

上面的类是用于输出树的,没有大的实际意义。在这个工具树种,我们使用了广度遍历。一般情况下,树的遍历有两种。一种是广度遍历,另外一种则是深度遍历。大家有兴趣可以百度下相关定义以及概念。

    代码差不多了,直接写个测试吧。

    

package net.itaem.test;

import java.util.ArrayList;
import java.util.List;

import net.itaem.ligerui.ITreeModel;
import net.itaem.ligerui.LigerUiTree;
import net.itaem.ligerui.LigerUiTreeTool;

/**
 * 测试liger ui的树模型
 * */
public class LigerUiTreeTest {

	public static void main(String[] args){
		ITreeModel root = new LigerUiTree("ROOT", "根节点", "localhost/root");
		List<ITreeModel> children = new ArrayList<ITreeModel>();
		//生成一个1 * 10 * 3三个层次的树模型
		for(int i=0; i<10; i++){
			ITreeModel child = new LigerUiTree("child-" + i, "child-name-" + i, "localhost/child-" + i);

			List<ITreeModel> childChildren = new ArrayList<ITreeModel>();
			for(int j=0; j<3; j++){
				ITreeModel childChild = new LigerUiTree("children-" + i + "" + j, "child-children-child-" + i + "" + j, "localhost/child/children-" + i + "" + j);
				childChildren.add(childChild);
			}
			child.setChildren(childChildren);
			children.add(child);
		}

		root.setChildren(children);

		System.out.println("======================whole tree=======================");
		LigerUiTreeTool.printTree(root);

		System.out.println("=======================基本信息================================");
        System.out.println(root);

        System.out.println("==========================subTree==============================");
		//输出根节点的子树
		List<ITreeModel> subTree = root.children().get(0).subTree();
		System.out.println(subTree);

		System.out.println("==========================route================================");
		//测试叶子节点到根节点的所有节点
		ITreeModel leaf = root.children().get(0).children().get(0);
		System.out.println(leaf.route());

		System.out.println("==========================after change=========================");
		//测试修改名字,url,name,id,isexpend等属性
		root.setName("change name");
		root.setId("change id");
		root.setIsexpand(true);
		root.setUrl("change url");
		System.out.println(root);

		System.out.println("==============================liger ui tree json==========================");
		System.out.println(root.toTreeJson());
	}
}

下面是程序输出结果:

    

======================whole tree=======================
根节点
    --child-name-0
      --child-children-child-00
      --child-children-child-01
      --child-children-child-02
  --child-name-1
    --child-children-child-10
    --child-children-child-11
    --child-children-child-12
  --child-name-2
    --child-children-child-20
    --child-children-child-21
    --child-children-child-22
  --child-name-3
    --child-children-child-30
    --child-children-child-31
    --child-children-child-32
  --child-name-4
    --child-children-child-40
    --child-children-child-41
    --child-children-child-42
  --child-name-5
    --child-children-child-50
    --child-children-child-51
    --child-children-child-52
  --child-name-6
    --child-children-child-60
    --child-children-child-61
    --child-children-child-62
  --child-name-7
    --child-children-child-70
    --child-children-child-71
    --child-children-child-72
  --child-name-8
    --child-children-child-80
    --child-children-child-81
    --child-children-child-82
  --child-name-9
    --child-children-child-90
    --child-children-child-91
    --child-children-child-92
=======================基本信息================================
LigerUiTree [name=根节点, level=3, url=localhost/root, id=ROOT, nodeType=menu, isexpand=false]
==========================subTree==============================
[LigerUiTree [name=child-name-0, level=2, url=localhost/child-0, id=child-0, nodeType=menu, isexpand=false], LigerUiTree [name=child-children-child-00, level=0, url=localhost/child/children-00, id=children-00, nodeType=leaf, isexpand=false], LigerUiTree [name=child-children-child-01, level=0, url=localhost/child/children-01, id=children-01, nodeType=leaf, isexpand=false], LigerUiTree [name=child-children-child-02, level=0, url=localhost/child/children-02, id=children-02, nodeType=leaf, isexpand=false]]
==========================route================================
[LigerUiTree [name=根节点, level=3, url=localhost/root, id=ROOT, nodeType=menu, isexpand=false], LigerUiTree [name=child-name-0, level=2, url=localhost/child-0, id=child-0, nodeType=menu, isexpand=false], LigerUiTree [name=child-children-child-00, level=0, url=localhost/child/children-00, id=children-00, nodeType=leaf, isexpand=false]]
==========================after change=========================
LigerUiTree [name=change name, level=3, url=change url, id=change id, nodeType=menu, isexpand=true]

哈哈,测试完毕,然后就可以使用Action,将树的数据携带到jsp中,那么一个ligerui的树插件就搞定了。

liger ui组件的抽取与封装

时间: 2024-11-10 14:53:55

liger ui组件的抽取与封装的相关文章

封装一个简单的UI组件

方法其实很简单,用一个函数把整个过程包起来.调用时用new,这样可以在一个页面使用多个改组件.这是一个非常简单的方法,后面还有很大改进的空间.下面是一个封装日历的示例. 现在我们的组件类似bootstrap,写好下面的html结构,然后引入ui.css和ui.js,就可以生成相应的UI组件了.效果如上图. <!doctype html> <html> <head> <meta charset="UTF-8"> <title>C

Android React Native使用原生UI组件

Android React Native 已经将几个常用的原生组件进行了封装,比如 ScrollView 和 TextInput,但是并不是所有系统的原始组件都被封装了,因此有的时候我们不得不自己动手封装一下,从而能够使用那些React Native没有为我们封装的原生组件,比如WebView,官方并没有提供Android端的实现,那么我们现在就动手封装一下WebView. 之前写过一篇文章Android React Native使用原生模块,而使用原生UI组件的方法和使用原生模块的方法十分类似

Android AsyncTask使用心得及错误处理-只能在主线程改变UI组件

大家肯定都会经常使用AsyncTask这个类,特别是在网络处理中,先看改正后的代码:这是正常的代码: class sendKeyTask extends AsyncTask<String, Void, Integer> { @Override protected void onPostExecute(Integer resultCode) { // TODO Auto-generated method stub super.onPostExecute(resultCode); switch (

react native 使用 iOS 原生 UI 组件

目前 react native 的组件还是不多,有些也并不怎么好用,这时候就需要封装原生 UI 组件了 之前写过RN 与 native 的通信 无非就是两种: 1>>>  react native 内部事件需要通知 native 调用 native 的方法(或者传递RN 中的数据到 native),这时候可以用新建一个 manager 之类的文件 RCT_EXPORT_MOUDLE() 暴露 native类  ,RCT_EXPORT_METHOD () 暴露 native 方法给 js

介绍推荐优秀的Vue UI组件库

Vue 是一个轻巧.高性能.可组件化的MVVM库,API简洁明了,上手快.从Vue推出以来,得到众多Web开发者的认可.在公司的Web前端项目开发中,多个项目采用基于Vue的UI组件框架开发,并投入正式使用.开发团队在使用Vue.js框架和UI组件库以后,开发效率大大提高,自己写的代码也少了,很多界面效果组件已经封装好了.在选择Vue UI组件库的过程中,通过GitHub上根据star数量.文档丰富程度.更新的频率以及维护等因素,也收集整理了一些优秀的Vue UI组件库. 下载资源:www.yi

【转】优秀的Vue UI组件库

原文来源:https://www.leixuesong.com/3342 Vue 是一个轻巧.高性能.可组件化的MVVM库,API简洁明了,上手快.从Vue推出以来,得到众多Web开发者的认可.在公司的Web前端项目开发中,多个项目采用基于Vue的UI组件框架开发,并投入正式使用.开发团队在使用Vue.js框架和UI组件库以后,开发效率大大提高,自己写的代码也少了,很多界面效果组件已经封装好了.在选择Vue UI组件库的过程中,通过GitHub上根据star数量.文档丰富程度.更新的频率以及维护

造个自己的Vue的UI组件库类似Element

前言 随着前端的三大框架的出现,组件化的思想越来越流行,出现许多组件库.它能够帮助开发者节省时间提高效率, 如React的Ant-design,Vue的iView,Element等,它们的功能已经很完善了. 我写这遍文章的目的:记录自己搭建UI库的过程(对Vue的理解加深了好多)演示地址首先讲一下思路: 平常写组件时,写一个组件要用时直接导入就行了,如你写了一个time.vue,用的时候 import time from '路径' 现在要写一个组件库,是不是把所有组件一个文件夹里(如button

15. react UI组件和容器组件的拆分 及 无状态组件

1.组件的拆分 组件拆分的前提 当所有的逻辑都出现在一个组件内时 组件会变得非常复杂 不便与代码的维护 所以对组件进行拆分 IU组件 进行页面渲染 容器组件  进行逻辑操作 UI组件的拆分 新建一个 TodoListUI.js 将 TodoList 组件的 render 方法进行拆分封装为 UI 组件 其余的 TodoList 组件为 容器组件 # TodoListUI.js import  React, { Component } from 'react'; import 'antd/dist

Android UI组件进阶(2)——仿Windows对话框

Android UI组件进阶(2)--仿Windows对话框 在开始本章前先祝大家中秋节快乐哈,相信很多上班的朋友都是放三天假的哈! 有时间的话回家陪陪父母吧!树欲静而风不止,子欲养而亲不待!岁月不饶人! 好了,道理和祝福语就说到这里了,今天给大家准备的是模仿Windows风格对话框! 效果图: 相信大部分的AlertDialog都是下面这个样子的: 今天给大家讲解的对话框是下面这样的: 对比两种对话框,站在用户的角度,相信你更加钟情于第二种颜色鲜明的对话框 好了下面就开始讲解如何制作模仿win