0

0

用jQuery打造TabPanel效果代码_jquery

php中文网

php中文网

发布时间:2016-05-16 18:26:40

|

1481人浏览过

|

来源于php中文网

原创

如大量信息查看,当网页多窗口框架等都会用到,现在网上基于jquery Tab控件,其实也蛮多了,我以前用过的idtabs,就比较简单实用,也是比较灵活,但是对于复杂情况就要编码多些,太简单了些。还有就是jquery UI的里面的tab控件(没用过,我对jquery ui不太感冒),另外就是近期有点小火的easyui 中的tab控件,最早在javaeye上面看到的,界面还算漂亮,因为之前没开源,所以一直没跟进(好像最近开源了,前几天下载了看看,编码风格有点像prototype,看不出jquery的影子,不知道为什么叫jquery easyui呵呵,因为没太深入去学习,也不好做其他评价)。说了那么多,我们还是回到主题,因为种种原因不得不想着自己开发一个吧。于是就有了这篇,先来看看效果吧。

下图是单网页多窗口框架的效果图

用jQuery打造TabPanel效果代码_jquery 

下图是文末提供调用示例的效果截图。

用jQuery打造TabPanel效果代码_jquery 

大家可以看到了还是使用ExtJs的效果。其实CSS基本上是直接copy它的。我觉得它那个就非常好看,当然实际使用的时候大家有能力完全可以自己样子

第一 我们还是从HTML开始吧

注:我先控件的思路始终是先确定HTML结构,其次是样式,最终才是js实现的事件方法等。

其实看图我们就可以基本确定,tab控件主要有两个部分的html 一个是头,用于放tab选项卡的;另外一个是体,是内容的容器。那么就是两个Div容器,讲tab控件分成了header和body两部分。

其中header部分因为包含多选项卡 所以很容易想到ul +li的配合。来看一下header中的实际html结构

用jQuery打造TabPanel效果代码_jquery 

通过通过其中li即是一个选项卡,第一个a是关闭按钮,第二个a才是实际内容 通过嵌套标签来实现 左右中的背景图片设置(这个做法比较多见的)。当然能够有个好的效果,还是要靠CSS支持。必须对CSS有一定的了解。

谱乐AI
谱乐AI

谱乐AI,集成 Suno、Udio 等顶尖AI音乐模型的一站式AI音乐生成平台。

下载

Body的结构则更简单就是div嵌套div就就结束了。

第二 CSS样式表

因为CSS是copy EXTJS的我也就不多介绍了。大家可以看代码下载里面的实际代码,如果有问题可以再沟通交流

第三:开始编写JS了

老规矩先来一段完整的JS代码,大概有500行左右的代码,其实我换行比较勤快,实际的代码量其实还是比较少。

复制代码 代码如下:

