基于python的最简单jQuery File Upload示例

2015年3月27日 13:42

找到个很不错的文件上传插件jQuery File Upload. 资料太少. 只能自己搭个环境,照着例子摸索. 奈何最简单的例子是基于php的, 不熟. 弄了个基于python的例子.
  • github
https://github.com/blueimp/jQuery-File-Upload
  • 目录
使用flask做了个简单web服务器,接收上传请求. 目录结构如下
https://github.c➜  flask-demo  tree
.
├── app.py
├── static
│   ├── 123.txt
│   └── file-upload
│       ├── angularjs.html
│       ├── basic.html
│       ├── basic-plus.html
│       ├── blueimp-file-upload.jquery.json
│       ├── bower.json
│       ├── CONTRIBUTING.md
│       ├── cors
│       │   ├── postmessage.html
│       │   └── result.html
│       ├── css
│       │   ├── demo.css
│       │   ├── demo-ie8.css
│       │   ├── jquery.fileupload.css
│       │   ├── jquery.fileupload-noscript.css
│       │   ├── jquery.fileupload-ui.css
│       │   ├── jquery.fileupload-ui-noscript.css
│       │   └── style.css
│       ├── Gruntfile.js
│       ├── img
│       │   ├── loading.gif
│       │   └── progressbar.gif
│       ├── index.html
│       ├── jquery-ui.html
│       ├── js
│       │   ├── app.js
│       │   ├── cors
│       │   │   ├── jquery.postmessage-transport.js
│       │   │   └── jquery.xdr-transport.js
│       │   ├── jquery.fileupload-angular.js
│       │   ├── jquery.fileupload-audio.js
│       │   ├── jquery.fileupload-image.js
│       │   ├── jquery.fileupload-jquery-ui.js
│       │   ├── jquery.fileupload.js
│       │   ├── jquery.fileupload-process.js
│       │   ├── jquery.fileupload-ui.js
│       │   ├── jquery.fileupload-validate.js
│       │   ├── jquery.fileupload-video.js
│       │   ├── jquery.iframe-transport.js
│       │   ├── jquery.min.js
│       │   ├── main.js
│       │   └── vendor
│       │       └── jquery.ui.widget.js
│       ├── package.json
│       ├── README.md
│       ├── server
│       │   ├── gae-go
│       │   │   ├── app
│       │   │   │   └── main.go
│       │   │   ├── app.yaml
│       │   │   └── static
│       │   │       ├── favicon.ico
│       │   │       └── robots.txt
│       │   ├── gae-python
│       │   │   ├── app.yaml
│       │   │   ├── main.py
│       │   │   └── static
│       │   │       ├── favicon.ico
│       │   │       └── robots.txt
│       │   ├── node
│       │   │   ├── package.json
│       │   │   ├── public
│       │   │   │   └── files
│       │   │   │       └── thumbnail
│       │   │   ├── server.js
│       │   │   └── tmp
│       │   └── php
│       │       ├── files
│       │       ├── index.php
│       │       └── UploadHandler.php
│       ├── test
│       │   ├── index.html
│       │   └── test.js
│       └── test.html
└── templates
    └── index.html

23 directories, 57 filesom/blueimp/jQuery-File-Upload
  • app.py
#encoding=utf-8
from flask import Flask
from flask import request
from flask import abort, redirect, url_for
from flask import render_template
import json

app = Flask(__name__)


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['files[]']
        filename = f.filename
        minetype = f.content_type
        f.save('static/' + filename)
    return json.dumps({"files": [{"name": filename, "minetype": minetype}]})


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=7000, debug=True)
  • demo.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>jQuery File Upload 示例</title>
</head>
<body>
<input id="fileupload" type="file" name="files[]" data-url="/upload" multiple>
<script src="/static/file-upload/js/jquery.min.js"></script>
<script src="/static/file-upload/js/vendor/jquery.ui.widget.js"></script>
<script src="/static/file-upload/js/jquery.iframe-transport.js"></script>
<script src="/static/file-upload/js/jquery.fileupload.js"></script>
<script>
$(function () {
    $('#fileupload').fileupload({
        dataType: 'json',
        done: function (e, data) {
            $.each(data.result.files, function (index, file) {
                $('<p/>').text(file.name).appendTo(document.body);
            });
        }
    });
});
</script>
</body> 
</html>
试了之后,确实很不错.
 

Tags: python flask jquery
评论(8) 阅读(7582)

异步加载css文件

2015年3月26日 10:45

