热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

WebUploader+SpringMVC实现文件上传功能

WebUploader是由Baidu团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。这篇文章主要介绍了WebUploader+SpringMVC实现文件上传功能,需要的朋友可以参考下

WebUploader是由Baidu团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥html5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS 6+, Android 4+。两套运行时,同样的调用方式,可供用户任意选用。 采用大文件分片并发上传,极大的提高了文件上传效率。

官方文档及更多示例请参考: http://fex.baidu.com/webuploader/

不扯废话了,由于我需要的只是上传图片功能,官网上边还说“WebUploader只包含文件上传的底层实现,不包括UI部分,所以交互方面可以自由发挥。”但是我又看到官网的例子不错,就把demo的js和css扒了下来.

这里写图片描述

这里写图片描述

前台相关代码:

jsp:

<%@ page language="java" cOntentType="text/html; charset=UTF-8"
 pageEncoding="UTF-8"%>















 

Demo

您可以尝试文件拖拽,使用QQ截屏工具,然后激活窗口后粘贴,或者点击添加图片按钮,来体验此demo.

或将照片拖到这里,单次最多可选300张

0%
开始上传

uploader_demo.js

jQuery(function() {
 var $ = jQuery, // just in case. Make sure it's not an other libaray.
  $wrap = $('#uploader'),  // 图片容器
  $queue = $('
    ') .appendTo( $wrap.find('.queueList') ), // 状态栏,包括进度和控制按钮 $statusBa $wrap.find('.statusBar'), // 文件总体选择信息。 $info = $statusBar.find('.info'), // 上传按钮 $upload = $wrap.find('.uploadBtn'), // 没选择文件之前的内容。 $placeHolder = $wrap.find('.placeholder'), // 总体进度条 $progress = $statusBar.find('.progress').hide(), // 添加的文件数量 fileCount = 0, // 添加的文件总大小 fileSize = 0, // 优化retina, 在retina下这个值是2 ratio = window.devicePixelRatio || 1, // 缩略图大小 thumbnailWidth = 110 * ratio, thumbnailHeight = 110 * ratio, // 可能有pedding, ready, uploading, confirm, done. state = 'pedding', // 所有文件的进度信息,key为file id percentages = {}, supportTransition = (function(){ var s = document.createElement('p').style, r = 'transition' in s || 'WebkitTransition' in s || 'MozTransition' in s || 'msTransition' in s || 'OTransition' in s; s = null; return r; })(), // WebUploader实例 uploader; if ( !WebUploader.Uploader.support() ) { alert( 'Web Uploader 不支持您的浏览器!如果你使用的是IE浏览器,请尝试升级 flash 播放器'); throw new Error( 'WebUploader does not support the browser you are using.' ); } // 实例化 uploader = WebUploader.create({ pick: { id: '#filePicker', label: '点击选择图片' }, dnd: '#uploader .queueList', paste: document.body, accept: { title: 'Images', extensions: 'gif,jpg,jpeg,bmp,png', mimeTypes: 'image/*' }, // swf文件路径,就是控件下的swf文件地址 swf: 'js/plugins/webuploader/Uploader.swf', disableGlobalDnd: true, chunked: true, // 文件接收服务端,写你要执行的方法就行 **server: 'http://localhost:8080/test/upload.do&#63;method=upload'**, fileNumLimit: 300, fileSizeLimit: 5 * 1024 * 1024, // 200 M fileSingleSizeLimit: 1 * 1024 * 1024 // 50 M }); // 添加“添加文件”的按钮, uploader.addButton({ id: '#filePicker2', label: '继续添加' }); // 当有文件添加进来时执行,负责view的创建 function addFile( file ) { var $li = $( '
  • ' + '

    ' + file.name + '

    ' + '

    '+ '

    ' + '
  • ' ), $btns = $('
    ' + '删除' + '向右旋转' + '向左旋转
    ').appendTo( $li ), $prgress = $li.find('p.progress span'), $wrap = $li.find( 'p.imgWrap' ), $info = $('

    '), showError = function( code ) { switch( code ) { case 'exceed_size': text = '文件大小超出'; break; case 'interrupt': text = '上传暂停'; break; default: text = '上传失败,请重试'; break; } $info.text( text ).appendTo( $li ); }; if ( file.getStatus() === 'invalid' ) { showError( file.statusText ); } else { // @todo lazyload $wrap.text( '预览中' ); uploader.makeThumb( file, function( error, src ) { if ( error ) { $wrap.text( '不能预览' ); return; } var img = $(''); $wrap.empty().append( img ); }, thumbnailWidth, thumbnailHeight ); percentages[ file.id ] = [ file.size, 0 ]; file.rotation = 0; } file.on('statuschange', function( cur, prev ) { if ( prev === 'progress' ) { $prgress.hide().width(0); } else if ( prev === 'queued' ) { $li.off( 'mouseenter mouseleave' ); $btns.remove(); } // 成功 if ( cur === 'error' || cur === 'invalid' ) { console.log( file.statusText ); showError( file.statusText ); percentages[ file.id ][ 1 ] = 1; } else if ( cur === 'interrupt' ) { showError( 'interrupt' ); } else if ( cur === 'queued' ) { percentages[ file.id ][ 1 ] = 0; } else if ( cur === 'progress' ) { $info.remove(); $prgress.css('display', 'block'); } else if ( cur === 'complete' ) { $li.append( '' ); } $li.removeClass( 'state-' + prev ).addClass( 'state-' + cur ); }); $li.on( 'mouseenter', function() { $btns.stop().animate({height: 30}); }); $li.on( 'mouseleave', function() { $btns.stop().animate({height: 0}); }); $btns.on( 'click', 'span', function() { var index = $(this).index(), deg; switch ( index ) { case 0: uploader.removeFile( file ); return; case 1: file.rotation += 90; break; case 2: file.rotation -= 90; break; } if ( supportTransition ) { deg = 'rotate(' + file.rotation + 'deg)'; $wrap.css({ '-webkit-transform': deg, '-mos-transform': deg, '-o-transform': deg, 'transform': deg }); } else { $wrap.css( 'filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+ (~~((file.rotation/90)%4 + 4)%4) +')'); // use jquery animate to rotation // $({ // rotation: rotation // }).animate({ // rotation: file.rotation // }, { // easing: 'linear', // step: function( now ) { // now = now * Math.PI / 180; // var cos = Math.cos( now ), // sin = Math.sin( now ); // $wrap.css( 'filter', "progid:DXImageTransform.Microsoft.Matrix(M11=" + cos + ",M12=" + (-sin) + ",M21=" + sin + ",M22=" + cos + ",SizingMethod='auto expand')"); // } // }); } }); $li.appendTo( $queue ); } // 负责view的销毁 function removeFile( file ) { var $li = $('#'+file.id); delete percentages[ file.id ]; updateTotalProgress(); $li.off().find('.file-panel').off().end().remove(); } function updateTotalProgress() { var loaded = 0, total = 0, spans = $progress.children(), percent; $.each( percentages, function( k, v ) { total += v[ 0 ]; loaded += v[ 0 ] * v[ 1 ]; } ); percent = total &#63; loaded / total : 0; spans.eq( 0 ).text( Math.round( percent * 100 ) + '%' ); spans.eq( 1 ).css( 'width', Math.round( percent * 100 ) + '%' ); updateStatus(); } function updateStatus() { var text = '', stats; if ( state === 'ready' ) { text = '选中' + fileCount + '张图片,共' + WebUploader.formatSize( fileSize ) + '。'; } else if ( state === 'confirm' ) { stats = uploader.getStats(); if ( stats.uploadFailNum ) { text = '已成功上传' + stats.successNum+ '张照片至XX相册,'+ stats.uploadFailNum + '张照片上传失败,重新上传失败图片或忽略' } } else { stats = uploader.getStats(); text = '共' + fileCount + '张(' + WebUploader.formatSize( fileSize ) + '),已上传' + stats.successNum + '张'; if ( stats.uploadFailNum ) { text += ',失败' + stats.uploadFailNum + '张'; } } $info.html( text ); } function setState( val ) { var file, stats; if ( val === state ) { return; } $upload.removeClass( 'state-' + state ); $upload.addClass( 'state-' + val ); state = val; switch ( state ) { case 'pedding': $placeHolder.removeClass( 'element-invisible' ); $queue.parent().removeClass('filled'); $queue.hide(); $statusBar.addClass( 'element-invisible' ); uploader.refresh(); break; case 'ready': $placeHolder.addClass( 'element-invisible' ); $( '#filePicker2' ).removeClass( 'element-invisible'); $queue.parent().addClass('filled'); $queue.show(); $statusBar.removeClass('element-invisible'); uploader.refresh(); break; case 'uploading': $( '#filePicker2' ).addClass( 'element-invisible' ); $progress.show(); $upload.text( '暂停上传' ); break; case 'paused': $progress.show(); $upload.text( '继续上传' ); break; case 'confirm': $progress.hide(); $upload.text( '开始上传' ).addClass( 'disabled' ); stats = uploader.getStats(); if ( stats.successNum && !stats.uploadFailNum ) { setState( 'finish' ); return; } break; case 'finish': stats = uploader.getStats(); if ( stats.successNum ) { alert( '上传成功' ); } else { // 没有成功的图片,重设 state = 'done'; location.reload(); } break; } updateStatus(); } uploader.OnUploadProgress= function( file, percentage ) { var $li = $('#'+file.id), $percent = $li.find('.progress span'); $percent.css( 'width', percentage * 100 + '%' ); percentages[ file.id ][ 1 ] = percentage; updateTotalProgress(); }; uploader.OnFileQueued= function( file ) { fileCount++; fileSize += file.size; if ( fileCount === 1 ) { $placeHolder.addClass( 'element-invisible' ); $statusBar.show(); } addFile( file ); setState( 'ready' ); updateTotalProgress(); }; uploader.OnFileDequeued= function( file ) { fileCount--; fileSize -= file.size; if ( !fileCount ) { setState( 'pedding' ); } removeFile( file ); updateTotalProgress(); }; uploader.on( 'all', function( type ) { var stats; switch( type ) { case 'uploadFinished': setState( 'confirm' ); break; case 'startUpload': setState( 'uploading' ); break; case 'stopUpload': setState( 'paused' ); break; } }); uploader.OnError= function( code ) { alert( 'Eroor: ' + code ); }; $upload.on('click', function() { if ( $(this).hasClass( 'disabled' ) ) { return false; } if ( state === 'ready' ) { uploader.upload(); } else if ( state === 'paused' ) { uploader.upload(); } else if ( state === 'uploading' ) { uploader.stop(); } }); $info.on( 'click', '.retry', function() { uploader.retry(); } ); $info.on( 'click', '.ignore', function() { alert( 'todo' ); } ); $upload.addClass( 'state-' + state ); updateTotalProgres});

    uploader_demo.css

    #container {
     color: #838383;
     font-size: 12px;
    }
    #uploader .queueList {
     margin: 20px;
     border: 3px dashed #e6e6e6;
    }
    #uploader .queueList.filled {
     padding: 17px;
     margin: 0;
     border: 3px dashed transparent;
    }
    #uploader .queueList.webuploader-dnd-over {
     border: 3px dashed #999999;
    }
    #uploader p {margin: 0;}
    .element-invisible {
     position: absolute !important;
     clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
     clip: rect(1px,1px,1px,1px);
    }
    #uploader .placeholder {
     min-height: 350px;
     padding-top: 178px;
     text-align: center;
     background: url(../images/image.png) center 93px no-repeat;
     color: #cccccc;
     font-size: 18px;
     position: relative;
    }
    #uploader .placeholder .webuploader-pick {
     font-size: 18px;
     background: #00b7ee;
     border-radius: 3px;
     line-height: 44px;
     padding: 0 30px;
     *width: 120px;
     color: #fff;
     display: inline-block;
     margin: 0 auto 20px auto;
     cursor: pointer;
     box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
    }
    #uploader .placeholder .webuploader-pick-hover {
     background: #00a2d4;
    }
    #uploader .placeholder .flashTip {
     color: #666666;
     font-size: 12px;
     position: absolute;
     width: 100%;
     text-align: center;
     bottom: 20px;
    }
    #uploader .placeholder .flashTip a {
     color: #0785d1;
     text-decoration: none;
    }
    #uploader .placeholder .flashTip a:hover {
     text-decoration: underline;
    }
    #uploader .filelist {
     list-style: none;
     margin: 0;
     padding: 0;
    }
    #uploader .filelist:after {
     content: '';
     display: block;
     width: 0;
     height: 0;
     overflow: hidden;
     clear: both;
    }
    #uploader .filelist li {
     width: 110px;
     height: 110px;
     background: url(../images/bg.png) no-repeat;
     text-align: center;
     margin: 0 8px 20px 0;
     position: relative;
     display: inline;
     float: left;
     overflow: hidden;
     font-size: 12px;
    }
    #uploader .filelist li p.log {
     position: relative;
     top: -45px;
    }
    #uploader .filelist li p.title {
     position: absolute;
     top: 0;
     left: 0;
     width: 100%;
     overflow: hidden;
     white-space: nowrap;
     text-overflow : ellipsis;
     top: 5px;
     text-indent: 5px;
     text-align: left;
    }
    #uploader .filelist li p.progress {
     position: absolute;
     width: 100%;
     bottom: 0;
     left: 0;
     height: 8px;
     overflow: hidden;
     z-index: 50;
     margin: 0;
     border-radius: 0;
     background: none;
     -webkit-box-shadow: 0 0 0;
    }
    #uploader .filelist li p.progress span {
     display: none;
     overflow: hidden;
     width: 0;
     height: 100%;
     background: #1483d8 url(../images/progress.png) repeat-x;
     -webit-transition: width 200ms linear;
     -moz-transition: width 200ms linear;
     -o-transition: width 200ms linear;
     -ms-transition: width 200ms linear;
     transition: width 200ms linear;
     -webkit-animation: progressmove 2s linear infinite;
     -moz-animation: progressmove 2s linear infinite;
     -o-animation: progressmove 2s linear infinite;
     -ms-animation: progressmove 2s linear infinite;
     animation: progressmove 2s linear infinite;
     -webkit-transform: translateZ(0);
    }
    @-webkit-keyframes progressmove {
     0% {
      background-position: 0 0;
     }
     100% {
      background-position: 17px 0;
     }
    }
    @-moz-keyframes progressmove {
     0% {
      background-position: 0 0;
     }
     100% {
      background-position: 17px 0;
     }
    }
    @keyframes progressmove {
     0% {
      background-position: 0 0;
     }
     100% {
      background-position: 17px 0;
     }
    }
    #uploader .filelist li p.imgWrap {
     position: relative;
     z-index: 2;
     line-height: 110px;
     vertical-align: middle;
     overflow: hidden;
     width: 110px;
     height: 110px;
     -webkit-transform-origin: 50% 50%;
     -moz-transform-origin: 50% 50%;
     -o-transform-origin: 50% 50%;
     -ms-transform-origin: 50% 50%;
     transform-origin: 50% 50%;
     -webit-transition: 200ms ease-out;
     -moz-transition: 200ms ease-out;
     -o-transition: 200ms ease-out;
     -ms-transition: 200ms ease-out;
     transition: 200ms ease-out;
    }
    #uploader .filelist li img {
     width: 100%;
    }
    #uploader .filelist li p.error {
     background: #f43838;
     color: #fff;
     position: absolute;
     bottom: 0;
     left: 0;
     height: 28px;
     line-height: 28px;
     width: 100%;
     z-index: 100;
    }
    #uploader .filelist li .success {
     display: block;
     position: absolute;
     left: 0;
     bottom: 0;
     height: 40px;
     width: 100%;
     z-index: 200;
     background: url(../images/success.png) no-repeat right bottom;
    }
    #uploader .filelist div.file-panel {
     position: absolute;
     height: 0;
     filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#80000000', endColorstr='#80000000')\0;
     background: rgba( 0, 0, 0, 0.5 );
     width: 100%;
     top: 0;
     left: 0;
     overflow: hidden;
     z-index: 300;
    }
    #uploader .filelist div.file-panel span {
     width: 24px;
     height: 24px;
     display: inline;
     float: right;
     text-indent: -9999px;
     overflow: hidden;
     background: url(../../img/uploader_icons.png) no-repeat;
     margin: 5px 1px 1px;
     cursor: pointer; 
    }
    #uploader .filelist div.file-panel span.rotateLeft {
     background-position: 0 -24px;
    }
    #uploader .filelist div.file-panel span.rotateLeft:hover {
     background-position: 0 0;
    }
    #uploader .filelist div.file-panel span.rotateRight {
     background-position: -24px -24px;
    }
    #uploader .filelist div.file-panel span.rotateRight:hover {
     background-position: -24px 0;
    }
    #uploader .filelist div.file-panel span.cancel {
     background-position: -48px -24px;
    }
    #uploader .filelist div.file-panel span.cancel:hover {
     background-position: -48px 0;
    }
    #uploader .statusBar {
     height: 63px;
     border-top: 1px solid #dadada;
     padding: 0 20px;
     line-height: 63px;
     vertical-align: middle;
     position: relative;
    }
    #uploader .statusBar .progress {
     border: 1px solid #1483d8;
     width: 198px;
     background: #fff;
     height: 18px;
     position: relative;
     display: inline-block;
     text-align: center;
     line-height: 20px;
     color: #6dbfff;
     position: relative;
     margin: 0 10px 0 0;
    }
    #uploader .statusBar .progress span.percentage {
     width: 0;
     height: 100%;
     left: 0;
     top: 0;
     background: #1483d8;
     position: absolute;
    }
    #uploader .statusBar .progress span.text {
     position: relative;
     z-index: 10;
    }
    #uploader .statusBar .info {
     display: inline-block;
     font-size: 14px;
     color: #666666;
    }
    #uploader .statusBar .btns {
     position: absolute;
     top: 10px;
     right: 20px;
     line-height: 40px;
    }
    #filePicker2 {
     display: inline-block;
     float: left;
    }
    #uploader .statusBar .btns .webuploader-pick,
    #uploader .statusBar .btns .uploadBtn,
    #uploader .statusBar .btns .uploadBtn.state-uploading,
    #uploader .statusBar .btns .uploadBtn.state-paused {
     background: #ffffff;
     border: 1px solid #cfcfcf;
     color: #565656;
     padding: 0 18px;
     display: inline-block;
     border-radius: 3px;
     margin-left: 10px;
     cursor: pointer;
     font-size: 14px;
     float: left;
    }
    #uploader .statusBar .btns .webuploader-pick-hover,
    #uploader .statusBar .btns .uploadBtn:hover,
    #uploader .statusBar .btns .uploadBtn.state-uploading:hover,
    #uploader .statusBar .btns .uploadBtn.state-paused:hover {
     background: #f0f0f0;
    }
    #uploader .statusBar .btns .uploadBtn {
     background: #00b7ee;
     color: #fff;
     border-color: transparent;
    }
    #uploader .statusBar .btns .uploadBtn:hover {
     background: #00a2d4;
    }
    #uploader .statusBar .btns .uploadBtn.disabled {
     pointer-events: none;
     opacity: 0.6;
    }

    后台代码:

    @Controller
    @RequestMapping("/upload")
    public class UpLoaderTestController {
     @RequestMapping(params = "method=uploadPic")
     public String uploadPic(HttpServletRequest request){
      return "uploaderDemo/uploaderTest";
     }
     @RequestMapping(params="method=upload")
     @ResponseBody
     public String uploads(@RequestParam("file")MultipartFile sortPicImg,HttpServletRequest request,HttpServletResponse response) {
      String path = SysConstants.PIC_SERVER_FILE_ROOT_DIR +SysConstants.PIC_PTYPE_DIR ;
      String fileName = System.currentTimeMillis()+"_"+sortPicImg.getOriginalFilename();
      File targetFile = new File(path, fileName);
      if (!targetFile.exists()) {
       targetFile.mkdirs();
      }
      JSONObject json = new JSONObject();
      //保存
      try {
       sortPicImg.transferTo(targetFile);
      } catch (Exception e) {
       e.printStackTrace();
       json.put("msg","error");
       return json.toJSONString();
      }
      json.put("msg","success");
      //json.put("filePath",request.getContextPath() + "/upload/" + fileName);
      File retfile = new File(SysConstants.PIC_SERVER_DNS +SysConstants.PIC_PTYPE_DIR, fileName);
      json.put("filePath",retfile.getPath());
      System.out.println("json="+json.toJSONString());
      return json.toJSONString();
     }
     }

    前台传到后台的图片是一张一张传的,每传一张图片调用一次该server方法,直到传完为止。

    将图片文件上传到图片服务器后,再将该图片地址存储在数据库中。


    推荐阅读
    • 利用ipv6技术,废旧笔记本变成server
      如果你家的路由器已经get到了ipv6地址,并且你家的电脑也获取了有效的ipv6地址,在广域网的设备可以访问到。那恭喜你,再配合我这个dd ... [详细]
    • Netty源代码分析服务器端启动ServerBootstrap初始化
      本文主要分析了Netty源代码中服务器端启动的过程,包括ServerBootstrap的初始化和相关参数的设置。通过分析NioEventLoopGroup、NioServerSocketChannel、ChannelOption.SO_BACKLOG等关键组件和选项的作用,深入理解Netty服务器端的启动过程。同时,还介绍了LoggingHandler的作用和使用方法,帮助读者更好地理解Netty源代码。 ... [详细]
    • 第38天:Python decimal 模块
      by程序员野客在我们开发工作中浮点类型的使用还是比较普遍的,对于一些涉及资金金额的计算更是不能有丝毫误差,Python的decimal模块为浮点型精确计算提供了支持。1简介deci ... [详细]
    • 摘自:https:www.cnblogs.comnick-huangp4076273.htmlselect*from(select'Nick'asitemfromd ... [详细]
    • 写在前面GitDataV,是一个github“大数据可视化平台”,通过它你可以更直观的看到你在github里的一些数据,(之所以打双引号& ... [详细]
    • socket8 [命名管道]
      ::命名管道不但能实现同一台机器上两个进程通信,还能在网络中不同机器上的两个进程之间的通信机制。与邮槽不同,命名管道是采用基于连接并且可靠的传输方式,所以命名管道传输数据只能一对一 ... [详细]
    • 一、vue-resource1、引入资源方式1)下载vue-resource.js,添加到项目中2)CDN:http:www ... [详细]
    • Bootstrap datetimepicker控件 日期时间选择器 简单使用
      bootstrap-datetimepicker日期控件简单使用应用场景:表单日期 ... [详细]
    • JS·经典·炫彩菜单(动画效果) for jquery
      CSS样式body{font-size:12px;}.menuBox{width:50%;height:auto;margin:0auto;}.menuBoxul{margin:0 ... [详细]
    • Html5-Canvas实现简易的抽奖转盘效果
      本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
    • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
    • 本文介绍了响应式页面的概念和实现方式,包括针对不同终端制作特定页面和制作一个页面适应不同终端的显示。分析了两种实现方式的优缺点,提出了选择方案的建议。同时,对于响应式页面的需求和背景进行了讨论,解释了为什么需要响应式页面。 ... [详细]
    • HTML5网页模板怎么加百度统计?
      本文介绍了如何在HTML5网页模板中加入百度统计,并对模板文件、css样式表、js插件库等内容进行了说明。同时还解答了关于HTML5网页模板的使用方法、表单提交、域名和空间的问题,并介绍了如何使用Visual Studio 2010创建HTML5模板。此外,还提到了使用Jquery编写美好的HTML5前端框架模板的方法,以及制作企业HTML5网站模板和支持HTML5的CMS。 ... [详细]
    • 从零基础到精通的前台学习路线
      随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
    • css元素可拖动,如何使用CSS禁止元素拖拽?
      一、用户行为三剑客以下3个CSS属性:user-select属性可以设置是否允许用户选择页面中的图文内容;user-modify属性可以设置是否允许输入 ... [详细]
    author-avatar
    妩媚的麻醉效应
    这个家伙很懒,什么也没留下!
    PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有