zoukankan      html  css  js  c++  java
  • 【ztree】zTree节点增删改&ztree对树节点进行检索

    1.对节点增删改查 

      今天遇到一个需求是对zTree的节点进行增删改,经过查阅资料总结如下:

    效果:

    完成增删改,要注意几个关键点:

    • 使用 编辑功能,必须设置 setting.edit 中的各个属性
    • 使用 编辑功能的事件回调函数,必须设置 setting.callback.beforeRemove / onRemove / beforeRename / onRename 等属性
    • zTree 不提供默认的增加按钮,如要实现需要利用自定义控件的方法 addHoverDom / removeHoverDom 
    • 我们利用 beforeEditName 来触发自定义的编辑操作

    首先,我们来看看具体的配置信息(详细内容见代码中的注释):

    <!DOCTYPE html>
    <html>
    
        <head>
            <meta charset="UTF-8">
            <title>zTree测试</title>
            <link rel="stylesheet" type="text/css" href="css/demo.css" />
            <link rel="stylesheet" type="text/css" href="css/zTreeStyle/zTreeStyle.css" />
            <script src="js/jquery-1.4.4.min.js" type="text/javascript" charset="utf-8"></script>
            <script src="js/jquery.ztree.all.js" type="text/javascript" charset="utf-8"></script>
        </head>
        <script type="text/javascript">
        var zTree;
        var setting = {
                view:{
                    addHoverDom:addHoverDom,
                    removeHoverDom:removeHoverDom,
                    selectedMulti:false
                },
                edit: {
                    enable: true,
                    editNameSelectAll:true,
                    removeTitle:'删除',
                    renameTitle:'重命名'
                },
                data: {
                    /* keep:{
                        parent:true,
                        leaf:true
                    }, */
                    simpleData: {
                        enable: true
                    }
                },
                callback:{
                    beforeRemove:beforeRemove,//点击删除时触发,用来提示用户是否确定删除(可以根据返回值 true|false 确定是否可以删除)
                    beforeEditName: beforeEditName,//点击编辑时触发,用来判断该节点是否能编辑
                    beforeRename:beforeRename,//编辑结束时触发,用来验证输入的数据是否符合要求(也是根据返回值 true|false 确定是否可以编辑完成)
                    onRemove:onRemove,//(beforeRemove返回true之后可以进行onRemove)删除节点后触发,用户后台操作
                    onRename:onRename,//编辑后触发,用于操作后台
                    beforeDrag:beforeDrag,//用户禁止拖动节点
                    onClick:clickNode//点击节点触发的事件
                }
            };
        var zNodes =[
                     { id:1, pId:0, name:"父节点 1", open:true},
                     { id:11, pId:1, name:"去百度",url:'http://www.baidu.com',target:'_blank'},
                     { id:12, pId:1, name:"叶子节点 1-2"},
                     { id:13, pId:1, name:"叶子节点 1-3"},
                     { id:2, pId:0, name:"父节点 2", open:true},
                     { id:21, pId:2, name:"叶子节点 2-1"},
                     { id:22, pId:2, name:"叶子节点 2-2"},
                     { id:23, pId:2, name:"叶子节点 2-3"},
                     { id:3, pId:0, name:"父节点 3", open:true},
                     { id:31, pId:3, name:"叶子节点 3-1"},
                     { id:32, pId:3, name:"叶子节点 3-2"},
                     { id:33, pId:3, name:"叶子节点 3-3"}
                 ];
        $(document).ready(function(){
            zTree = $.fn.zTree.init($("#tree"), setting, zNodes);
        });
        function beforeRemove(e,treeId,treeNode){
            return confirm("你确定要删除吗?");
        }
        function onRemove(e,treeId,treeNode){
            if(treeNode.isParent){
                var childNodes = zTree.removeChildNodes(treeNode);
                var paramsArray = new Array();
                for(var i = 0; i < childNodes.length; i++){
                    paramsArray.push(childNodes[i].id);
                }
                alert("删除父节点的id为:"+treeNode.id+"
    他的孩子节点有:"+paramsArray.join(","));
                return;
            }
            alert("你点击要删除的节点的名称为:"+treeNode.name+"
    "+"节点id为:"+treeNode.id);
        }
        function beforeEditName(treeId,treeNode){
            /* if(treeNode.isParent){
                alert("不准编辑非叶子节点!");
                return false;
            } */
            return true;
        }
        function beforeRename(treeId,treeNode,newName,isCancel){
            if(newName.length < 3){
                alert("名称不能少于3个字符!");
                return false;
            }
            return true;
        }
        function onRename(e,treeId,treeNode,isCancel){
            alert("修改节点的id为:"+treeNode.id+"
    修改后的名称为:"+treeNode.name);
        }
        function clickNode(e,treeId,treeNode){
            if(treeNode.id == 11){
                location.href=treeNode.url;
            }else{
                alert("节点名称:"+treeNode.name+"
    节点id:"+treeNode.id);
            }
        }
        function beforeDrag(treeId,treeNodes){
            return false;
        }
        var newCount = 1;
        function addHoverDom(treeId,treeNode){
            var sObj = $("#" + treeNode.tId + "_span");
            if (treeNode.editNameFlag || $("#addBtn_"+treeNode.tId).length>0) return;
            var addStr = "<span class='button add' id='addBtn_" + treeNode.tId
                + "' title='添加子节点' onfocus='this.blur();'></span>";
            sObj.after(addStr);
            var btn = $("#addBtn_"+treeNode.tId);
            if (btn) btn.bind("click", function(){
                //在这里向后台发送请求保存一个新建的叶子节点,父id为treeNode.id,让后将下面的100+newCount换成返回的id
                //zTree.addNodes(treeNode, {id:(100 + newCount), pId:treeNode.id, name:"新建节点" + (newCount++)});
                alert("开始添加节点")
                return false;
            });
        }
        function removeHoverDom(treeId,treeNode){
            $("#addBtn_"+treeNode.tId).unbind().remove();
        }
        </script>
    <body>
        <ul id="tree" class="ztree"></ul>
    </body>
    </html>

    最后附一个完整的与后台交互的例子:

    /***********S  QLQ*********************/
    var zTree;
    var setting = {
        view : {
            addHoverDom : addHoverDom,
            removeHoverDom : removeHoverDom,
            selectedMulti : false
        },
        edit : {
            enable : true,
            editNameSelectAll : true,
            removeTitle : '删除',
            renameTitle : '重命名'
        },
        data : {
            key : {
                name:"typeName"
            },
            /* keep:{
                parent:true,
                leaf:true
            }, */
            simpleData : {
                enable : true,
                idKey: "typeId",
                pIdKey: "upId",
                rootPId: 1
            }
        },
        callback : {
            beforeRemove : beforeRemove,//点击删除时触发,用来提示用户是否确定删除
            beforeEditName : beforeEditName,//点击编辑时触发,用来判断该节点是否能编辑,是否进入编辑状态
            beforeRename : beforeRename,//编辑结束时触发,用来验证输入的数据是否符合要求
            onRemove : onRemove,//删除节点后触发,用户后台操作
            onRename : onRename,//编辑后触发,用于操作后台
            onClick : clickNode
        //点击节点触发的事件
        }
    };
    function geneTypeTree(){
        $.getJSON(contextPath+"/trainacontentType_getTraincontenttypeTree.action",function(response){
            var zNodes = response.traincontenttypeTree;
            zTree = $.fn.zTree.init($("#tree"),setting,zNodes);
        });
    }
    
    $(document).ready(function() {
        geneTypeTree();
                    });
    
    
    /******S  删除*******/
    function beforeRemove(treeId, treeNode) {
        if(confirm("确认删除?
    将会删除下面的所有视频!")){
            if(treeNode.isParent){
                alert("该目录下面还有子目录,请从最底层目录开始删除!");
                return false;
            }
            return true;
        }
        return false;
    }
    function onRemove(e, treeId,treeNode) {
        var typeId = treeNode.typeId;
        $.post(contextPath+"/trainacontentType_deleteTrainContentTypeById.action",
                {"typeId":typeId},
                function(repsonse){
                    alert(repsonse.result);
                    if("删除成功"==repsonse.result)//删除成功之后执行查询
                        btnFindFy();
                }
                ,'json')
        
        
    }
    /******E  删除*******/
    
    function beforeEditName(treeId,treeNode) {
        /* if(treeNode.isParent){
            alert("不准编辑非叶子节点!");
            return false;
        } */
        return true;
    }
    
    function beforeRename(treeId,treeNode, newName,isCancel) {
        if (newName.length < 3) {
            alert("名称不能少于3个字符!");
            return false;
        }
        return true;
    }
    function onRename(e, treeId,treeNode, isCancel) {
        if(confirm("您确认修改类别名称?")){
            $.post(contextPath+"/trainacontentType_updateTraincontenttypeName.action",
                    {
                "traincontenttype.typeid":treeNode.typeId,
                "traincontenttype.typename":treeNode.typeName
                    },
                    function(response){
                        if(response != null){
                            if("修改成功"==response.result){
                                alert(response.result);
                            }
                        }
                    }
                    ,
            'json');
        }
    }
    
    /************S   点击事件*********/
    function clickNode(e, treeId,treeNode) {
        $("#trainContentTypeId").val(treeNode.typeId);//向隐藏的类别编号赋值
        $("[name='typeId']").val(treeNode.typeId);//向隐藏的类别编号赋值
        $("#yeHao").val("1");
        btnFindFy();
    }
    /************E   点击事件*********/
    
    
    function addHoverDom(treeId,treeNode) {
        var sObj = $("#"+ treeNode.tId+ "_span");
        if (treeNode.editNameFlag|| $("#addBtn_"+ treeNode.tId).length > 0)
            return;
        var addStr = "<span class='button add' id='addBtn_"+ treeNode.tId+ "' title='添加子节点' onfocus='this.blur();'></span>";
        sObj.after(addStr);
        var btn = $("#addBtn_"+ treeNode.tId);
        if (btn)btn.bind("click",function() {
                                if(confirm("确认在该目录下面添加培训内容类别?")){
                                    var typeName = prompt("请输入类别名称");//获取到的名字
                                    if(typeName != null){//点击确定
                                        if(typeName.length>1){
                                            var upId = treeNode.typeId;//上级编号
                                            $.post(contextPath+"/trainacontentType_addTraincontenttype.action",
                                                    {
                                                        "traincontenttype.upid":upId,
                                                        "traincontenttype.typename":typeName
                                                    },
                                                    function(response){
                                                        if(response!=null){
                                                            alert(response.result);
                                                        }
                                                        if(response.result == "添加成功" ){
                                                            var traincontenttype = response.traincontenttype;//获取返回来的数据
                                                            zTree.addNodes(treeNode, {typeId:traincontenttype.typeid, upId:treeNode.id, typeName:typeName});
                                                        }
    //                                                    geneTypeTree();
                                                    },
                                                'json');
                                        }else{
                                            alert("请输入正确的类别名称")
                                        }
                                    }
                                }
                                //在这里向后台发送请求保存一个新建的叶子节点,父id为treeNode.id,让后将下面的100+newCount换成返回的id
                                //zTree.addNodes(treeNode, {id:(100 + newCount), pId:treeNode.id, name:"新建节点" + (newCount++)});
                                return false;
                            });
    }
    function removeHoverDom(treeId,treeNode) {
        $("#addBtn_" + treeNode.tId).unbind().remove();
    }

    下面附一个更加详细的最近用到的树:  (包含展开所有节点,点击,重命名,删除,添加等事件,以及验证操作)

    /********S   左边树相关操作**********/
    /**
     * 查询课程类别树结构
     */
    function getTypeTree(){
        $.getJSON(contextPath + '/courseType/getTypeTree.do',{"trainSchemeId":$("#trainSchemeId").val()},geneTypeTree);
    }
    
    /**
     * 生成课程类别树函数
     * @param typeTree  返回的课程类别信息(多一条虚拟的课程类别节点)
     */
    function geneTypeTree(typeTree){
        var setting = {
            view : {
                addHoverDom : addHoverDom,//用于当鼠标移动到节点上时,显示用户自定义控件,显示隐藏状态同 zTree 内部的编辑、删除按钮
                removeHoverDom : removeHoverDom,//用于当鼠标移出节点时,隐藏用户自定义控件,显示隐藏状态同 zTree 内部的编辑、删除按钮
                selectedMulti : false //设置是否允许同时选中多个节点。
            },
            edit : {
                enable : true,//设置 zTree 是否处于编辑状态
                editNameSelectAll : true,//节点编辑名称 input 初次显示时,设置 txt 内容是否为全选状态。
                removeTitle : '删除课程类别',
                renameTitle : '重命名课程类别'
            },
            data : {
                simpleData : {
                    enable : true,
                    idKey : "typenum",
                    pIdKey : "uptypenum",
                    rootPId : "1"
                },
                key : {
                    name : "typename",
                }
            },
            callback : {
                beforeRemove : beforeRemove,//点击删除时触发,用来提示用户是否确定删除
                beforeEditName : beforeEditName,//点击编辑时触发,用来判断该节点是否能编辑
                beforeRename : beforeRename,//编辑结束时触发,用来验证输入的数据是否符合要求
                onRemove : onRemove,//删除节点后触发,用户后台操作
                onRename : onRename,//编辑后触发,用于操作后台
                onClick : clickNode//点击节点触发的事件
            }
        };
        var treeNodes = typeTree;//树节点数据(从后台获取)
        $.fn.zTree.init($("#treeDiv"), setting, treeNodes);//在界面生成一颗树
        openAllTreenode();//展开树的所有节点
    }
    
    /**
     * 展开树的所有节点
     */
    function openAllTreenode(){
    
        // 获取树对象
        var treeObj = $.fn.zTree.getZTreeObj("treeDiv");
        /* 获取所有树节点 */
        var nodes = treeObj.transformToArray(treeObj.getNodes());
        // 展开除第一级之外的其他节点
        for (var i = 0, length_1 = nodes.length; i < length_1; i++) {
            if(nodes[i].level == 0){
                continue;
            }
            nodes[i].open = true;
        }
        //展开第一级节点
        treeObj.expandNode(nodes[0], true);
    
    }
    
    
    
    /******S  删除*******/
    /**
     * 删除前的询问(验证是否可以删除)
     * @param treeId
     * @param treeNode  需要删除的树节点
     * @returns {boolean} 是否可以执行删除函数
     */
    function beforeRemove(treeId, treeNode) {
        var layer =getLauiLayer();
        if(treeNode.level == 0){
            layer.msg("您不可以删除根节点!请从二级节点开始操作!",{icon:2,shade: [0.8, '#393D49']})
            return false;
        }
        if(treeNode.isParent){
            layer.msg("该目录下面还有子目录,请从最底层目录开始删除!",{icon:2,shade: [0.8, '#393D49']})
            return false;
        }
        //如果表格中有数据就不让删除
        if($("#trainCourseTbody").children("tr").length>0){
            layer.msg("该节点已经排有课程,不允许删除课程类别!先删除培养方案课程!",{icon:2,time:2*1000,shade: [0.8, '#393D49']});
            return false;
        }
        if(confirm("确认删除?")){
            return true;
        }
        return false;
    }
    
    /**
     * 删除的操作
     * @param e 事件
     * @param treeId    树的界面中的ID
     * @param treeNode  节点
     */
    function onRemove(e, treeId,treeNode) {
        var layer = getLauiLayer();
        var trainSchemeId = getTrainSchemeId();//培养方案编号
        var typeNum = treeNode.typenum;//类别num
        $.post(contextPath+"/courseType/deleteCourseType.do",{"trainSchemeId":trainSchemeId,"typeNum":typeNum},function (response) {
            layer.msg(response,{time:2*1000,shade: [0.8, '#393D49']},function () {
                if("删除成功" == response){
                    getTypeTree();//重新生成树
                    //1.清空条件
                    var form = $("#queryTrainCourseForm");
                    form.find("input").not("#queryTrainCourseTrainshemeId").val("");
                    form.find("select").val("");
                    //2.重新查询一次
                    queryTrainCourseByCondition();
                }
            })
        },'text')
    }
    /******E  删除*******/
    
    
    
    /****S  编辑根节点****/
    /**
     * 验证是否可以进入编辑模式
     * @param treeId
     * @param treeNode
     * @returns {boolean}   true|false代表是否进入编辑模式
     */
    function beforeEditName(treeId,treeNode) {
        var layer;
        layui.use(['layer'],function () {
            layer = layui.layer;
        });
        //如果是根节点不允许编辑
        if(treeNode.level == 0 ){
            layer.msg("您不能编辑根节点!",{icon:2,shade: [0.8, '#393D49']});
            return false;
        }
        return true;
    }
    
    /**
     * 用于捕获节点编辑名称结束(Input 失去焦点 或 按下 Enter 键)之后,更新节点名称数据之前的事件回调函数,并且根据返回值确定是否允许更改名称的操作
     * @param treeId
     * @param treeNode
     * @param newName
     * @param isCancel
     * @returns {boolean}   是否成功
     */
    function beforeRename(treeId,treeNode, newName,isCancel) {
        var layer;
        layui.use(['layer'],function () {
            layer = layui.layer;
        })
        if (($.trim(newName)).length < 2) {
            layer.alert("名称不能少于2个字符!")
            return false;
        }
        return true;
    }
    
    /**
     * 修改名称的操作(正经的修改传到后台进行操作)
     * @param e
     * @param treeId
     * @param treeNode
     * @param isCancel
     */
    function onRename(e, treeId,treeNode, isCancel) {
        //如果选择了取消,重新查一下树
        if(isCancel == true){
            getTypeTree()
            return false;
        }
        if(confirm("您确认修改类别名称?")) {
            $.post(contextPath+"/courseType/updateCourseType.do",
                {
                    "trainSchemeId":$("#trainSchemeId").val(),
                    "typeNum":treeNode.typenum,
                    "typeName":treeNode.typename
                },
                function(response){
                    if(response != null){
                        var layer;
                        layui.use("layer",function () {
                            layer = layui.layer;
                        });
                        layer.msg(response,{shade: [0.8, '#393D49'],time:2*1000,icon:1},function () {
                            if("修改成功"==response){
                                getTypeTree();//修改成功之后重新查一下树
                            }
                        })
                    }
                }
                ,
                'text');
        }else {//如果选择了取消重新查一下树
            getTypeTree();//取消之后重新查树
        }
    
    }
    
    
    /****E  编辑根节点****/
    
    /************S   点击事件*********/
    /**
     * 点击事件
     * @param e 事件
     * @param treeId    树节点的ID
     * @param treeNode  树节点
     */
    function clickNode(e, treeId,treeNode) {
        $("#trainCourseTypeNum").val(treeNode.typenum);//向隐藏的课程类别编号赋值(最后添加到表单中传到后台保存)
        $("#trainCourseTypeName").val(treeNode.typename);//
        $("#typeNum_0").val(treeNode.typenum);//向隐藏的课程类别编号赋值
        // queryTrainCourseByCondition();//分页查询培养方案课程信息
        clearConditionAndQueryTrainCourse();
    }
    /************E   点击事件*********/
    
    /**
     * 增加一个课程类别事件(自定义组件),用于当鼠标移动到节点上时,显示用户自定义控件,显示隐藏状态同 zTree 内部的编辑、删除按钮
     * @param treeId    树节点在界面的编号
     * @param treeNode      树节点
     */
    function addHoverDom(treeId,treeNode) {
        //1.初始化layer模块
        var layer;
        layui.use(['layer'],function () {
            layer = layui.layer;
        })
        //2.
        var sObj = $("#"+ treeNode.tId+ "_span");
        if (treeNode.editNameFlag|| $("#addBtn_"+ treeNode.tId).length > 0)
            return;
        var addStr = "<span class='button add' id='addBtn_"+ treeNode.tId+ "' title='添加子节点' onfocus='this.blur();'></span>";
        sObj.after(addStr);
        var btn = $("#addBtn_"+ treeNode.tId);
        if (btn)btn.bind("click",function() {//增加的业务逻辑写在这里
            var name = treeNode.typename ; //获取到当前的节点的名称
            var typenum = treeNode.typenum ; //获取到当前的节点的编号
            var layer = getLauiLayer();
            //如果是叶子节点并且排有课程不允许再添加
            if(!treeNode.isParent &&$("#trainCourseTbody").children("tr").length>0){
                layer.msg("该节点已经排有课程,不允许添加课程类别!",{icon:2,time:2*1000,shade: [0.8, '#393D49']});
                return;
            }
            if(confirm("确认在类别  "+name+"  下添加新的类别?")){
                //1.向隐藏的地方赋值
                $(".clear-input").val("");//清空残留的数据
                $("#addType_uptypenum").val(typenum);//上级编号
                $("#add_trainingschemeid").val($("#trainSchemeId").val());//培养方案编号
                $("#addType_upTypeName").val(name);//上级类别名称
                $("#addType_remark").val("无");//描述默认无
                //2.打开模态框
                var index = layer.open({
                    title:'添加课程类别',
                    area: [$(window).width()*0.80+'px', $(window).height()*0.70 +'px'],//大小
                    fix: true, //不固定
                    maxmin: true,
                    zIndex:500,
                    shadeClose: false,
                    shade:0.4,
                    type:1,
                    content:$('#addTypeModal')
                });
                //向页面隐藏index
                $("#hidden_addType_index").val(index);
            }
        });
    }
    
    /**
     *用于当鼠标移出节点时,隐藏用户自定义控件,显示隐藏状态同 zTree 内部的编辑、删除按钮
     * @param treeId
     * @param treeNode
     */
    function removeHoverDom(treeId,treeNode) {
        $("#addBtn_" + treeNode.tId).unbind().remove();
    }
    /********S   左边树相关操作**********/

    效果:

     2. 对树进行检索

      在数据很多的情况下,树形结构会变得比较复杂。需要增加关键字查询功能,如下:

     HTML代码:

                            <!---->
                            <div class="el_leftTree">
                                <!--标题类,添加了一个颜色-->
                                <span class="el_treeTitle">检修单位</span>
                                <select class="btn btn-default mark-type" id="el_bigStatusMark"    title="请选择" onchange="historyBigInfoFind()">
                                        <option value="0">当前检修</option>
                                        <option value="1">历史检修</option>
                                </select>
                                <div style="margin: 5px 0px;">
                                    <input type="text" id="keyword" style=" 80%;" placeholder="关键字" onchange="filterKeywords()"/>
                                </div>
                                <ul id="departmentAndOverHaulTree" class="ztree"></ul>
                            </div>

    需要引入的JS

    JS代码:

    /*******S 增加关键字搜索功能**********/
    /**
     * 查找子结点,如果找到,返回true,否则返回false
     */
    function searchChildren(keyword,children){
        if(children == null || children.length == 0){
            return false;
        }
        for(var i = 0;i < children.length;i++){
            var node = children[i];
            if(node.name.indexOf(keyword)!=-1){
                return true;
            }
            //递归查找子结点
            var result = searchChildren(keyword,node.children);
            if(result){
                return true;
            }
        }
        return false;
    }
    
    /**
     * 查找当前结点和父结点,如果找到,返回ture,否则返回false
     */
    function searchParent(keyword,node){
        if(node == null){
            return false;
        }
        if(node.name.indexOf(keyword)!=-1){
            return true;
        }
        //递归查找父结点
        return searchParent(keyword,node.getParentNode());
    }
    
    var hiddenNodes = []; //用于存储被隐藏的结点
    
    //过滤ztree显示数据
    function filterKeywords(){
        var ztreeObj = $.fn.zTree.getZTreeObj("departmentAndOverHaulTree");
        //显示上次搜索后隐藏的结点
        ztreeObj.showNodes(hiddenNodes);
        //查找不符合条件的结点
        //返回true表示要过滤,需要隐藏,返回false表示不需要过滤,不需要隐藏
        function filterFunc(node){
            var keyword=$("#keyword").val();
        //如果当前结点,或者其父结点可以找到,或者当前结点的子结点可以找到,则该结点不隐藏
            if(searchParent(keyword,node) || searchChildren(keyword,node.children)){
                return false;
            }
            return true;
        };
    
        //获取不符合条件的叶子结点
        hiddenNodes=ztreeObj.getNodesByFilter(filterFunc);
    
        //隐藏不符合条件的叶子结点
        ztreeObj.hideNodes(hiddenNodes);
    };
    /*******E 增加关键字搜索功能**********/
  • 相关阅读:
    CODING x 百果园 _ 水果零售龙头迈出 DevOps 体系建设第一步
    Nocalhost 亮相 CD Foundation 国内首届 Meetup,Keith Chan 将出席致辞
    做云原生时代标准化工具,实现高效云上研发工作流
    打造数字化软件工厂 —— 一站式 DevOps 平台全景解读
    WePack —— 助力企业渐进式 DevOps 转型
    CODING Compass —— 打造行云流水般的软件工厂
    Nocalhost —— 让云原生开发回归原始而又简单
    CODING 代码资产安全系列之 —— 构建全链路安全能力,守护代码资产安全
    Nocalhost:云原生开发新体验
    使用 Nocalhost 开发 Kubernetes 中的 APISIX Ingress Controller
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/8516207.html
Copyright © 2011-2022 走看看