$("<link>")
.attr({
    rel: "stylesheet",
    type: "text/css",
    href: "/static/videojs/video.js"
})
.appendTo("head");

Tags: css
评论(0) 阅读(1503)

video.js视频播放插件初试

2015年3月25日 10:57

最近在弄视频服务器,首先找播放插件。当看到video.js,非常清爽,并且它支持flv、mp4、webm、ogv播放格式,比较喜欢,所以选它.

简单示例

  • video.js官网
http://www.videojs.com/
  • 下载
wget http://www.videojs.com/downloads/video-js-4.12.5.zip
  • 解压
unzip video-js-4.12.5.zip
  • 简易web服务器
进入video-js目录,使用python,运行一个简易服务器
➜  video-js  python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
 
在浏览器访问http://localhost:8000/demo.html 即可看到demo

demo.html文件介绍

<!DOCTYPE html>
<html>
<head>
  <title>Video.js | HTML5 Video Player</title>

  <!-- Chang URLs to wherever Video.js files will be hosted -->
  <link href="video-js.css" rel="stylesheet" type="text/css">
  <!-- video.js must be in the <head> for older IEs to work. -->
  <script src="video.js"></script>

  <!-- Unless using the CDN hosted version, update the URL to the Flash SWF -->
  <script>
    <!--支持播放flv -->
    videojs.options.flash.swf = "video-js.swf";
  </script>


</head>
<body>
  <!-- poster封面 preload预加载 -->
  <video id="example_video_1" class="video-js vjs-default-skin" controls preload="none" width="640" height="264"
      poster="http://video-js.zencoder.com/oceans-clip.png"
      data-setup="{}">
    <!-- 三种播放格式-->
    <source src="http://video-js.zencoder.com/oceans-clip.mp4" type='video/mp4' />
    <source src="http://video-js.zencoder.com/oceans-clip.webm" type='video/webm' />
    <source src="http://video-js.zencoder.com/oceans-clip.ogv" type='video/ogg' />
    <!-- 字幕 -->
    <track kind="captions" src="demo.captions.vtt" srclang="en" label="English"></track><!-- Tracks need an ending tag thanks to IE9 -->
    <track kind="subtitles" src="demo.captions.vtt" srclang="en" label="English"></track><!-- Tracks need an ending tag thanks to IE9 -->
    <p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
  </video>

</body>
</html>
 
从上可看出,支持四种播放格式flv、mp4、webm、ogv

测试自己的视频

  • 转换视频
找个mp4视频,然后转换为flv、ogv、webm、swf格式. 
➜  video-js  ls -sh video
总用量 303M
 25M demo.flv   96M demo.ogv   40M demo.webm
120M demo.mp4   25M demo.swf
  • 修改demo.html文件
<source src="/video/demo.flv" type='video/x-flv' />
<!--
<source src="/video/demo.ogv" type='video/ogg' />
<source src="/video/demo.mp4" type='video/mp4' />
<source src="/video/demo.webm" type='video/webm' />
-->
  • 播放效果
改成自己的视频后,发现播放非常慢. 由于视频在本地,这种情况不正常. 最后发现由于视频文件放在web服务器中,web服务器处理静态数据很慢.

nginx静态资源服务器

有没有更快的访问方式?想到nginx处理静态数据非常快. 
  • 安装nginx
nginx的安装就不说了
 
  • 修改配置
location / {
    root   /home/wyq/workspace/video-js/;
    #root   html;
    index  index.html index.htm;
}
启动nginx之后,通过它访问demo.html,发现此时播放视频非常流畅.
  • 限速   
假如视频把网页速度占了,怎么限制视频速度?在可以在nginx中添加如下参数.
location / {
    root   /home/wyq/workspace/video-js/;
    limit_rate_after 5m; #下载5M以后开始限速
    limit_rate 512k;     #每个链接速度限制为512K
    #root   html;
    index  index.html index.htm;
}
 
另外找资料发现,网上说播放视频需要http_flv_module模块才支持拖动播放flv视频. 按照上面方法,没有安装flv模块,也可以拖动播放。想了下原因,可能我用的是nginx1.6,比较新,不需要安装flv模块,也可以拖动播放. 
 

Tags: jquery
评论(1) 阅读(22485)

$('a').click()无法触发页面跳转

2015年2月14日 22:55

描述

在用$("a").click()方法, 触发a元素点击事件,进行页面跳转效果. 结果发现页面未发生跳转.

示例

