zTree初体验--MVC linq动态多条件OR查询

  工作需要,使用zTree实现了一个点击显示下拉复选框列表选中项作为查询条件的功能。简单记录下菜鸟级开发历程。

  zTree:是一个依靠jQuery实现的多功能树控件。通过简单引用配置就可使用。

  具体使用:

(1)、脚本、样式引用

注意:引用顺序,zTree.js一定放最后。

<link rel="stylesheet" href="@Url.Content("~/Scripts/jquery.plugins/zTree/zTreeStyle.css")" type="text/css">
<script src="@Url.Content("~/Scripts/jquery.plugins/zTree/jquery.ztree.core-3.5.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.plugins/zTree/jquery.ztree.excheck-3.5.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.plugins/jquery.json.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.plugins/zTree/zTree.js")"></script>

(2)、前台展示

说明:txt_InfoSource用来展示选中复选框后的数据,DashBoardCheckList为后台查询条件模型传递数据(怎么让txt_InfoSource为模型传递数据?!)。灰色背景为zTree控件展示。

<div style="display:inline-block;">
        <div style="display:inline-block;">
            <input type="text" id="txt_InfoSource" class="width_130" readonly="readonly" value="@ViewBag.CheckList" />
            @Html.HiddenFor(MODEL => MODEL.DashBoardCheckList, new { @id = "DashBoardCheckList", @readonly = "readonly" })
        </div>
        <div id="menuContent" class="menuContent" style="display:none;z-index: 1000; position: absolute; background: #eee;">
            <ul id="tree" class="ztree" style=""></ul>
        </div>
    </div>

(3)、操作脚本

   因为我实现了两个一样的功能,只是数据显示不一样,所以就写了两套zTree

var functionManage = new FunctionManage();
var zTree;
$(document).ready(function ($) {
    functionManage.Init();
});

/// <summary>构造函数
///   <para></para>
/// </summary>
function FunctionManage() {
    //当前操作类型: 0= 默认值, 1= 添加新的, 2 = 更新
    this.CurOperType = 0;
    this.CurFunNode = null; //当前选择菜单节点对象
}

//**********public methods*************************
/// <summary>初始化
///   <para>这是一个详细信息</para>
/// </summary>
/// <param name="_parameter" type="String">参数说明</param>
/// <return></returen>
FunctionManage.prototype.Init = function (_parameter) {
    this._BindEvent();
    this.LoadFunctionTree();
}
//**********private event methods******************

/// <summary>绑定,注册点击事件
///  <para></para>
/// </summary>
FunctionManage.prototype._BindEvent = function () {
    var _this = this
    $("#txt_InfoSource").click(function () {
        $("#menuContent").show();
        $("body").bind("mousedown", _this.CaseStateOnBodyDown);
    });

    $("#txt_InfoSource2").click(function () {
        $("#menuContent2").show();
        $("body").bind("mousedown", _this.CaseStateOnBodyDown);
    });
}

/// <summary>加载功能树,在这里配置zTree的相关属性、事件,注意:回调事件名必须与官方一致,实现随意。
/// <para></para>
/// </summary>
FunctionManage.prototype.LoadFunctionTree = function () {
    var setting = {
        check: {
            enable: true
        },
        view: {
            dblClickExpand: false,
            showLine: true,
            selectedMulti: false
        },
        data: {
            simpleData: {
                enable: true,
                idKey: "id",
                pIdKey: "pId",
                rootPId: ""
            }
        },
        callback: {
            onClick: functionManage.zTreeOnClick
            , onRightClick: functionManage.OnRightClick
            , onCheck: functionManage.zTreeOnClick
        }
    };
  

  //请求加载数据
    $.post("/TrackerGraph/GetModuleNameTreeList", { "ModuleName": $("#txt_InfoSource").val(), CoveredName: $("#txt_InfoSource2").val() }, function (data) {
        
    //我的返回数据类型是根据ModuleName和CoveredName返回 json+"="+json.
    //总感觉这么玩字符串略麻烦,不知有没有简单些的方式?!
     var array = new Array();
     //分割字符串
        array = data.split("=");
        var returnMsg = JSON.parse(array[0])
        if (returnMsg.Success) {
       //给树赋值
            $.fn.zTree.init($("#tree"), setting, JSON2.parse(returnMsg.Data));
            zTree = $.fn.zTree.getZTreeObj("tree");
        }
        else {
            alert(returnMsg.Message);
        }
        returnMsg = JSON.parse(array[1])
        
        if (returnMsg.Success) {
            $.fn.zTree.init($("#tree2"), setting, JSON2.parse(returnMsg.Data));
            zTree = $.fn.zTree.getZTreeObj("tree2");
        }
        else {
            alert(returnMsg.Message);
        }
    });
}