; (function ($) {
$.fn.tabpanel =function(option){
var dfop ={
items:[], //选项卡数据项 {id,text,classes,disabled,closeable,content,url,cuscall,onactive}
width:500,
height:400,
scrollwidth:100,//如果存在滚动条,点击按钮次每次滚动的距离
autoscroll:true //当选项卡宽度大于容器时自动添加滚动按钮
};
var headerheight=28;
$.extend(dfop, option);
var me =$(this).addClass("x-tab-panel").width(dfop.width);
innerwidth = dfop.width-2;
//构建Tab的Html
var tcs= dfop.autoscroll?"x-tab-scrolling-top":"";
var header = $("
");
var stripwrap = $("
");
var scrollerright = $("");
var scrollerleft = $("");
var ulwrap = $("
    ");
    var stripspacer = $("
    ");
    var litemp =[];
    for(var i=0,l=dfop.items.length; i{
    var item =dfop.items[i];
    builditemlihtml(item,litemp);
    }
    litemp.push("
  • ");
    ulwrap.html(litemp.join(""));
    litemp =null;
    stripwrap.append(ulwrap);
    if(dfop.autoscroll)
    {
    header.append(scrollerright).append(scrollerleft);
    }
    header.append(stripwrap).append(stripspacer);
    var bodyheight=dfop.height-headerheight;
    var bodywrap = $("
    ");
    var body = $("
    ").css({width:innerwidth,height:bodyheight});
    var bodytemp=[];
    for(var i=0,l=dfop.items.length; ivar item =dfop.items[i];
    builditembodyhtml(item,bodytemp);
    }
    body.html(bodytemp.join("")).appendTo(bodywrap);
    me.append(header).append(bodywrap);
    initevents();
    function builditemlihtml(item,parray)
    {
    parray.push("
  • ");
    parray.push("");
    parray.push("");
    parray.push("",item.text,"");
    parray.push("
  • ");
    }
    function builditembodyhtml(item,parray)
    {
    parray.push("
    ");
    parray.push("
    ");
    parray.push("
    ");
    if(item.url){
    parray.push("");
    }
    else if(item.cuscall){
    parray.push("
    ");
    }
    else{
    parray.push(item.content);
    }
    parray.push("
    ");
    }
    function initevents()
    {
    //reset scoller
    resetscoller();
    scollerclick();
    ulwrap.find("li:not(.x-tab-edge)").each(function(e){
    inititemevents(this);
    });
    }
    function inititemevents(liitem)
    {
    liswaphover.call(liitem);
    liclick.call(liitem);
    closeitemclick.call(liitem);
    }
    function scollerclick()
    {
    if(dfop.autoscroll)
    {
    scrollerleft.click(function(e){scolling("left")});
    scrollerright.click(function(e){scolling("right")});
    }
    }
    function resetscoller()
    {
    if(dfop.autoscroll)
    {
    var edge = ulwrap.find("li.x-tab-edge");
    var eleft =edge.position().left;
    var sleft = stripwrap.attr("scrollLeft");
    if( sleft+eleft>innerwidth )
    {
    header.addClass("x-tab-scrolling");
    scrollerleft.css("visibility","visible");
    scrollerright.css("visibility","visible");
    if(sleft>0)
    {
    scrollerleft.removeClass("x-tab-scroller-left-disabled");
    }
    else{
    scrollerleft.addClass("x-tab-scroller-left-disabled");
    }
    if(eleft>innerwidth)
    {
    scrollerright.removeClass("x-tab-scroller-right-disabled");
    }
    else{
    scrollerright.addClass("x-tab-scroller-right-disabled");
    }
    dfop.showscrollnow =true;
    }
    else
    {
    header.removeClass("x-tab-scrolling");
    stripwrap.animate({"scrollLeft":0},"fast");
    scrollerleft.css("visibility","hidden");
    scrollerright.css("visibility","hidden");
    dfop.showscrollnow =false;
    }
    }
    }
    //
    function scolling(type,max)
    {
    //debugger;
    if(!dfop.autoscroll || !dfop.showscrollnow)
    {
    return;
    }
    //debugger;
    //var swidth = stripwrap.attr("scrollWidth");
    var sleft = stripwrap.attr("scrollLeft");
    var edge = ulwrap.find("li.x-tab-edge");
    var eleft = edge.position().left ;
    if(type=="left"){
    if(scrollerleft.hasClass("x-tab-scroller-left-disabled"))
    {
    return;
    }
    if(sleft-dfop.scrollwidth-20>0)
    {
    sleft -=dfop.scrollwidth;
    }
    else{
    sleft =0;
    scrollerleft.addClass("x-tab-scroller-left-disabled");
    }
    if(scrollerright.hasClass("x-tab-scroller-right-disabled"))
    {
    scrollerright.removeClass("x-tab-scroller-right-disabled");
    }
    stripwrap.animate({"scrollLeft":sleft},"fast");
    }
    else{
    if(scrollerright.hasClass("x-tab-scroller-right-disabled") && !max)
    {
    return;
    }
    //left + ;
    if(max || (eleft>innerwidth && eleft-dfop.scrollwidth-20{
    //debugger;
    sleft = sleft+eleft-(innerwidth-38) ;
    scrollerright.addClass("x-tab-scroller-right-disabled");
    // sleft = eleft-innerwidth;
    }
    else
    {
    sleft +=dfop.scrollwidth;
    }
    if(sleft>0)
    {
    if(scrollerleft.hasClass("x-tab-scroller-left-disabled"))
    {
    scrollerleft.removeClass("x-tab-scroller-left-disabled");
    }
    }
    stripwrap.animate({"scrollLeft":sleft},"fast");
    }
    }
    function scollingToli(liitem)
    {
    var sleft = stripwrap.attr("scrollLeft");
    var lleft = liitem.position().left;
    var lwidth = liitem.outerWidth();
    var edge = ulwrap.find("li.x-tab-edge");
    var eleft = edge.position().left ;
    if(lleft{
    sleft +=(lleft-2) ;
    if(sleft{
    sleft=0;
    scrollerleft.addClass("x-tab-scroller-left-disabled");
    }
    if(scrollerright.hasClass("x-tab-scroller-right-disabled"))
    {
    scrollerright.removeClass("x-tab-scroller-right-disabled");
    }
    stripwrap.animate({"scrollLeft":sleft},"fast");
    }
    else{
    if(lleft+lwidth>innerwidth-40)
    {
    sleft = sleft+lleft+lwidth+-innerwidth+40; // 40 =scrollerleft and scrollerrightwidth;
    if(scrollerleft.hasClass("x-tab-scroller-left-disabled"))
    {
    scrollerleft.removeClass("x-tab-scroller-left-disabled");
    }
    //滚到最后一个了,那么就要禁用right;
    if(eleft-(lleft+lwidth+-innerwidth+40){
    scrollerright.addClass("x-tab-scroller-right-disabled");
    }
    stripwrap.animate({"scrollLeft":sleft},"fast");
    }
    }
    liitem.click();
    }
    function liswaphover()
    {
    $(this).hover(function(e){
    if(!$(this).hasClass("x-tab-strip-disabled"))
    {
    $(this).addClass("x-tab-strip-over");
    }
    },function(e){
    if(!$(this).hasClass("x-tab-strip-disabled"))
    {
    $(this).removeClass("x-tab-strip-over");
    }
    });
    }
    function closeitemclick()
    {
    if($(this).hasClass("x-tab-strip-closable"))
    {
    $(this).find("a.x-tab-strip-close").click(function(){
    deleteitembyliid($(this).parent().attr("id"));
    });
    }
    }
    function liclick()
    {
    $(this).click(function(e){
    var itemid = this.id.substr(7);
    var curr = getactiveitem();
    if( curr !=null && itemid == curr.id)
    {
    return;
    }
    var clickitem = getitembyid(itemid);
    if(clickitem && clickitem.disabled)
    {
    return ;
    }
    if(curr)
    {
    $("#tab_li_"+curr.id).removeClass("x-tab-strip-active");
    $("#tab_item_"+curr.id).addClass("x-hide-display");
    curr.isactive =false;
    }
    if(clickitem)
    {
    $(this).addClass("x-tab-strip-active");
    $("#tab_item_"+clickitem.id).removeClass("x-hide-display");
    if(clickitem.url)
    {
    var cururl = $("#tab_item_frame_"+clickitem.id).attr("src");
    if(cururl =="about:blank")
    {
    $("#tab_item_frame_"+clickitem.id).attr("src",clickitem.url);
    }
    }
    else if(clickitem.cuscall && !clickitem.cuscalled)
    {
    var panel = $("#tab_item_content_"+clickitem.id);
    var ret = clickitem.cuscall(this,clickitem,panel);
    clickitem.cuscalled =true;
    if(ret) //如果存在返回值,且不为空
    {
    clickitem.content = ret;
    panel.html(ret);
    }
    }
    clickitem.isactive =true;
    if(clickitem.onactive)
    {
    clickitem.onactive.call(this,clickitem);
    }
    }
    });
    }
    //获取当前活跃项
    function getactiveitem()
    {
    for(var i=0,j=dfop.items.length;i{
    if(dfop.items[i].isactive)
    {
    return dfop.items[i];
    break;
    }
    }
    return null;
    }
    //根据ID获取Item数据
    function getitembyid(id)
    {
    for(var i=0,j=dfop.items.length;i{
    if(dfop.items[i].id == id)
    {
    return dfop.items[i];
    break;
    }
    }
    return null;
    }
    function getIndexbyId(id)
    {
    for(var i=0,j=dfop.items.length;i{
    if(dfop.items[i].id == id)
    {
    return i;
    break;
    }
    }
    return -1;
    }
    //添加项
    function addtabitem(item)
    {
    var chkitem =getitembyid(item.id);
    if(!chkitem){
    var isactive =item.isactive;
    item.isactive =false;
    var lastitem = dfop.items[dfop.items.length-1];
    dfop.items.push(item);
    var lastli = $("#tab_li_"+lastitem.id);
    var lastdiv = $("#tab_item_"+lastitem.id);
    var litemp =[];
    var bodytemp = [];
    builditemlihtml(item,litemp);
    builditembodyhtml(item,bodytemp);
    var liitem = $(litemp.join(""));
    var bodyitem= $(bodytemp.join(""));
    lastli.after(liitem);
    lastdiv.after(bodyitem);
    //事件
    var li = $("#tab_li_"+item.id);
    inititemevents(li);
    if(isactive)
    {
    li.click();
    }
    resetscoller();
    scolling("right",true);
    }
    else{
    alert("指定的tab项已存在!");
    }
    }
    function openitemOrAdd(item,allowAdd)
    {
    var checkitem = getitembyid(item.id);
    if(!checkitem && allowAdd )
    {
    addtabitem(item);
    }
    else{
    var li = $("#tab_li_"+item.id);
    scollingToli(li);
    }
    }
    //移除一个tab 项
    function deleteitembyliid(liid)
    {
    var id= liid.substr(7);
    $("#"+liid).remove();
    $("#tab_item_"+id).remove();
    var index = getIndexbyId(id);
    if(index>=0)
    {
    var nextcur;
    if(index {
    nextcur = dfop.items[index+1];
    }
    else if(index>0){
    nextcur = dfop.items[index-1];
    }
    if(nextcur)
    {
    $("#tab_li_"+nextcur.id).click();
    }
    dfop.items.splice(index,1);
    resetscoller();
    scolling("right",true);
    }
    }
    function resize(width,height)
    {
    if(width ==dfop.width && height ==dfop.height)
    {
    return;
    }
    if(width){ dfop.width=width};
    if(height){ dfop.height =height;}
    innerwidth = width-2;
    bodyheight=dfop.height-headerheight;
    me.css("width",dfop.width);
    header.css("width",innerwidth);
    body.css({width:innerwidth,height:bodyheight});
    for(var i=0,j=dfop.items.length;i{
    var item =dfop.items[i];
    $("#tab_item_"+item.id).css({width:innerwidth});
    $("#tab_item_content_"+item.id).css({width:innerwidth,height:bodyheight});
    }
    resetscoller();
    }
    //设置选项卡项是否disabled
    function setdisabletabitem(itemId,disabled)
    {
    var chitem= getitembyid(itemId);
    if(!chitem || chitem.disabled ==disabled)
    {
    return;
    }
    if(disabled)
    {
    chitem.disabled =true;
    $("#tab_item_"+item.id).addClass("x-tab-strip-disabled");
    }
    else{
    chitem.disabled =false;
    $("#tab_item_"+item.id).removeClass("x-tab-strip-disabled");
    }
    }
    me[0].tab = {
    addtabitem:addtabitem,
    opentabitem:openitemOrAdd,
    resize:resize,
    setdisabletabitem:setdisabletabitem
    };
    };
    $.fn.addtabitem =function(item)
    {
    if(this[0].tab)
    {
    return this[0].tab.addtabitem(item);
    }
    return false;
    }
    $.fn.opentabitem =function(item,orAdd)
    {
    if(this[0].tab)
    {
    return this[0].tab.opentabitem(item,orAdd);
    }
    return false;
    }
    $.fn.resizetabpanel =function(w,h)
    {
    if(this[0].tab)
    {
    return this[0].tab.resize(w,h);
    }
    return false;
    }
    $.fn.setdisabletabitem =function(itemId,disabled)
    {
    if(this[0].tab)
    {
    return this[0].tab.setdisabletabitem(itemId,disabled);
    }
    return false;
    }
    })(jQuery);

    接着我们来一步一步来分析我的实现,开始还是编写jQuery控件的“模板”,关于为什么要这么写,请参考这篇的说明

    复制代码 代码如下:

    ; (function ($) {
    $.fn.tabpanel =function(option){
    };
    )(jQuery);

    接着就是编写默认参数

    复制代码 代码如下:
    var dfop ={
    items:[], //选项卡数据项 {id,text,classes,disabled,closeable,content,url,cuscall,onactive}
    width:500,
    height:400,
    scrollwidth:100,//如果存在滚动条,点击按钮次每次滚动的距离
    autoscroll:true //当选项卡宽度大于容器时自动添加滚动按钮
    };

    默认参数还是比较简单,我已加上了注释,其中就是item数组的项麻烦些,不过我相信大家通过字面的意思就已经知道大半了,我还是描述一下吧:id 即标示,必须唯一、text显示的文本、classes 特定的样式,如效果中的主页,我加了个图标,就通过此属性实现、disabled 是否禁用、closeable 是否可关闭、

    content 和url 和cuscall 三个只要设置其中之一即可,content就是实际的内容html、url标示内容为网页,自动往内容中添加iframe,cuscall则是自定义,即内容显示什么有cuscall执行的结果来决定,可通过此属性来实现异步content内容。

    onactive是指当tab项被激活时触发的事件。 是一个接受item内容的函数,详见demo

    参数设置完了,通过外部传递的参数来更新默认的参数:

    $.extend(dfop, option);

    接着就是构建html的部分,这部分比较长,我就不重复贴代码了。

    当我们把html构建完成之后,就要给html元素添加事件,包括 选项卡的点击事件,左移按钮,右移按钮的点击事件,选项卡的鼠标hover效果事件等。

    复制代码 代码如下:


    function initevents()
    {
    //reset scoller
    resetscoller(); //设置默认是否出现滚动掉
    scollerclick(); //滚动条的点击事件,如果存在的话
    ulwrap.find("li:not(.x-tab-edge)").each(function(e){
    inititemevents(this); //给每个选项卡 添加事件
    });
    }
    function inititemevents(liitem)
    {
    liswaphover.call(liitem); //选项卡的鼠标hover效果
    liclick.call(liitem); //选项卡的点击事件
    closeitemclick.call(liitem); // 点击关闭按钮的事件
    }


    至于事件的实现,其实一个个来做,各个击破也就简单了。主要繁琐在控制滚动按钮的出现和禁用等的处理上,其他点击事件等都比较简单。

    最后就是公开方法,和为了公开这些方法来编写一些内部方法,这个tabpanel自然还是比较简单易用,同时扩展性。大家可以根据实际的需求做些调整,当然现在的功能应该也满足大部分的要求了。

    最后来看一下公开了哪些方法:

    1:动态 新增tab项的方法,即通过js动态新增tab项,这里其实就是对items数据的维护,然后重新调用tabitem的输出html方法,最后单独为其设置事件。简单

    2:选中或者新增。这也是通过js调用的方法,是对上一方法的扩展,即可通过js让某个tab项激活,如果该项不存在则通过参数来新增该选项卡

    3:重新设置tabpanel的大小,即通过js重新设置tabpanel的大小,这个在窗口大小变化时调用,非常实用哦。

    4:设置某项为禁用,通过js方法设置某项tabitem状态为禁用。


    最后大家可以通过 代码 包括之前控件的实例,我已经提供了一个压缩包,但是我更推荐大家实用SVN获取最新代码。因为有的时候一些小的变动我就不发文告知了。

    http://code.google.com/p/xjplugin/downloads/list

    http://xiazai.jb51.net/201005/yuanma/xjPlugin_addtabpanel.rar

    热门AI工具

    更多
    DeepSeek
    DeepSeek

    幻方量化公司旗下的开源大模型平台

    豆包大模型
    豆包大模型

    字节跳动自主研发的一系列大型语言模型

    通义千问
    通义千问

    阿里巴巴推出的全能AI助手

    腾讯元宝
    腾讯元宝

    腾讯混元平台推出的AI助手

    文心一言
    文心一言

    文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

    讯飞写作
    讯飞写作

    基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

    即梦AI
    即梦AI

    一站式AI创作平台,免费AI图片和视频生成。

    ChatGPT
    ChatGPT

    最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

    智谱清言 - 免费全能的AI助手
    智谱清言 - 免费全能的AI助手

    智谱清言 - 免费全能的AI助手

    相关专题

    更多
    batoto漫画官网入口与网页版访问指南
    batoto漫画官网入口与网页版访问指南

    本专题系统整理batoto漫画官方网站最新可用入口,涵盖最新官网地址、网页版登录页面及防走失访问方式说明,帮助用户快速找到batoto漫画官方平台,稳定在线阅读各类漫画内容。

    24

    2026.02.25

    Steam官网正版入口与注册登录指南_新手快速进入游戏平台方法
    Steam官网正版入口与注册登录指南_新手快速进入游戏平台方法

    本专题系统整理Steam官网最新可用入口,涵盖网页版登录地址、新用户注册流程、账号登录方法及官方游戏商店访问说明,帮助新手玩家快速进入Steam平台,完成注册登录并管理个人游戏库。

    1

    2026.02.25

    TypeScript全栈项目架构与接口规范设计
    TypeScript全栈项目架构与接口规范设计

    本专题面向全栈开发者,系统讲解基于 TypeScript 构建前后端统一技术栈的工程化实践。内容涵盖项目分层设计、接口协议规范、类型共享机制、错误码体系设计、接口自动化生成与文档维护方案。通过完整项目示例,帮助开发者构建结构清晰、类型安全、易维护的现代全栈应用架构。

    0

    2026.02.25

    Python数据处理流水线与ETL工程实战
    Python数据处理流水线与ETL工程实战

    本专题聚焦 Python 在数据工程场景下的实际应用,系统讲解 ETL 流程设计、数据抽取与清洗、批处理与增量处理方案,以及数据质量校验与异常处理机制。通过构建完整的数据处理流水线案例,帮助开发者掌握数据工程中的性能优化思路与工程化规范,为后续数据分析与机器学习提供稳定可靠的数据基础。

    0

    2026.02.25

    Java领域驱动设计(DDD)与复杂业务建模实战
    Java领域驱动设计(DDD)与复杂业务建模实战

    本专题围绕 Java 在复杂业务系统中的建模与架构设计展开,深入讲解领域驱动设计(DDD)的核心思想与落地实践。内容涵盖领域划分、聚合根设计、限界上下文、领域事件、贫血模型与充血模型对比,并结合实际业务案例,讲解如何在 Spring 体系中实现可演进的领域模型架构,帮助开发者应对复杂业务带来的系统演化挑战。

    0

    2026.02.25

    Golang 生态工具与框架:扩展开发能力
    Golang 生态工具与框架:扩展开发能力

    《Golang 生态工具与框架》系统梳理 Go 语言在实际工程中的主流工具链与框架选型思路,涵盖 Web 框架、RPC 通信、依赖管理、测试工具、代码生成与项目结构设计等内容。通过真实项目场景解析不同工具的适用边界与组合方式,帮助开发者构建高效、可维护的 Go 工程体系,并提升团队协作与交付效率。

    18

    2026.02.24

    Golang 性能优化专题:提升应用效率
    Golang 性能优化专题:提升应用效率

    《Golang 性能优化专题》聚焦 Go 应用在高并发与大规模服务中的性能问题,从 profiling、内存分配、Goroutine 调度、GC 机制到 I/O 与锁竞争逐层分析。结合真实案例讲解定位瓶颈的方法与优化策略,帮助开发者建立系统化性能调优思维,在保证代码可维护性的同时显著提升服务吞吐与稳定性。

    9

    2026.02.24

    Golang 面试题精选:高频问题与解答
    Golang 面试题精选:高频问题与解答

    Golang 面试题精选》系统整理企业常见 Go 技术面试问题,覆盖语言基础、并发模型、内存与调度机制、网络编程、工程实践与性能优化等核心知识点。每道题不仅给出答案,还拆解背后的设计原理与考察思路,帮助读者建立完整知识结构,在面试与实际开发中都能更从容应对复杂问题。

    5

    2026.02.24

    Golang 运行与部署实战:从本地到云端
    Golang 运行与部署实战:从本地到云端

    《Golang 运行与部署实战》围绕 Go 应用从开发完成到稳定上线的完整流程展开,系统讲解编译构建、环境配置、日志与配置管理、容器化部署以及常见运维问题处理。结合真实项目场景,拆解自动化构建与持续部署思路,帮助开发者建立可靠的发布流程,提升服务稳定性与可维护性。

    5

    2026.02.24

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    jQuery 教程
    jQuery 教程

    共42课时 | 6.6万人学习

    HTML+CSS基础与实战
    HTML+CSS基础与实战

    共132课时 | 11.6万人学习

    tp6+adminlte搭建通用后台
    tp6+adminlte搭建通用后台

    共39课时 | 5.8万人学习

    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号 技术交流群
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号