<html>
<meta charset='utf-8'>
<body>
<button id="btn">按钮</button>
<a href="http://www.baidu.com" target="_blank" id="link">链接</a>
</body>
<script src="/jquery1.91.js" type="text/javascript"></script>
<script>
$(function(){
    $("#btn").click(function(e){
        //触发点击事件
        $("a").click();
    });
</script>
</html>

解决方法

  • 第一种: 用原生的a对象触发事件
$("a")[0].click();
  • 第二种: 通过事件冒泡触发事件
<a href="http://www.baidu.com" target="_blank" id="link"><span id="link">链接</span></a>

$(function(){
    $("#btn").click(function(e){
        //触发点击事件
        $("#link").click();
    });
</script>
 

Tags: jquery
评论(0) 阅读(1444)

<img>加载图片失败,怎样替换为默认图片

2015年1月05日 15:45

img元素加载图片失败,则变成一个小图标,让页面变得难看。此时如何替换为默认图片?

onerror属性

img元素自带onerror属性,加载失败时,触发error事件
<img src="image.gif" onerror='this.src="default.gif" />

jquery.error函数

jquery提供对应的事件处理函数
$('img').error(function(){
    $(this).attr('src',"default.gif");
})

jquery.one函数

使用上面两种方法,假如默认图片也加载失败,则变成死循环. 此时可使用one()绑定事件
$("img").one("error", function(e){
     $(this).attr("src", "default.gif");
});
 
另外error事件,不支持冒泡,jquery.delegate函数捕捉不到error事件。
 

Tags: html
评论(0) 阅读(7758)

angularjs过滤器(number)

2014年8月22日 21:13

用来精确浮点数(指定小数点位数).

在html中用法

{{ number_expression | number : fractionSize}}

在js中用法

$filter('number')(number, fractionSize)

参数

  • number 待精确的数字
  • factionSize(可选) 小数点后精确位数,默认值是3.
默认情况下保留的小数位数小于等于3. 比如: 1234-->1234;1234.56789-->1234.568;1234.56-->1234.56)

例子

<!doctype html>
<html ng-app='demo'>
<meta charset='utf-8'>
<body>
<div ng-controller="ExampleController">
  输入数字: <input ng-model='val'><br>
  <!-- 默认格式 -->
  默认格式: <span id='number-default'>{{val | number}}</span><br>
  <!-- factionSize=0 -->
  保留0位: <span>{{val | number:0}}</span><br>
  <!--factionSize大于小数点位数 -->
  保留10位: <span>{{val | number:10}}</span><br>
  <!-- factionSize小于小数点位数-->
  保留2位: <span>{{val | number:2}}</span>
</div>

<script src="/static/lib/angular/angular.js"></script>
<script src="/static/lib/angular-resource/angular-resource.min.js"></script>
<script>
    var app = angular.module('demo', ['ngResource'])
    .controller('ExampleController', function($scope) {
        $scope.val = 1234.56789;
    });
</script>
</body>
</html>
 
显示结果
输入数字: 1,234.56789
默认格式: 1,234.568
保留0位: 1,235
保留10位: 1,234.5678900000
保留2位: 1,234.57
 

Tags: angularjs;过滤器;number
评论(0) 阅读(5189)

angularjs指令名是怎么回事?

2014年8月12日 12:06

疑惑

查了很多资料,对指令名的介绍都是一笔带过,只说是驼峰形式. 但是在实际使用时,经常遇到定义的指令名与指令标签对应不上的情况. 对指令名就感到非常疑惑. 定义时指令名是一种形式,使用时又是一种形式,两者怎么关联对应的?
 
找不到资料,自己查查angular源码,一探究竟.

分析源码

首先在angular.js文件,找到解析指令名的代码
switch(nodeType) {
  case 1: /* Element */
    // use the node name: <directive>
    //此处是解析标签形式的指令
    addDirective(directives,
        directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);

    // iterate over the attributes
    for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
             j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
      var attrStartName = false;
      var attrEndName = false;

      attr = nAttrs[j];
      if (!msie || msie >= 8 || attr.specified) {
        name = attr.name;
        value = trim(attr.value);

        // support ngAttr attribute binding
        ngAttrName = directiveNormalize(name);
        if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
          name = snake_case(ngAttrName.substr(6), '-');
        }

        var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
        if (ngAttrName === directiveNName + 'Start') {
          attrStartName = name;
          attrEndName = name.substr(0, name.length - 5) + 'end';
          name = name.substr(0, name.length - 6);
        }

        //此处是解析属性形式的指令名
        nName = directiveNormalize(name.toLowerCase());
        attrsMap[nName] = name;
        if (isNgAttr || !attrs.hasOwnProperty(nName)) {
            attrs[nName] = value;
            if (getBooleanAttrName(node, nName)) {
              attrs[nName] = true; // presence means true
            }
        }
        addAttrInterpolateDirective(node, directives, value, nName);
        addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
                      attrEndName);
      }
    }
上面一处是解析标签形式的指令名,调用了directiveNormalize(nodeName_(node).toLowerCase())
另一处是解析属性形式的指令名,调用了directiveNormalize(name.toLowerCase())
两处都使用了toLowerCase()
所以解析指令的第一步:将指令名转为小写.
 
继续看directiveNormalize()函数
var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
/**
 * Converts all accepted directives format into proper directive name.
 * All of these will become 'myDirective':
 *   my:Directive
 *   my-directive
 *   x-my-directive
 *   data-my:directive
 *
 * Also there is special case for Moz prefix starting with upper case letter.
 * @param name Name to normalize
 */
function directiveNormalize(name) {
  return camelCase(name.replace(PREFIX_REGEXP, ''));
}
它使用用了name.replace(PREFIX_REGEXP, ''),它的作用是去掉x和data开始的前缀
所以解析指令的第二步: 去掉以x-和data-开头的前缀(例如 x- x: x_ data- data: data_ 忽略大小写)
 
 
再继续看camelCase()函数
var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
var MOZ_HACK_REGEXP = /^moz([A-Z])/;
var jqLiteMinErr = minErr('jqLite');

/**
 * Converts snake_case to camelCase.
 * Also there is special case for Moz prefix starting with upper case letter.
 * @param name Name to normalize
 */
function camelCase(name) {
  return name.
    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
      return offset ? letter.toUpperCase() : letter;
    }).
    replace(MOZ_HACK_REGEXP, 'Moz$1');
}
使用了两个replace替换字符,第二个replace不用管,重点看第一个replace,它是什么作用?
 