/// <summary>复选框选择事件
///   <para></para>
/// </summary>
FunctionManage.prototype.zTreeOnClick = function (e, treeId, treeNode) {
    var zTree = $.fn.zTree.getZTreeObj(treeId),
    nodes = zTree.getCheckedNodes(true),
    vName = "";
    var statusValue = "", solStatusValue = ""; //主表状态,处理状态值。
    for (var i = 0, l = nodes.length; i < l; i++) {
        if (nodes[i].isParent == false) {
       //每个节点都有nsme跟value,用起来很方便
            statusValue += nodes[i].value + ",";
            vName += nodes[i].name + ",";
        }
    }

    vName = vName.substr(0, vName.length - 1);
  //选择节点后,更新前台数据
    if (treeId == "tree") {
        $("#txt_InfoSource").val(vName.toString());
        $("#DashBoardCheckList").val(vName.toString());
    }
    if (treeId == "tree2") {
        $("#txt_InfoSource2").val(vName.toString());
        $("#CoveredModelCheckList").val(vName.toString());
    }

}

/// <summary>显示树
///   <para>控件ID</para>
/// </summary>
FunctionManage.prototype.showMenu = function (controlID) {
    var cityObj = $("#" + controlID);
    var cityOffset = $("#" + controlID).offset();
    if (controlID == "aInfoSource") {
        //cityOffset.top + cityObj.outerHeight()
        $("#menuContent").css({ left: cityOffset.left + "px", top: 60 + "px" }).slideDown("fast");
        $("body").bind("mousedown", this.CaseStateOnBodyDown);
    }
    if (controlID == "menuStreet") {
        $("#divStreet").css({ left: cityOffset.left + "px", top: cityOffset.top + cityObj.outerHeight() + "px" }).slideDown("fast");
        $("body").bind("mousedown", this.StreetOnBodyDown);
    }

    if (controlID == "aInfoSource2") {
        $("#menuContent2").css({ left: cityOffset.left + "px", top: 60 + "px" }).slideDown("fast");
        $("body").bind("mousedown", this.CaseStateOnBodyDown);
    }
    if (controlID == "menuStreet2") {
        $("#divStreet").css({ left: cityOffset.left + "px", top: cityOffset.top + cityObj.outerHeight() + "px" }).slideDown("fast");
        $("body").bind("mousedown", this.StreetOnBodyDown);
    }

}

/// <summary>隐藏Module Name树列表
///   <para></para>
/// </summary>
FunctionManage.prototype.CaseStateHideMenu = function () {
    $("#menuContent").fadeOut("fast");
    $("#menuContent2").fadeOut("fast");
    $("body").unbind("mousedown", this.CaseStateOnBodyDown);
}

FunctionManage.prototype.CaseStateOnBodyDown = function (event) {
    if (!(event.target.id == "txt_InfoSource" ||
         event.target.id == "menuContent" ||
        $(event.target).parents("#menuContent").length > 0 ||
        event.target.id == "txt_InfoSource2" ||
         event.target.id == "menuContent2" ||
        $(event.target).parents("#menuContent2").length > 0
     )) {
        functionManage.CaseStateHideMenu();
    }
}
View Code

引用了上面脚本之后,就成功一半了,剩下的就是后台数据处理了。

(4)、客户端加载数据

a.页面初次加载,直接从数据库读取数据展示出来。否则根据查询条件,显示数据。

