Bootstrap嵌入jqGrid,使你的table牛逼起来


Posted in Javascript onMay 05, 2016

Bootstrap原生的table组件只能满足简单的数据展示,满足不了更富有操作性的要求。当然了,你可以找到一款叫做“DataTables-1.10.11”的基于bootstrap的table组件,但如果你对API看得不甚了解的话,用起来可就痛苦了,但是如果你选择使用jqGrid,那么本篇教程就给你带来了解决这种富操作性table的解决方案。

一、效果展示

Bootstrap嵌入jqGrid,使你的table牛逼起来

OK,就展示这一张图片,相信你已经爱上了bootstrap版的jqGrid,和bootstrap很兼容,简直完美,当然了,这需要我们在缘由的jqGrid上进行一些改动,同时对组件进行一定的封装。

二、资源下载

我反正挺热爱分享的,关于jqGrid的组件代码,你可以从jqGrid的官网上下载,但是下载下来需要一些改动,那么我直接将改动后的jqGrid上传到了git,你只需要把提供的文件导入到你对应的项目即可。

另外,你还需要下载一个jquery-ui-1.10.0.custom.css,我就不提供下载地址了,不过我相信,你肯定会找得到,就算是用频出事故的度娘,你也可以找得到。

三、本篇都讲一些什么

自从建了QQ群后,“络绎不绝”的有同学加入到群中,但我也发现,进群的一步人直接来找我要demo,或者项目代码,这个我可不喜欢,自己动手做一做,去实现以下,改造一下,才会是你自己的东西,完全照搬我的代码显然你得不到更多的帮助,希望以上同学学习的时候再主动一些。

说完上面这点小废话后,我们言归正传,来说说我们本篇博客主要来讲些什么,什么才是在bootstrap中嵌入jqGrid的关键所在,我总结有如下:

jqGrid在bootstrap中的布局方案jqGrid自身的构造化参数jqGrid在bootstrap中的模块化jqGrid的数据操作

暂定分为以上部分来说明,但必须注意,限于篇幅,博客中只提供思路和部分代码。

①、 jqGrid在bootstrap中的布局方案

<!DOCTYPE html>
<html lang="zh-CN">

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ include file="/components/common/taglib.jsp"%>
<%@ include file="/components/common/csslib.jsp"%>

<head>
<link type="text/css" rel="stylesheet" href="${ctx}/css/deal/my_pay_list.css" />
</head>
<body>
  <div class="container">
    <form class="form-horizontal" id="jqgridForm" role="form" action="${ctx}/deal/datablePayDealOrdersList"
    method="post">
    <div class="form-group">
      <div class="col-sm-12">
        <label for="name" class="control-label pull-left">项目名称:</label>
        <div class="col-sm-3">
          <input type="text" name="name" class="form-control" id="name" placeholder="请输入项目名称" value="" />
        </div>
      </div>
    </div>
    <div class="form-group">
      <div class="col-sm-12">
        <button type="button" class="btn btn-primary pull-right" id="searchBtn">检索</button>
      </div>
    </div>
    <div class="form-group">
      <div class="col-sm-12">
        <table id="pageGrid" rel="jqgridForm" class="jqgrid"></table>
        <div id="pageGridPager"></div>
      </div>
    </div>
  </form>
</div>
<%@ include file="/components/common/jslib.jsp"%>
<script type="text/javascript" src="${ctx}/js/deal/my_pay_list.js"></script>
</body>
</html>

介于每个人的项目千差万别,列出的代码中我们只关注jqGrid部分:

id="jqgridForm",此处我们为jqGrid包含一层检索条件的form表单,也就是效果图上列出的search部分,当点击检索按钮时,就把form表单域的查询条件提交到controller,进而获取的数据。id="searchBtn",定义检索按钮,后面讲模块化会用得到。<table id="pageGrid" rel="jqgridForm" class="jqgrid"></table> <div id="pageGridPager"></div>定义jqGrid的table元素和jqGrid的footer元素,使用的规则我的项目暂时约定这种规则,你也可以有你自己的规则。通过rel指定form的id,可以更便捷的使用table的检索form。②、 jqGrid自身的构造化参数