把它拿出来看看
var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
function camelCase(name) {
  return name.
    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
      console.log("_:" + _)
      console.log("separator:" + separator)
      console.log("letter:" + letter)
      return offset ? letter.toUpperCase() : letter;
    }).
}
console.log("----my-directive")
console.log(camelCase(my-directive));

console.log("----mydirective")
console.log(camelCase(my-directive));

console.log("----mydirectiveworld")
console.log(camelCase(my-directive));
/* 
输出内容
----my-directive
_:-d
separator:-d
letter:d
myDirective

----mydirective
mydirective

----mydirectiveworld
mydirectiveworld
*/
可以看到第一个replace作用是生成驼峰指令名
所以解析指令的第三步:根据分割符(: - _)标记,将字符转换为驼峰形式
 
关于replace函数的说明,可以看看这篇文章
http://yongqing.is-programmer.com/posts/56305.html
 
 
更多指令名与指令对应的示例
以分割符"-"为例
mymenu --> mymenu   正确
mymenu --> myMenu   错误
mymenu --> my-Menu  错误

myMenu --> my-Menu  正确
myMenu --> myMenu   错误
myMenu --> mymenu   错误

MyMenu --> x-MyMenu 正确
MyMenu --> MyMenu   错误
MyMenu --> mymenu   错误

myProductsMenu --> my-Products-Menu   正确
myProductsMenu --> myProductsMenu     错误
myProductsMenu --> my-ProductsMenu    错误

总结

指令的匹配过程
  1. 将指令名转换为小写.
  2. 去掉以x-和data-开头的前缀(例如 x- x: x_ data- data: data_ 忽略大小写)
  3. 根据分割符(: - _),转换为驼峰形式
其实只要注意一点: 匹配过程以定义时的指令名为准,分割符是用来标识驼峰的(angular没有能力识别单词,分割符的一个作用是标识驼峰).
 

Tags: angularjs;指令
评论(0) 阅读(1489)

javascript replace函数

2014年8月11日 20:39

定义
replace()函数用于替换字符串.
 
语法
stringObject.replace(regexp/substr, newSubStr/function)
参数
regexp/substr       正则表达式/字符串
newSubStr/function  替换文本/生成替换文本的函数
 
示例
var str = "Visit Microsoft!";
var res = str.replace("Microsoft", "W3Schools");
 