b.zTree数据加载

 /// <summary>
        ///  获取zTree节点列表
        /// </summary>
        /// <returns></returns>
        public string GetModuleNameTreeList(string ModuleName, string CoveredName)
        {
            //1)定义根节点对象
            JsonTreeItem rootNode = new JsonTreeItem();
            JsonTreeItem CoveredrootNode = new JsonTreeItem();
            rootNode.id = "0";
            rootNode.pId = "0";
            rootNode.name = "ModuleName";
            rootNode.children = new List<JsonTreeItem>();
            rootNode.open = "true";
            rootNode.IsChecked = !string.IsNullOrEmpty(ModuleName);

            CoveredrootNode.id = "0";
            CoveredrootNode.pId = "0";
            CoveredrootNode.name = "CoveredModuleName";
            CoveredrootNode.children = new List<JsonTreeItem>();
            CoveredrootNode.open = "true";
            CoveredrootNode.IsChecked = !string.IsNullOrEmpty(CoveredName);

            //2)缓存所有菜单节点数据
            var list = (from raw in db.TR_Words
                        where raw.WordType == 11 && raw.ModuleName == "TR"
                        select new { raw.WordName, raw.WordValue });
            //3)遍历加载一级根节点
            if (list != null)
            {
                foreach (var item in list)
                {
                    bool isChecked = false;
                    if (ModuleName != null && ModuleName.IndexOf(item.WordName) != -1)
                    {
                        isChecked = true;
                    }
                    //定义一级节点,参数参考JsonTreeItem模型中的说明
                    JsonTreeItem LevelNode1 = new JsonTreeItem("0", rootNode.id, item.WordName, item.WordName.ToString(), "", isChecked, false, "false");
                    //根节点添加一级节点
                    rootNode.children.Add(LevelNode1);

                    bool CoveredisChecked = false;
                    if (CoveredName != null && CoveredName.IndexOf(item.WordName) != -1)
                    {
                        CoveredisChecked = true;
                    }
                    //定义一级节点
                    JsonTreeItem CoveredLevelNode1 = new JsonTreeItem("0", CoveredrootNode.id, item.WordName, item.WordName.ToString(), "", CoveredisChecked, false, "false");
                    //根节点添加一级节点
                    CoveredrootNode.children.Add(CoveredLevelNode1);
                }
            }
            string returnJsonValue = GetJson(rootNode);
            string returnCoveredJsonValue = GetJson(CoveredrootNode);
            return returnJsonValue + "=" + returnCoveredJsonValue;
        }    
View Code

JsonTreeItem模型:

namespace Opentide.DataContracts
{
    /// <summary>Json树对象结构
    /// 
    /// </summary>
    [DataContractAttribute]
    [Serializable]
    public class JsonTreeItem 
    {
        /// <summary>
        /// treeNode 节点的唯一标识 tId。
        /// </summary>
        [DataMember]
        public string  id { get; set; }

        ///<summary>
        /// 节点名称
        ///</summary>
        [DataMember]
        public string name { get; set; }

        ///<summary>
        /// 节点值
        ///</summary>
        [DataMember]
        public string value { get; set; }

        ///<summary>
        /// 父节点id
        ///</summary>
        [DataMember]
        public string pId { get; set; }


        ///<summary>
        /// 节点层级
        ///</summary>
        [DataMember]
        public string level { get; set; }

        ///<summary>
        /// 节点的子节点数据集合
        ///</summary>
        [DataMember]
        public List<JsonTreeItem> children { get; set; }

        /// <summary>
        /// 记录 treeNode 节点的 展开 / 折叠 状态。
        /// </summary>
        [DataMember]
        public string open  { get; set; }

        ///<summary>
        /// 节点自定义图标的 URL 路径
        ///</summary>
        [DataMember]
        public string icon { get; set; }

        ///<summary>
        /// 节点链接的目标 URL
        ///</summary>
        [DataMember]
        public string url { get; set; }


        ///<summary>
        /// 节点链接的目标 URL2
        ///</summary>
        [DataMember]
        public string url2 { get; set; }


        ///<summary>
        /// 是否选中复选框
        ///</summary>
        [DataMember]
        public bool nocheck { get; set; }

        ///<summary>
        /// 是否选中复选框
        ///</summary>
        [DataMember(Name="checked")]
        public bool IsChecked { get; set; }

