Bootstrap fileinput文件上传预览插件使用详解


Posted in Javascript onMay 16, 2017

介绍

通过本文,你可以学习到如何封装或者开发一个前端组件,同时学习Bootstrap-fileinput组件的使用,封装后使用更加简单方便。

Bootstrap fileinput文件上传预览插件使用详解

BaseFile是AdminEAP框架中基于Bootstrap-fileinput的附件上传组件,它支持 支持多文件、在线预览、拖拽上传等功能,封装后BaseFile主要包括以下功能:

  • 弹出窗口的附件上传
  • 当前界面的附件上传
  • 显示附件明细
  • 可编辑的附件明细(删除、预览、不可新增)

关于Bootstrap-fileinput的API文档可参考http://plugins.krajee.com/file-input

本文源码已在AdminEAP框架(一个基于AdminLTE的Java开发平台)中开源,可在Github下载相关代码:

Github:https://github.com/bill1012/AdminEAP

AdminEAP官网:http://www.admineap.com

使用说明

1、初始化

如果需要在当前界面使用附件上传功能(非弹窗方式)则需要在头部引入相关的css和js文件

css文件

<link rel="stylesheet" href="./resources/common/libs/fileinput/css/fileinput.min.css" >

js文件

<script src="./resources/common/libs/fileinput/js/fileinput.js"></script>
<script src="./resources/common/libs/fileinput/js/locales/zh.js"></script>
<!--BaseFile组件-->
<script src="./resources/common/js/base-file.js"></script>

form表单上还需要配置enctype="multipart/form-data"属性

2、弹窗方式调用

BaseFile支持弹窗方式打开一个附件上传窗口,点击附件上传后,弹出窗口,上传附件关闭窗口后,上传的附件在type=file的控件回填。

在表单中点击弹窗上传附件:

Bootstrap fileinput文件上传预览插件使用详解

Bootstrap fileinput文件上传预览插件使用详解

上传完毕,关闭窗口,附件回填

Bootstrap fileinput文件上传预览插件使用详解

再次打开上传附件上传窗口时,会把已有的附件回填到附件上传窗口。

配置如下:

html代码

<input type="hidden" name="fileIds" id="fileIds">
   <div class="form-group">
    <div class="btn btn-default btn-file" id="uploadFile">
     <i class="fa fa-paperclip"></i> 上传附件(Max. 10MB)
    </div>
   </div>
   <div class="form-group" id="file_container">
    <input type="file" name="file" id="attachment">
   </div>

js代码

$("#uploadFile").file({
   title: "请上传附件",
   fileinput: {
    maxFileSize: 10240,
    maxFileCount:3
   },
   fileIdContainer:"[name='fileIds']",
   showContainer:'#attachment',
   //显示文件类型 edit=可编辑 detail=明细 默认为明细
   showType:'edit',
   //弹出窗口 执行上传附件后的回调函数(window:false不调用此方法)
   window:true,
   callback:function(fileIds,oldfileIds){
    //更新fileIds
    this.showFiles({
     fileIds:fileIds
    });
   }
  });

3、本地界面调用

本地界面调用附件上传,如下图所示:

将上传附件嵌入到当前界面方式

Bootstrap fileinput文件上传预览插件使用详解

上传后的附件可删除、可预览

Bootstrap fileinput文件上传预览插件使用详解

Bootstrap fileinput文件上传预览插件使用详解

(目前图片文件可预览,其他文件不可预览,后期将集成txt/xml/html/pdf的预览功能)

配置如下:

html代码

<div class="form-group" id="file_container">
  <input type="file" name="file" id="attachment">
</div>

js代码

$("#attachment").file({
   fileinput: {
    maxFileSize: 10240,
    maxFileCount:3
   },
   fileIdContainer:"[name='fileIds']",
   window:false
  });

4、控件参数说明

window 默认为true,弹窗方式打开

title window=true时配置,弹窗的标题,默认为“文件上传”

width window=true时配置,弹窗的宽度,默认900

winId window=true时配置,弹出的id,默认为fileWin