替换字符
假如替换字符newSubStr中包含$符号,它表示什么?
$1、 $2、 ...、$99 与 regexp 中的第1到第99个子表达式相匹配的文本
$& 与 regexp 相匹配的子串
$` 位于匹配子串左侧的文本
$' 位于匹配子串右侧的文本
$$ 直接量符号。
 
上面$1、$2...中提到的子表达式是什么意思?正则表达式中用小括号包裹起来的表达式.
例如:
/a/   无子表达式
/[a]/ 无子表达式
/(a)/ 有子表达式(a)
/(a), (b)/ 有子表达式(a)、(b)
 
示例
name = "Doe, John";
name.replace(/(\w+)\s*, \s*(\w+)/, "$2 $1");
//输出"John Doe"
 
替换函数
替换函数说明

function(match, p1, p2,..., offset, string)
match      匹配到的字符串
p1, p2...  匹配到的子表达式
offset     匹配到字符串的位置
string     整个字符串
 
示例
var name = "ace:mm-Abc".replace(/([\:\-\_]+(.))/, function(match, p1, p2, offset, total){
        console.log("match:" + _);
        console.log("p1:" + separator);
        console.log("p2:" + letter);
        console.log("offset:" + offset);
        console.log("total:"+ total)
        return offset ? p2.toUpperCase() : p2;
})
console.log(name)
/*输出
substr::m test.html:43
p1::m
p2:m
offset:3
total:ace:mm-Abc
aceMm-Abc 
*/
上面正则表达式中有两个子表达式
p1是子表达式([\:\-\_]+(.))匹配到的内容":m"
p2是子表单是(.)匹配到的内容"m"
 

Tags: js
评论(0) 阅读(1238)

理解指令的restrict属性

2014年7月30日 01:26

restrcit属性说明
restrict: EACM中的任意一个之母。它是用来限制指令的声明格式的。
E - 元素名称:<my-directive></my-directive>
A - 属性: <div my-directive="exp"> </div>
C - 类名:<div class="my-directive: exp;"></div>
M - 注释: <!-- directive: my-directive exp -->
 
它做了什么
示例
<html ng-app='app'>
<body>
    <hello> </hello>
    <div hello> </div>
    <div class="hello"> </div>
    <!-- directive: hello -->
</body>

<script src="bower_components/angular/angular.js"></script>
<script>
var appModule = angular.module('app', []);
appModule.directive('hello', function() {
    return {
        restrict: 'AEC',
        template: '<h3>Hi there</h3>',
        replace: true
    };
});
</script>
</html>
 
运行结果
<h3>Hi there</h3>
<h3 hello>Hi there</h3>
<h3 class="hello">Hi there</h3>
<h3>Hi there</h3>
可以看到几种方式,做的事情一样,只有部分区别. 这些区别有什么作用,用在什么场合?
 
使用场合
restrict=E时,浏览器无法识别指令的声明元素,那么可以知道这个指令一定是起替换作用,也就是说template一定有值.
restrict=A时,指令是以元素属性形式存在的,这个指令的作用则可以不是替换作用. 那么它可以做什么?以link方式操作dom.
比如为元素聚焦
<input type="input" focus/>

appModule.directive('focus', function() {
    return {
        restrict: 'A',
        link:function(scope, elem, attrs){
            $(elem).focus();
        }
    };
});
restrict=C,则是在绑定指令的同时,指定它的css样式,让指令与样式同步.
restrict=M,则在一些场合非常有用,方便在注释与代码之间切换.
 
 

Tags: angularjs
评论(4) 阅读(2372)

web路径解析三种方式

2014年7月10日 17:12

路径解析经过三个阶段:
文件路径
静态文件与网站目录结构一致,动态文件也是根文件路径执行脚本,比如/index.asp
MVC
java中的struts就是典型的MVC模式,将url映射到控制器,调用服务操作数据,再返回结果.
操作的行为主要是用post和get请取方法.
restful
目前最流程的就是restful,restful全称是Representational State Transfer表现层状态转换
它将服务器端提供的内容实体看作资源,并表现在url上, 对资源的操作体现在http方法上, 资源的类型体现在请求字段Accept和响应字段Content-Type上
 
在MVC中,主要使用post和get请取方法,增删操作表现在url上
POST /user/add?username=jacksontian
GET  /user/remove?username=jacksontian
POST /user/update?username=jacksontian
GET  /user/get?username=jacksontian
在restful中
POST   /user/jacksontian   增加
DELETE /user/jacksontian   删除
PUT    /user/jacksontian   更新
GET    /user/jacksontian   查询
 
 
 

Tags: restful;nodejs
评论(0) 阅读(1173)