构造化参数,我把他提取到了①中的my_pay_list.js中。

$(function() {
  var jqOption = {
    datatype : "xml",
    mtype : "POST",
    shrinkToFit : true,
    viewrecords : false,
    rownumbers : false,
    autowidth : true,
    height : "100%",
    colNames : [ 'id', 'status', '项目信息', '项目状态', '订单号', '项目名称', '下单时间', '支付金额', '支持数量', '订单状态', '操作' ],
    colModel : [
        {
          name : 'id',
          index : 'id',
          hidden : true
        },
        {
          name : 'status',
          index : 'status',
          hidden : true
        },
        {
          name : 'image_str',
          index : 'image_str',
          width : 140,
          resizable : false,
          sortable : false,
          formatter : function(cellvalue, options, rowObject) {
            if (cellvalue == '支付总花费:') {
              return cellvalue;
            }

          },
          align : 'left'
        }, {
          name : 'oper',
          index : 'oper',
          width : 90,
          resizable : false,
          sortable : false,
          align : 'center',
          formatter : function(cellvalue, options, rowObject) {
            var status = parseInt($(rowObject).find("status").text());
            var id = $(rowObject).find("id").text();
            if (status == 0) {
              return '<a class="color0088cc" width="700" target="dialog" href="' + common.ctx + '/deal/initPayg/' + id + '">去支付</a>';
            }

            if (status == 1 || status == 3) {
              return '<a class="color0088cc" target="_blank" href="' + common.ctx + '/deal/showDealOr/' + id + '">查看详情</a>';
            }

            if (status == 2) {
              return '<a class="color0088cc" target="ajaxTodo" href="' + common.ctx + '/deal/receivder/' + id + '">确认收货</a>';
            }

          },
        } ],
    xmlReader : {
      repeatitems : false,
      root : "PageGrid",
      row : "map",
      page : 'page',
      total : 'total',
      records : 'records',
      id : 'ID'
    },
    rowNum : 50,
    rowList : [ 50, 100, 200, 300 ],
    pager : "#pageGridPager",
    footerrow : true,
    loadError : YUNM.ajaxError,
    gridComplete : function() {
      var $form = $("#" + $("#pageGrid").attr("rel"));
      $.ajax({
        type : $form.method || 'POST',
        url : common.ctx + "/deal/getAllOrded",
        data : $form.serializeArray(),
        dataType : "json",
        cache : false,
        success : function(json) {
          $("#pageGrid").footerData("set", {
            image_str : "支付总花费:",
            order_price : json.message
          });
        },
        error : YUNM.ajaxError
      });

      if ($.fn.ajaxTodo) {
        $("a[target=ajaxTodo]", $("#pageGrid")).ajaxTodo();
      }

      // dialog
      if ($.fn.ajaxTodialog) {
        $("a[target=dialog]", $("#pageGrid")).ajaxTodialog();
      }
    },
  };
  initEnv(jqOption);
});

一点都不熟悉jqGrid的同学,建议先看jqGrid的demo,以及jqGrid的官方文档,当然了,对于已经熟悉jqGrid的同学,doc和demo肯定是必看的。

以上文件列出的属性非常多,对于jqGrid,我不做过多的介绍,本篇的主旨主要来介绍如何将jqGrid嵌入到bootstrap,那么重点就不在于介绍jqGrid上,我只介绍几个关键点:

formatter: function(cellvalue, options, rowObject) {,formatter还是很经常要使用的,那么对于如何获得对应单元格的值就很重要,我的jqGrid使用的是xml(datatype : “xml”)数据格式,那么可通过$(rowObject).find("deal_id").text()找到对应deal_id列的值。xmlReader : { repeatitems : false, root : "PageGrid",,注意xmlReader中的参数值,在接下来介绍④jqGrid的数据操作会细节介绍,和后台的xml数据封装有关系。$("#pageGrid").footerData("set", {image_str : "支付总花费:", order_price : json.message});,关于footerData方法,使用起来也很方便,效果可参照效果图。initEnv(jqOption);方法,在页面onload后,我们将jqGrid的初始化参数传递给initEnv方法,后续③jqGrid在bootstrap中的模块化会介绍initEnv方法。③、jqGrid在bootstrap中的模块化

②中我们注意到initEnv方法,那么这个方法内部就是专门针对jqGrid做的模块化封装工作。

initEnv方法

function initEnv(jqOption) {

  $(window).resize(function() {
    initLayout();
  });

  initUI(null, jqOption);
}

该方法中,我们将会看到initLayout方法和initUI方法,具体内容稍候介绍。

initLayout

function initLayout() {
  $("table[rel=jqgridForm]").each(function() {
    var rel = $(this).attr("rel");
    if (rel) {
      var $form = $("#" + rel);
      var tableWidth = $form.width();
      $(this).setGridWidth(tableWidth, true);
    }
  });
}

也就是说,在窗口缩放的时候,我们为jqGrid重新绘制宽度,使其自适应于bootstrap的响应式布局。使用的方法就是jqGrid的setGridWidth方法。

initUI

function initUI(_box, jqOption) {
  var $p = $(_box || document);
  if (jqOption) {
    YUNM.debug("初始化jqgrid");

    var $form = $("#" + $("#pageGrid").attr("rel"));

    YUNM.debug(YUNM.array2obj($form.serializeArray()));

    // 初始化
    var op = $.extend({
      url : $form.attr("action"),
      postData : YUNM.array2obj($form.serializeArray()),
    }, jqOption);
    $("#pageGrid").jqGrid(op);

    // 检索按钮
    $("#searchBtn", $form).click(function() {
      $("#pageGrid").jqGrid('setGridParam', {
        url : $form.attr("action"),
        page : 1,
        postData : YUNM.array2obj($form.serializeArray()),
      });
      $("#pageGrid").trigger("reloadGrid");

    });

    // toolbar,将button的圆角去掉
    $(".btn", $form).each(function() {
      var $this = $(this);
      $this.css({
        "border-radius" : "0px",
        "border-bottom" : "0",
      });
    });

  }
}
array2obj : function(array) {
  var params = $({});
  $.each(array, function(i) {
    var $param = $(this)[0];
    params.attr($param.name, $param.value);
  });
  return params[0];
},

如果你曾看过我之前的系列文章,对于initUi方法就不会太陌生,熟悉dwz的朋友,自然也不会陌生,我项目中的大部分模板还是依赖于dwz,谢谢这些前辈们。

var $form = $("#" + $("#pageGrid").attr("rel"));由于我们在jqGrid上关联了form检索条件的form表单,此处就可以将form表单对象取到,取到form表单对象,自然也就去得到了检索域的值($form.serializeArray())。拿到form表单的检索域值后,此时就需要做一番处理了。我们知道,jqGrid在向controller传递参数时,必然需要上送分页、排序的相关字段(page、rows、sord、sidx),使用的方法是$("#pageGrid").jqGrid({postData:xxx});,通常情况下,我们上送form表单时,只需要使用$form.serializeArray()就可以,但如果此时,只是将xxx替换为$form.serializeArray(),那么controller中将不会获得分页、排序的相关字段(page、rows、sord、sidx),这是一个冲突,此时怎么处理呢?解决办法就是将form表单数据对象化(array2obj 方法),然后我们再通过var op =$.extend({url:$form.attr("action"),postData:YUNM.array2obj($form.serializeArray()),},jqOption);$("#pageGrid").jqGrid(op);将检索域的值和分页、排序的相关字段一起上送到controller。$("#searchBtn", $form).click通过封装click事件,将jqGrid的数据重新加载。$(".btn", $form).each(function() {此处的方法将检索button去圆角,使其更贴合jqGrid,见效果图。④ 、jqGrid的数据操作

数据操作部分,我认为包含有 检索参数传递、分页排序参数传递、sql语句的编写。

关于参数传递,前端的参数封装在③中已有介绍,我们来看一看controller中如何处理数据的。

首先,我们来定义PageGrid,也就是jqGrid中xmlReader的数据源。

package com.honzh.common.page;

import java.util.List;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("pageGrid")
@SuppressWarnings("rawtypes")
public class PageGrid {
  private int page;
  private int total;
  private int records;

  private List data;

  public int getPage() {
    return this.page;
  }

  public void setPage(int page) {
    this.page = page;
  }

  public int getTotal() {
    return this.total;
  }

  public void setTotal(int total) {
    this.total = total;
  }

  public int getRecords() {
    return this.records;
  }

  public void setRecords(int records) {
    this.records = records;
  }

  public List getData() {
    return this.data;
  }

  public void setData(List data) {
    this.data = data;
  }
}

项目中需要xstream.jar,自行下载。

XStreamComponent.java

package com.honzh.common.page;

import org.apache.commons.lang.StringUtils;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.mapper.DefaultMapper;
import com.thoughtworks.xstream.mapper.XStream11XmlFriendlyMapper;

public class XStreamComponent {
  private XStream xstream;

  public static XStreamComponent newInstance() {
    XStreamComponent xmlComponent = new XStreamComponent();
    xmlComponent.alias(new Class[] { PageGrid.class });

    return xmlComponent;
  }

  public XStreamComponent() {
    this.xstream = new XStream(new DomDriver());
  }

  public String toXML(Object obj) {
    return this.xstream.toXML(obj);
  }

  public String toPageXML(Object obj) {
    registerConverter(new MapCustomConverter(new DefaultMapper(XStream11XmlFriendlyMapper.class.getClassLoader())));
    return toXML(obj);
  }

  public Object fromPageXML(String xml) {
    registerConverter(new MapCustomConverter(new DefaultMapper(XStream11XmlFriendlyMapper.class.getClassLoader())));
    return fromXML(xml);
  }

  public Object fromXML(String xml) {
    return this.xstream.fromXML(xml);
  }

  @SuppressWarnings("rawtypes")
  public void processAnnotations(Class type) {
    this.xstream.processAnnotations(type);
  }

  @SuppressWarnings("rawtypes")
  public void processAnnotations(Class[] types) {
    this.xstream.processAnnotations(types);
  }

  @SuppressWarnings("rawtypes")
  public void alias(String name, Class type) {
    this.xstream.alias(name, type);
  }

  @SuppressWarnings("rawtypes")
  public void alias(Class[] types) {
    for (Class type : types) {
      String className = type.getName();
      try {
        String[] classNames = StringUtils.split(className, ".");
        this.xstream.alias(classNames[(classNames.length - 1)], type);
      } catch (Exception ex) {
        this.xstream.alias(className, type);
      }
    }
  }

  public void registerConverter(Converter converter) {
    this.xstream.registerConverter(converter);
  }

  @SuppressWarnings("rawtypes")
  public void useAttributeFor(Class definedIn, String fieldName) {
    this.xstream.useAttributeFor(definedIn, fieldName);
  }
}

主要将pageGrid封装为xml对象,进而传递会前端。

MapCustomConverter.java

package com.honzh.common.page;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.mapper.Mapper;

public class MapCustomConverter extends AbstractCollectionConverter {
  public MapCustomConverter(Mapper mapper) {
    super(mapper);
  }

  @SuppressWarnings("rawtypes")
  public boolean canConvert(Class type) {
    return (type.equals(HashMap.class)) || (type.equals(Hashtable.class))
        || (type.getName().equals("java.util.LinkedHashMap"))
        || (type.getName().equals("sun.font.AttributeMap"));
  }

  @SuppressWarnings({ "rawtypes" })
  public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
    Map map = (Map) source;
    for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
      Map.Entry entry = (Map.Entry) iterator.next();
      writer.startNode(entry.getKey() == null ? "null" : entry.getKey().toString());
      writer.setValue(entry.getValue() == null ? "" : entry.getValue().toString());
      writer.endNode();
    }
  }

  @SuppressWarnings("rawtypes")
  public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
    Map map = (Map) createCollection(context.getRequiredType());
    populateMap(reader, context, map);
    return map;
  }

  @SuppressWarnings({ "rawtypes", "unchecked" })
  protected void populateMap(HierarchicalStreamReader reader, UnmarshallingContext context, Map map) {
    while (reader.hasMoreChildren()) {
      reader.moveDown();
      Object key = reader.getNodeName();
      Object value = reader.getValue();
      map.put(key, value);
      reader.moveUp();
    }
  }
}

主要将数据库中获取的hashmap转换为标准的xml格式数据。

BaseConditionVO.java

package com.honzh.common.persistence;

import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.session.RowBounds;

/**
 * 分页查询时的参数设置类.<br>
 * 
 * <P>
 * 1.PAGE_SHOW_COUNT──当然默认一页显示10。<br>
 * 2.pageNum──第几页。<br>
 * 3.numPerPage──一页显示多少,为空时,显示PAGE_SHOW_COUNT。<br>
 * 4.totalCount──总共数目。totalCount/numPerPage=多少页<br>
 * 5.orderField──排序的列。<br>
 * 6.orderDirection──排序的方向。
 * </P>
 */
public class BaseConditionVO {
  public final static int PAGE_SHOW_COUNT = 50;
  private int pageNum = 1;
  private int numPerPage = 0;
  private long totalCount = 0;
  private String orderField = "";
  private String orderDirection = "";

  /**
   * @Fields ps : 对参数类型进行封装.
   */
  private Map<String, Object> mo = new HashMap<String, Object>();

  public int getPageNum() {
    return pageNum;
  }

  public void setPageNum(int pageNum) {
    this.pageNum = pageNum;
  }

  public int getNumPerPage() {
    return numPerPage > 0 ? numPerPage : PAGE_SHOW_COUNT;
  }

  public void setNumPerPage(int numPerPage) {
    this.numPerPage = numPerPage;
  }

  public String getOrderField() {
    return orderField;
  }

  public void setOrderField(String orderField) {
    this.orderField = orderField;
  }

  public String getOrderDirection() {
    return "desc".equals(orderDirection) ? "desc" : "asc";
  }

  public void setOrderDirection(String orderDirection) {
    this.orderDirection = orderDirection;
  }

  public long getTotalCount() {
    return totalCount;
  }

  public void setTotalCount(long totalCount) {
    this.totalCount = totalCount;
  }

  public int getStartIndex() {
    int pageNum = this.getPageNum() > 0 ? this.getPageNum() - 1 : 0;
    return pageNum * this.getNumPerPage();
  }

  public RowBounds createRowBounds() {
    RowBounds ro = new RowBounds(this.getStartIndex(), this.getNumPerPage());
    return ro;
  }

  /**
   * @Title: addParams
   * @Description: 添加查询条件
   * @param key
   * @param value
   */
  public void addParams(String key, Object value) {
    this.getMo().put(key, value);
  }

  /**
   * @Title: getParams
   * @Description: 获取查询条件
   * @param key
   * @return
   */
  public Object getParams(String key) {
    return this.getMo().get(key);
  }

  /**
   * @return the mo
   */
  public Map<String, Object> getMo() {
    return mo;
  }

  /**
   * @param mo
   *      the mo to set
   */
  public void setMo(Map<String, Object> mo) {
    this.mo = mo;
  }

  @Override
  public String toString() {
    return "条件:" + pageNum + "," + numPerPage + "," + totalCount + "," + orderField + "," + orderDirection + ","
        + mo;
  }
}

分页的查询数据对象,包括分页、排序、检索域。

protected BaseConditionVO getBaseConditionVOForTable() {
    BaseConditionVO vo = new BaseConditionVO();
    // 分页的参数
    int currentPage = getParaToInt("page");
    int sizes = getParaToInt("rows");
    String sortOrder = getPara("sord");
    String sortCol = getPara("sidx");
    vo.setNumPerPage(sizes);
    vo.setPageNum(currentPage);
    vo.setOrderField(sortCol);
    vo.setOrderDirection(sortOrder);

    return vo;
  }
将jqGrid传递的参数转换为BaseConditionVO分页查询对象。

protected void renderXml(HttpServletResponse res, String xmlResponse) {
    try {
      res.setCharacterEncoding("UTF-8");
      res.setHeader("Content-type", "text/xml");
      PrintWriter out = res.getWriter();
      out.print(xmlResponse);
      if (out != null) {
        out.close();
      }
    } catch (IOException e) {
      logger.error(e.getMessage());
      logger.error(e.getMessage(), e);
    }

  }

将xml写入到输出流中。

定义完了这些基础的对象,接下来,我们就要着手获取数据和传递数据了。

@SuppressWarnings("rawtypes")
  @RequestMapping(value = "datablePayDealOrdersList")
  public void datablePayDealOrdersList(HttpServletResponse response) {
    try {
      logger.debug("获取我支付的订单");

      XStreamComponent xstreamComponent = XStreamComponent.newInstance();
      // 获取列表参数
      BaseConditionVO vo = getBaseConditionVOForTable();
      vo.addParams("name", getPara("name"));

      logger.debug("我支付的订单查询" + vo);

      // 我创建的项目
      List myDealOrders = dealOrderService.getByIssueUid(vo, vo.createRowBounds());
      Long count = dealOrderService.searchIssueTotalCount(vo);

      String xmlResponse = xstreamComponent.toPageXML(createPageGrid(myDealOrders, vo, count.intValue()));

      renderXml(response, xmlResponse.replaceAll("__", "_"));
    } catch (UncategorizedSQLException e) {
      logger.error(e.getMessage());
      logger.error(e.getMessage(), e);

      renderXml(response, Constants.QUERY_ERROR);
    } catch (Exception e) {
      logger.error(e.getMessage());
      logger.error(e.getMessage(), e);

      renderXml(response, Constants.SERVER_ERROR);
    }
  }

我们来详细说明一下:
1. XStreamComponent.newInstance()创建xml流对象。
2. BaseConditionVO vo = getBaseConditionVOForTable();创建分页查询参数对象。
3. vo.addParams("name", getPara("name"));将检索域的值放入到查询对象中。
4. dealOrderService.getByIssueUid(vo, vo.createRowBounds());mybatis的分页查询方式,超简单,之前一个群里的朋友专门做了一种mybatis的分页组件,我觉得用原始的mybatis查询方法更有效率,之后,我们会写出对应的mybatis中xml的sql写法。
5. renderXml(response, xmlResponse.replaceAll("__", "_"));将数据写入到jsp的out输出流中。

最后,我们来介绍,通过mybatis如何获取分页数据。

mapper.java

package com.honzh.biz.database.mapper;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;

import org.apache.ibatis.session.RowBounds;

import com.honzh.common.persistence.BaseConditionVO;

public interface DealOrderMapper {
  @SuppressWarnings("rawtypes")
  List<HashMap> getByIssueUid(BaseConditionVO vo, RowBounds createRowBounds);
}

想mapper.xml传递的两个对象,分别是BaseConditionVO 还有分页的RowBounds ,xml中sql就会自动分页。

mapper.xml

<select id="getByIssueUid" resultType="hashmap" parameterType="map">
    select * from daa
    WHERE is_delete=0

    <if test="mo.name != null and mo.name != ''">
      and y.name like CONCAT('%','${mo.name}','%')
    </if>

     <choose>
      <when test="orderField !=null and orderField !=''">
         ORDER BY ${orderField} <if test="orderDirection != null and orderDirection != ''">${orderDirection}</if>
      </when>
      <otherwise>
         order by d.order_time DESC
      </otherwise>
    </choose>
  </select>

你完全可以不关注RowBounds ,mybatis内部会自动为你封装好limit的。检索域的name可以直接通过mo.name或得到。orderField、orderDirection也传递过来了。

到此为止,整篇的Bootstrap嵌入jqGrid就圆满结束了,ok,使你的table牛逼起来吧!

Javascript 相关文章推荐
jQuery 解析xml文件
Aug 09 Javascript
javascript的alert box在java中如何显示多行
May 18 Javascript
jQuery内部原理和实现方式浅析
Feb 03 Javascript
JSON遍历方式实例总结
Dec 07 Javascript
详解JavaScript时间格式化
Dec 23 Javascript
设计模式中的facade外观模式在JavaScript开发中的运用
May 18 Javascript
基于vue的短信验证码倒计时demo
Sep 13 Javascript
vue+webpack 打包文件 404 页面空白的解决方法
Feb 28 Javascript
利用Node.js批量抓取高清妹子图片实例教程
Aug 02 Javascript
webpack4 处理SCSS的方法示例
Sep 03 Javascript
详解如何在vscode里面调试js和node.js的方法步骤
Dec 24 Javascript
Node.JS发送http请求批量检查文件中的网页地址、服务是否有效可用
Nov 20 Javascript
Struts2+jquery.form.js实现图片与文件上传的方法
May 05 #Javascript
使用jquery.form.js实现图片上传的方法
May 05 #Javascript
探讨:JavaScript ECAMScript5 新特性之get/set访问器
May 05 #Javascript
浅析JS异步加载进度条
May 05 #Javascript
AngularJS入门(用ng-repeat指令实现循环输出
May 05 #Javascript
图文详解Heap Sort堆排序算法及JavaScript的代码实现
May 04 #Javascript
一分钟理解js闭包
May 04 #Javascript
You might like
帖几个PHP的无限分类实现想法~
2007/01/02 PHP
php判断是否为json格式的方法
2014/03/04 PHP
PHP多维数组转一维数组的简单实现方法
2015/12/23 PHP
CI框架常用经典操作类总结(路由,伪静态,分页,session,验证码等)
2016/11/21 PHP
Laravel框架路由设置与使用示例
2018/06/12 PHP
PHP实现的日历功能示例
2018/09/01 PHP
PHP抽象类基本用法示例
2018/12/28 PHP
【消息提示组件】,兼容IE6/7&amp;&amp;FF2
2007/09/04 Javascript
详细介绍jQuery.outerWidth() 函数具体用法
2015/07/20 Javascript
jQuery EasyUI Dialog拖不下来如何解决
2015/09/28 Javascript
jQuery多条件筛选如何实现
2015/11/04 Javascript
Knockoutjs 学习系列(一)ko初体验
2016/06/07 Javascript
解决OneThink中无法异步提交kindeditor文本框中修改后的内容方法
2017/05/05 Javascript
JS判断Android、iOS或浏览器的多种方法(四种方法)
2017/06/29 Javascript
基于vue组件实现猜数字游戏
2020/05/28 Javascript
解决vue axios的封装 请求状态的错误提示问题
2018/09/25 Javascript
json数据格式常见操作示例
2019/06/13 Javascript
微信小程序动态显示项目倒计时
2019/06/20 Javascript
js回调函数仿360开机
2019/12/26 Javascript
python用户管理系统的实例讲解
2017/12/23 Python
Python3安装pip工具的详细步骤
2019/10/14 Python
浅谈PyQt5中异步刷新UI和Python多线程总结
2019/12/13 Python
Python使用Numpy模块读取文件并绘制图片
2020/05/13 Python
keras.layer.input()用法说明
2020/06/16 Python
浏览器实现移动端高性能css3动画(开启gpu加速)
2013/12/23 HTML / CSS
法国票务网站:Ticketmaster法国
2018/07/09 全球购物
耐克波兰官方网站:Nike波兰
2019/09/03 全球购物
.NET remoting的两种通道是什么
2016/05/31 面试题
小车司机岗位职责
2013/11/25 职场文书
文科教师毕业的自我评价
2014/01/16 职场文书
事业单位个人总结
2015/02/12 职场文书
后勤个人工作总结
2015/02/28 职场文书
2016党员干部廉洁自律心得体会
2016/01/13 职场文书
Pycharm远程调试和MySQL数据库授权问题
2022/03/18 MySQL
Javascript中Microtask和Macrotask鲜为人知的知识点
2022/04/02 Javascript
前端与RabbitMQ实时消息推送未读消息小红点实现示例
2022/07/23 Java/Android