fileinput Bootstrap-fileinput的配置参数,会覆盖默认配置,比如允许上传哪种类型的附件allowedFileTypes,允许上传最大附件大小maxFileSize,允许上传附件的个数maxFileCount等,具体的配置参数可以查询Bootstrap-fileinput的API文档。

fileIdContainer 必须,上传后的附件id存储的位置,id以逗号分隔

showContainer window=true必须配置,文件上传后回填的区域,window=false时如不配置,则取base-file的初始对象

showType window=true配置,值为edit或者detail,edit表示回填后可对数据进行删除、预览,detail只能显示,不能删除

callback window=true配置,关闭附件上传的窗口后执行的回调函数(比如更新当前的文件列表),fileIds,oldfileIds两个参数分别是更新后文件ids和更新前的文件ids

BaseFile默认配置,BaseFile的更多实现,请查看BaseFile源码

BaseFile.prototype.default = {
  winId: "fileWin",
  width: 900,
  title: "文件上传",
  //通用文件上传界面
  url: basePath + "/file/uploader",
  //默认支持多文件上传
  multiple: true,
  //默认弹出附件上传窗口
  window:true,
  showType:"detail",
  fileinput: {
   language: 'zh',
   uploadUrl: basePath + "/file/uploadMultipleFile",
   deleteUrl:basePath+"/file/delete",
   uploadAsync:false,
   validateInitialCount:true,
   overwriteInitial: false,
   allowedPreviewTypes: ['image'],
   previewFileIcon:'<i class="fa fa-file-o"></i>',
   previewFileIconSettings: null,
   slugCallback: function (text) {
    var newtext=(!text||text=='') ? '' : String(text).replace(/[\-\[\]\/\{}:;#%=\(\)\*\+\?\\\^\$\|<>&"']/g, '_');
    //去除空格
    return newtext.replace(/(^\s+)|(\s+$)/g,"").replace(/\s/g,"");
   }
  }
 }

5、BaseFile控件源码

/**
 * 通用文件管理组件
 * @author billjiang qq:475572229
 */
(function ($, window, document, undefined) {
 'use strict';

 var pluginName = 'file';

 $.fn[pluginName] = function (options) {
  var self = $(this);
  if (this == null)
   return null;
  var data = this.data(pluginName);
  if (!data) {
   data = new BaseFile(this, $.extend(true, {}, options));
   self.data(pluginName, data);
  }
 };


 var BaseFile = function (element, options) {
  this.element = element;
  //extend优先级 后面的会覆盖前面的
  //alert(this.element.selector);
  //将容器ID传过去便于弹窗获取到BaseFile对象,如果页面布局不在使用jquery.load方法,则该方法会失效,因为不是一个页面了
  options.container = options.container || this.element.selector.replace("#", "");
  //初始化文件图标信息
  this.getFileIconSettings();
  this.options = $.extend(true, {}, this.default, options);
  //初始化图标信息
  this.initFileIds();

  if(this.options.window) {
   this.element.click(function () {
    $(this).data('file').openWin();
   });
  }else{
   //非弹窗形式
   if(this.options.multiple)
    this.element.attr("multiple","multiple");
  }

  //如果配置了附件编辑容器showContainer(附件列表,可单个删除),则进行初始化
  if(this.hasDisplayZone()){
   this.showFiles();
  }


 }

 BaseFile.prototype.default = {
  winId: "fileWin",
  width: 900,
  title: "文件上传",
  //通用文件上传界面
  url: basePath + "/file/uploader",
  //默认支持多文件上传
  multiple: true,
  //默认弹出附件上传窗口
  window:true,
  showType:"detail",
  fileinput: {
   language: 'zh',
   uploadUrl: basePath + "/file/uploadMultipleFile",
   deleteUrl:basePath+"/file/delete",
   uploadAsync:false,
   validateInitialCount:true,
   overwriteInitial: false,
   allowedPreviewTypes: ['image'],
   previewFileIcon:'<i class="fa fa-file-o"></i>',
   previewFileIconSettings: null,
   slugCallback: function (text) {
    var newtext=(!text||text=='') ? '' : String(text).replace(/[\-\[\]\/\{}:;#%=\(\)\*\+\?\\\^\$\|<>&"']/g, '_');
    //去除空格
    return newtext.replace(/(^\s+)|(\s+$)/g,"").replace(/\s/g,"");
   }
  }
 }

 BaseFile.prototype.getFileInputConfig=function () {
  return this.options.fileinput;
 }
 BaseFile.prototype.getFileIconSettings = function () {
  var self = this;
  ajaxPost(basePath + "/file/icons", null, function (icons) {
   self.previewFileIconSettings = icons;
   //console.log(self.previewFileIconSettings);
  })
 }


 BaseFile.prototype.openWin = function () {
  var that = this;
  var self = $.extend(true, {}, this.options);
  //深拷贝后删除属性,这样不会通过后台传送过去,防止被XSS过滤掉特殊字符
  //不需要通过参数config=传递到弹窗的参数可使用delete删除
  delete self.callback;
  delete self.fileIds;
  delete self.showContainer;
  delete self.fileIdContainer;
  delete self.fileinput;

  /*console.log(this.options);
   console.log("=============");
   console.log(self);*/
  modals.openWin({
   winId: that.options.winId,
   url: that.options.url + "?config=" + JSON.stringify(self),
   width: that.options.width + "px",
   title: that.options.title,
   backdrop: "static"
  });
 }

 BaseFile.prototype.callbackHandler = function (fileIds) {
  //更新fileIds并执行回调函数
  var oldfileIds = this.options.fileIds;
  this.options.fileIds = fileIds;
  this.updateFileIds();
  if (this.options.callback) {
   this.options.callback.call(this, fileIds, oldfileIds);
  }
 }

 //调用成功后执行显示附件
 BaseFile.prototype.showFiles=function(options){
  options=options||{};
  if(!this.hasDisplayZone()){
   modals.error("请配置showContainer属性,并在容器下配置type=file的input组件");
   return;
  }
  var fileIds=options.fileIds||this.options.fileIds;
  if(!fileIds&&this.options.window){
   $(this.options.showContainer).hide();
   return;
  }
  //显示
  $(this.options.showContainer).show();
  var fileComponet=$(this.options.showContainer);
  var fileResult=this.getFileResult(fileIds),preview=fileResult.initialPreview,previewConfig=fileResult.initialPreviewConfig,self=this;
  //配置三类参数 edit=附件列表(可删除) detail=附件列表(显示) 可上传
  var defaultConfig={
   initialPreview:preview,
   initialPreviewConfig:previewConfig
  };
  var config;
  if(this.options.window){
   if(this.options.showType=="edit"){
    //全局配置->本方法默认配置->edit属性下配置->外部参数
    config=$.extend({},self.options.fileinput,defaultConfig,{
     showRemove:false,
     showUpload:false,
     showClose:false,
     showBrowse:false,
     showCaption:false
    },options);
   }else if(this.options.showType=="detail"){
    config=$.extend({},self.options.fileinput,defaultConfig,{
     showRemove:false,
     showUpload:false,
     showClose:false,
     showBrowse:false,
     showCaption:false,
     initialPreviewShowDelete:false
    },options);
   }
  }else{
   config=$.extend({},self.options.fileinput,defaultConfig,{
    showClose:false
   },options);
  }

  if(!config){
   modals.error("未找到showFiles中的相关配置");
   return;
  }
  //console.log("config=========="+JSON.stringify(config));
  fileComponet.fileinput('destroy');
  fileComponet.fileinput(config).on("filedeleted",function (event,key) {
   var newfids=self.deleteFileIds(key,self.options.fileIds);
   self.options.fileIds=newfids;
   self.updateFileIds();
  }).on("fileuploaded",function(event,data,previewId,index){
   var newfids=self.addFileIds(data.response.fileIds,self.options.fileIds);
   self.options.fileIds=newfids;
   self.updateFileIds();
  }).on("filebatchuploadsuccess",function (event,data,previewId,index) {
   var newfids=self.addFileIds(data.response.fileIds,self.options.fileIds);
   self.options.fileIds=newfids;
   self.updateFileIds();
  }).on("filezoomhidden", function(event, params) {
   $(document.body).removeClass('modal-open');
   $(document.body).css("padding-right","0px");
  });
 }

 /**
  * 向targetIds里删除数据fileIds
  * @param fileIds
  * @param targetIds
  */
 BaseFile.prototype.deleteFileIds=function(fileIds,targetIds){
  if(!fileIds) return targetIds;
  //没有文件删除,其中必有蹊跷
  if(!targetIds){
   modals.error("没有要删除的文件,请检查是否数据没有初始化");
   return;
  }
  var fileIdArr=fileIds.split(",");
  var fresult=targetIds.split(",");
  $.each(fileIdArr,function (index,fileId){
   //存在则删除
   if($.inArray(fileId,fresult)>-1){
    fresult.splice($.inArray(fileId,fresult),1);
   }
  })
  return fresult.join();
 }

 /**
  * 向targetIds里加数据fileIds
  * @param fileIds
  * @param targetIds
  */
 BaseFile.prototype.addFileIds=function (fileIds,targetIds) {
  if(!fileIds)return targetIds;
  var fileIdArr=fileIds.split(",");
  var fresult=[];
  if(targetIds){
   fresult=targetIds.split(",");
  }
  $.each(fileIdArr,function (index,fileId){
   //不存在,新增
   if($.inArray(fileId,fresult)==-1){
    fresult.push(fileId);
   }
  })
  return fresult.join();
 }

 BaseFile.prototype.updateFileIds=function(){
  if(this.options.fileIdContainer)
   $(this.options.fileIdContainer).val(this.options.fileIds);
 }

 BaseFile.prototype.initFileIds=function(){
  //不弹出窗口的话一定要绑定fileIdContainer
  if(!this.options.window){
   if(!this.options.fileIdContainer||!$(this.options.fileIdContainer)){
    modals.info("请设置fileIdContainer属性");
    return;
   }
  }
  if(!this.options.fileIds){
   if(this.options.fileIdContainer){
    this.options.fileIds=$(this.options.fileIdContainer).val();
   }
  }
 }

 BaseFile.prototype.getFileResult=function(fileIds){
  var ret=null;
  ajaxPost(basePath+"/file/getFiles",{fileIds:fileIds},function(result){
   ret=result;
  });
  return ret;
 };

 /**
  * 是否有显示区域
  * @returns {boolean}
  */
 BaseFile.prototype.hasDisplayZone=function(){
  if(!this.options.showContainer){
   this.options.showContainer=this.element.selector;
  }
  if(!this.options.showContainer||!$(this.options.showContainer)){
   return false;
  }
  return true;
 }


})(jQuery, window, document);

6、后端源码

@Controller
@RequestMapping("/file")
public class UploaderController {

 private static Logger logger= LoggerFactory.getLogger(UploaderController.class);

 //previewFileIconSettings
 public static Map fileIconMap=new HashMap();
 @Resource
 private UploaderService uploaderService;

 static {
  fileIconMap.put("doc" ,"<i class='fa fa-file-word-o text-primary'></i>");
  fileIconMap.put("docx","<i class='fa fa-file-word-o text-primary'></i>");
  fileIconMap.put("xls" ,"<i class='fa fa-file-excel-o text-success'></i>");
  fileIconMap.put("xlsx","<i class='fa fa-file-excel-o text-success'></i>");
  fileIconMap.put("ppt" ,"<i class='fa fa-file-powerpoint-o text-danger'></i>");
  fileIconMap.put("pptx","<i class='fa fa-file-powerpoint-o text-danger'></i>");
  fileIconMap.put("jpg" ,"<i class='fa fa-file-photo-o text-warning'></i>");
  fileIconMap.put("pdf" ,"<i class='fa fa-file-pdf-o text-danger'></i>");
  fileIconMap.put("zip" ,"<i class='fa fa-file-archive-o text-muted'></i>");
  fileIconMap.put("rar" ,"<i class='fa fa-file-archive-o text-muted'></i>");
  fileIconMap.put("default" ,"<i class='fa fa-file-o'></i>");
 }

 //从setting.properties文件中注入文件相对目录(相对目录为显示文件)
 //@Value("${uploaderPath}") 只有配置@Config才能注入
 private static final String uploaderPath=PropertiesUtil.getValue("uploaderPath");


 /**
  * 跳转到通用文件上传窗口
  * @return
  */
 @RequestMapping(value="/uploader",method = RequestMethod.GET)
 public String uploader(String config,HttpServletRequest request){
  request.setAttribute("config",config);
  return "base/file/file_uploader";
 }


 /**
  * 通用文件上传接口,存储到固定地址,以后存储到文件服务器地址
  */
 @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
 @ResponseBody
 public SysFile uploadFile(@RequestParam(value = "file", required = false) MultipartFile file,
        HttpServletRequest request, HttpServletResponse response) {
  //TODO dosomething
  return new SysFile();
 }

 /**
  * 多文件上传,用于uploadAsync=false(同步多文件上传使用)
  * @param files
  * @param request
  * @param response
  * @return
  */
 @RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST)
 @ResponseBody
 public FileResult uploadMultipleFile(@RequestParam(value = "file", required = false) MultipartFile[] files,
           HttpServletRequest request, HttpServletResponse response) throws IOException {
  System.out.println("the num of file:"+files.length);

  FileResult msg = new FileResult();

  ArrayList<Integer> arr = new ArrayList<>();
  //缓存当前的文件
  List<SysFile> fileList=new ArrayList<>();
  String dirPath = request.getRealPath("/");
  for (int i = 0; i < files.length; i++) {
   MultipartFile file = files[i];

   if (!file.isEmpty()) {
    InputStream in = null;
    OutputStream out = null;
    try {
     File dir = new File(dirPath+uploaderPath);
     if (!dir.exists())
      dir.mkdirs();
     //这样也可以上传同名文件了
     String filePrefixFormat="yyyyMMddHHmmssS";
     System.out.println(DateUtil.format(new Date(),filePrefixFormat));
     String savedName=DateUtil.format(new Date(),filePrefixFormat)+"_"+file.getOriginalFilename();
     String filePath=dir.getAbsolutePath() + File.separator + savedName;
     File serverFile = new File(filePath);
     //将文件写入到服务器
     //FileUtil.copyInputStreamToFile(file.getInputStream(),serverFile);
     file.transferTo(serverFile);
     SysFile sysFile=new SysFile();
     sysFile.setFileName(file.getOriginalFilename());
     sysFile.setSavedName(savedName);
     sysFile.setCreateDateTime(new Date());
     sysFile.setUpdateDateTime(new Date());
     sysFile.setCreateUserId(SecurityUtil.getUserId());
     sysFile.setDeleted(0);
     sysFile.setFileSize(file.getSize());
     sysFile.setFilePath(uploaderPath+File.separator+savedName);
     uploaderService.save(sysFile);
     fileList.add(sysFile);
     /*preview.add("<div class=\"file-preview-other\">\n" +
       "<span class=\"file-other-icon\"><i class=\"fa fa-file-o text-default\"></i></span>\n" +
       "</div>");*/

     logger.info("Server File Location=" + serverFile.getAbsolutePath());
    } catch (Exception e) {
     logger.error( file.getOriginalFilename()+"上传发生异常,异常原因:"+e.getMessage());
     arr.add(i);
    } finally {
     if (out != null) {
      out.close();
     }
     if (in != null) {
      in.close();
     }
    }
   } else {
    arr.add(i);
   }
  }

  if(arr.size() > 0) {
   msg.setError("文件上传失败!");
   msg.setErrorkeys(arr);
  }
  FileResult preview=getPreivewSettings(fileList,request);
  msg.setInitialPreview(preview.getInitialPreview());
  msg.setInitialPreviewConfig(preview.getInitialPreviewConfig());
  msg.setFileIds(preview.getFileIds());
  return msg;
 }

 //删除某一项文件
 @RequestMapping(value="/delete",method = RequestMethod.POST)
 @ResponseBody
 public Result delete(String id,HttpServletRequest request){
  SysFile sysFile=uploaderService.get(SysFile.class,id);
  String dirPath=request.getRealPath("/");
  FileUtil.delFile(dirPath+uploaderPath+File.separator+sysFile.getSavedName());
  uploaderService.delete(sysFile);
  return new Result();
 }

 /**
  * 获取字体图标map,base-file控件使用
  */
 @RequestMapping(value="/icons",method = RequestMethod.POST)
 @ResponseBody
 public Map getIcons(){
  return fileIconMap;
 }

 /**
  * 根据文件名获取icon
  * @param fileName 文件
  * @return
  */
 public String getFileIcon(String fileName){
  String ext= StrUtil.getExtName(fileName);
  return fileIconMap.get(ext)==null?fileIconMap.get("default").toString():fileIconMap.get(ext).toString();
 }

 /**
  * 根据附件IDS 获取文件
  * @param fileIds
  * @param request
  * @return
  */
 @RequestMapping(value="/getFiles",method = RequestMethod.POST)
 @ResponseBody
 public FileResult getFiles(String fileIds,HttpServletRequest request){
  String[] fileIdArr=fileIds.split(",");
  DetachedCriteria criteria=DetachedCriteria.forClass(SysFile.class);
  criteria.add(Restrictions.in("id",fileIdArr));
  criteria.addOrder(Order.asc("createDateTime"));
  List<SysFile> fileList=uploaderService.findByCriteria(criteria);
  return getPreivewSettings(fileList,request);
 }


 /**
  * 回填已有文件的缩略图
  * @param fileList 文件列表
  * @param request
  * @return initialPreiview initialPreviewConfig fileIds
  */
 public FileResult getPreivewSettings(List<SysFile> fileList,HttpServletRequest request){
  FileResult fileResult=new FileResult();
  List<String> previews=new ArrayList<>();
  List<FileResult.PreviewConfig> previewConfigs=new ArrayList<>();
  //缓存当前的文件
  String dirPath = request.getRealPath("/");
  String[] fileArr=new String[fileList.size()];
  int index=0;
  for (SysFile sysFile : fileList) {
   //上传后预览 TODO 该预览样式暂时不支持theme:explorer的样式,后续可以再次扩展
   //如果其他文件可预览txt、xml、html、pdf等 可在此配置
   if(FileUtil.isImage(dirPath+uploaderPath+File.separator+sysFile.getSavedName())) {
    previews.add("<img src='." + sysFile.getFilePath().replace(File.separator, "/") + "' class='file-preview-image kv-preview-data' " +
      "style='width:auto;height:160px' alt='" + sysFile.getFileName() + " title='" + sysFile.getFileName() + "''>");
   }else{
    previews.add("<div class='kv-preview-data file-preview-other-frame'><div class='file-preview-other'>" +
      "<span class='file-other-icon'>"+getFileIcon(sysFile.getFileName())+"</span></div></div>");
   }
   //上传后预览配置
   FileResult.PreviewConfig previewConfig=new FileResult.PreviewConfig();
   previewConfig.setWidth("120px");
   previewConfig.setCaption(sysFile.getFileName());
   previewConfig.setKey(sysFile.getId());
   // previewConfig.setUrl(request.getContextPath()+"/file/delete");
   previewConfig.setExtra(new FileResult.PreviewConfig.Extra(sysFile.getId()));
   previewConfig.setSize(sysFile.getFileSize());
   previewConfigs.add(previewConfig);
   fileArr[index++]=sysFile.getId();
  }
  fileResult.setInitialPreview(previews);
  fileResult.setInitialPreviewConfig(previewConfigs);
  fileResult.setFileIds(StrUtil.join(fileArr));
  return fileResult;
 }
}

总结

本文源码已在AdminEAP框架(一个基于AdminLTE的Java开发平台)中开源,可在Github下载相关代码:

Github:https://github.com/bill1012/AdminEAP

AdminEAP官网:http://www.admineap.com

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木

Javascript 相关文章推荐
ext读取两种结构的xml的代码
Nov 05 Javascript
Javascript表格翻页效果的具体实现
Oct 05 Javascript
使用jquery animate创建平滑滚动效果(可以是到顶部、到底部或指定地方)
May 27 Javascript
JavaScript中textRange对象使用方法小结
Mar 24 Javascript
JS实现简易图片轮播效果的方法
Mar 25 Javascript
JavaScript返回网页中超链接数量的方法
Apr 03 Javascript
jQuery实现的仿百度分页足迹效果代码
Oct 30 Javascript
跟我学习javascript的浮点数精度
Nov 16 Javascript
js中bool值的转换及“&amp;&amp;”、“||”、 “!!”详解
Dec 21 Javascript
详解小程序原生使用ES7 async/await语法
Aug 06 Javascript
解决mui框架中switch开关通过js控制开或者关状态时小圆点不动的问题
Sep 03 Javascript
springboot+vue实现文件上传下载
Nov 17 Vue.js
js自定义瀑布流布局插件
May 16 #Javascript
简单实现js点击展开二级菜单功能
May 16 #Javascript
JavaScript禁止微信浏览器下拉回弹效果
May 16 #Javascript
jQuery实现div跟随鼠标移动
Aug 20 #jQuery
jquery+ajax实现省市区三级联动 (封装和不封装两种方式)
May 15 #jQuery
bootstrap响应式表格实例详解
May 15 #Javascript
VUE多层路由嵌套实现代码
May 15 #Javascript
You might like
mysql_fetch_assoc和mysql_fetch_row的功能加起来就是mysql_fetch_array
2007/01/15 PHP
php 获得汉字拼音首字母的函数
2009/08/01 PHP
PHP 7.1新特性的汇总介绍
2016/12/16 PHP
初学js插入节点appendChild insertBefore使用方法
2011/07/04 Javascript
cookie 最近浏览记录(中文escape转码)具体实现
2013/06/08 Javascript
jQuery处理xml格式的返回数据(实例解析)
2013/11/28 Javascript
ExtJS4中使用mixins实现多继承示例
2013/12/03 Javascript
javascript实现页面内关键词高亮显示代码
2014/04/03 Javascript
js用拖动滑块来控制图片大小的方法
2015/02/27 Javascript
javascript自定义in_array()函数实现方法
2015/08/03 Javascript
javascript日期验证之输入日期大于等于当前日期
2015/12/13 Javascript
AngularJS使用自定义指令替代ng-repeat的方法
2016/09/17 Javascript
AngularJS路由Ui-router模块用法示例
2017/05/29 Javascript
10行原生JS实现文字无缝滚动(超简单)
2018/01/02 Javascript
vue 2.x 中axios 封装的get 和post方法
2018/02/28 Javascript
vue+vue-router转场动画的实例代码
2018/09/01 Javascript
Angularjs Ng_repeat中实现复选框选中并显示不同的样式方法
2018/09/12 Javascript
Vue动态生成el-checkbox点击无法赋值的解决方法
2019/02/21 Javascript
Vue服务端渲染实践之Web应用首屏耗时最优化方案
2019/03/22 Javascript
js对象数组和对象的使用实例详解
2019/08/27 Javascript
JavaScript 中的无穷数(Infinity)详解
2020/02/13 Javascript
[01:00:14]2018DOTA2亚洲邀请赛 4.6 淘汰赛 VP vs TNC 第三场
2018/04/10 DOTA
[32:39]完美世界DOTA2联赛循环赛 Forest vs Inki BO2第一场 11.04
2020/11/04 DOTA
详解Python中with语句的用法
2015/04/15 Python
在windows下快速搭建web.py开发框架方法
2016/04/22 Python
为Python的Tornado框架配置使用Jinja2模板引擎的方法
2016/06/30 Python
Python语言生成水仙花数代码示例
2017/12/18 Python
python3.6使用pymysql连接Mysql数据库
2018/05/25 Python
Python模拟登录的多种方法(四种)
2018/06/01 Python
Python Multiprocessing多进程 使用tqdm显示进度条的实现
2019/08/13 Python
解决python gdal投影坐标系转换的问题
2020/01/17 Python
解决pycharm同一目录下无法import其他文件
2020/02/12 Python
TensorFlow2.1.0安装过程中setuptools、wrapt等相关错误指南
2020/04/08 Python
Python实现异步IO的示例
2020/11/05 Python
教师产假请假条
2014/04/10 职场文书
原料仓管员岗位职责
2014/04/12 职场文书