        ///<summary>
        /// 当前登录用户ID
        ///</summary>
        [DataMember]
        public string UserID { get; set; }


        ///<summary>
        /// 菜单排序ID
        ///</summary>
        [DataMember]
        public int SortID { get; set; }


        ///<summary>
        /// 菜单状态0-不禁用,1-正常
        ///</summary>
        [DataMember]
        public int Status { get; set; }



        public JsonTreeItem()
        {
 
        }


        /// <summary>构造节点实例信息
        /// 
        /// </summary>
        /// <param name="id">节点ID</param>
        /// <param name="pid">父节点</param>
        /// <param name="name">节点名称</param>
        /// <param name="_value">节点值</param>
        /// <param name="url">url地址</param>
        /// <param name="_isChecked">是否选中复选框</param>
        public JsonTreeItem(string _id, string _pid, string _name, string _value, string _url, bool _isChecked)
        {
            this.id = _id;
            this.pId = _pid;
            this.name = _name;
            this.value = _value;
            this.url = _url;
            this.IsChecked = _isChecked;
        }

        /// <summary>构造节点实例信息
        /// 
        /// </summary>
        /// <param name="id">节点ID</param>
        /// <param name="pid">父节点</param>
        /// <param name="name">节点名称</param>
        /// <param name="_value">节点值</param>
        /// <param name="_url">url地址</param>
        /// <param name="_isChecked">是否选中复选框</param>
        /// <param name="_nocheck">是否隐藏复选框</param>
        /// <param name="_nocheck">是否打开子节点</param>
        public JsonTreeItem(string _id, string _pid, string _name, string _value,string _url, bool _isChecked, bool _nocheck,string _open)
        {
            this.id = _id;
            this.pId = _pid;
            this.name = _name;
            this.value = _value;
            this.IsChecked = _isChecked;
            this.nocheck = _nocheck;
            this.open = _open;
        }
    }
}
View Code

值得一提的是,在使用linq做动态多条件OR查询的时候使用了Expressions扩展:PredicateExtensions。

namespace Opentide.Common.Extension
{
    /// <summary>
    /// 构造函数使用True时:单个AND有效,多个AND有效;单个OR无效,多个OR无效;混合时写在AND后的OR有效
    /// 构造函数使用False时:单个AND无效,多个AND无效;单个OR有效,多个OR有效;混合时写在OR后面的AND有效
    /// </summary>
    public static class PredicateExtensions
    {
        public static Expression<Func<T, bool>> True<T>() { return f => true; }
        public static Expression<Func<T, bool>> False<T>() { return f => false; }
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
        {
            var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>(Expression.Or(expression1.Body, invokedExpression), expression1.Parameters);
        }
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
        {
            var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters);
        }
    }
}

private List<TR_TrackerRaw> GetCoveredModelNameBaseList(TrackerGraphSearch search, List<TR_TrackerRaw> list)
        {
            if (search.CoveredModelCheckList != null)
            {
                string CoveredModelCheckList = search.CoveredModelCheckList.ToString();

                string[] CoveredArray = CoveredModelCheckList.Split(',');

                list = GetNeedReceive(list, CoveredArray);
            }
            return list;
        }

        private static List<TR_TrackerRaw> GetNeedReceive(List<TR_TrackerRaw> list, Array hubID)
        {
            IQueryable<TR_TrackerRaw> useList = list.AsQueryable();
            try
            {
                var predicate = PredicateExtensions.False<TR_TrackerRaw>();
                foreach (string h in hubID)
                {
                    string htemp = h;
                    predicate = predicate.Or(c => c.ModuleName == htemp);
                }
                return useList.Where(predicate).ToList();
            }
            catch (Exception ex)
            {
                //_log.Error(ex.ToString());
                return null;
            }
        }
View Code

还有很多不足,欢迎大神不吝指教。

最后附上参考博文:

zTree官网:http://www.ztree.me/v3/main.php#_zTreeInfo

linq动态查询:

http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library

http://www.cnblogs.com/killuakun/archive/2008/08/03/1259389.html

原文地址:https://www.cnblogs.com/FlyBKB/p/5052852.html