├── QiniuInputVueAsset.php ├── composer.json ├── QiniuInputAsset.php ├── assets ├── css │ ├── qiniu-input.min.css │ ├── qiniu-input.css │ └── qiniu-input.css.map └── js │ ├── qiniu-input.min.js │ ├── qiniu-input.js.map │ └── qiniu-input.js ├── Auth.php ├── README.md └── QiniuFileInput.php /QiniuInputVueAsset.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | class QiniuInputVueAsset extends AssetBundle 8 | { 9 | public $sourcePath = '@bower/vue/dist'; 10 | 11 | public $js = [ 12 | 'vue.js', 13 | ]; 14 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zh/yii2-qiniu-images", 3 | "description": "一款直传七牛的yii2图片widget", 4 | "type": "yii2-extension", 5 | "keywords": ["yii2","images","七牛","多图"], 6 | "license": "BSD-3-Clause", 7 | "authors": [ 8 | { 9 | "name": "yanghu", 10 | "email": "127802495@qq.com" 11 | } 12 | ], 13 | "require": { 14 | "yiisoft/yii2": "*", 15 | "bower-asset/vue": "~2.4" 16 | }, 17 | "autoload": { 18 | "psr-4": { 19 | "zh\\qiniu\\": "" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /QiniuInputAsset.php: -------------------------------------------------------------------------------- 1 | sourcePath = __DIR__ . '/assets'; 13 | $this->js = YII_DEBUG ? ['js/qiniu-input.js'] : ['js/qiniu-input.min.js']; 14 | $this->css = YII_DEBUG ? ['css/qiniu-input.css'] : ['css/qiniu-input.min.css']; 15 | parent::init(); 16 | } 17 | 18 | /** 19 | * @inheritdoc 20 | */ 21 | public $depends = [ 22 | 'yii\bootstrap\BootstrapAsset', 23 | ]; 24 | 25 | } -------------------------------------------------------------------------------- /assets/css/qiniu-input.min.css: -------------------------------------------------------------------------------- 1 | .zh-images{border:1px dashed #999;border-radius:10px;margin-bottom:10px;min-height:100px;padding:10px}.zh-images .err-box{height:50px;color:#a94442;background-color:#f2dede;line-height:50px;border-radius:5px;padding-left:10px}.zh-images .err-box .close{line-height:50px;margin-right:5px;color:#fff;opacity:.8;float:right}.zh-images .zh-images-items{display:inline-block;overflow:hidden;-webkit-box-shadow:1px 1px 5px 0 #a2958a;box-shadow:1px 1px 5px 0 #a2958a;padding:6px;margin:10px;background-color:#fff;cursor:pointer;position:relative}.zh-images .zh-images-items img{max-height:150px}.zh-images .zh-images-items .zh-cover{position:absolute;width:100%;height:30px;line-height:30px;text-align:center;background-color:rgba(0,0,0,.6);left:0;bottom:0;display:none;-webkit-transition:opacity 6s linear 0s;transition:opacity 6s linear 0s}.zh-images .zh-images-items .zh-cover i{color:#fff;font-size:14px;line-height:30px}.zh-images .zh-images-items:hover .zh-cover{display:block;color:#fff}.file-btn{position:relative;z-index:2}.file-btn input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;text-align:right;opacity:0;background:0 0;display:block;cursor:pointer;z-index:1} -------------------------------------------------------------------------------- /assets/css/qiniu-input.css: -------------------------------------------------------------------------------- 1 | .zh-images { 2 | border: 1px dashed #999; 3 | border-radius: 10px; 4 | margin-bottom: 10px; 5 | min-height: 100px; 6 | padding: 10px; 7 | } 8 | 9 | .zh-images .err-box { 10 | height: 50px; 11 | color: #a94442; 12 | background-color: #f2dede; 13 | line-height: 50px; 14 | border-radius: 5px; 15 | padding-left: 10px; 16 | } 17 | 18 | .zh-images .err-box .close { 19 | line-height: 50px; 20 | margin-right: 5px; 21 | color: #fff; 22 | opacity: .8; 23 | float: right; 24 | } 25 | 26 | .zh-images .zh-images-items { 27 | display: inline-block; 28 | overflow: hidden; 29 | -webkit-box-shadow: 1px 1px 5px 0 #a2958a; 30 | box-shadow: 1px 1px 5px 0 #a2958a; 31 | padding: 6px; 32 | margin: 10px; 33 | background-color: #fff; 34 | cursor: pointer; 35 | position: relative; 36 | } 37 | 38 | .zh-images .zh-images-items img { 39 | max-height: 150px; 40 | } 41 | 42 | .zh-images .zh-images-items .zh-cover { 43 | position: absolute; 44 | width: 100%; 45 | height: 30px; 46 | line-height: 30px; 47 | text-align: center; 48 | background-color: rgba(0, 0, 0, 0.6); 49 | left: 0; 50 | bottom: 0; 51 | display: none; 52 | -webkit-transition: opacity 6s linear 0s; 53 | transition: opacity 6s linear 0s; 54 | } 55 | 56 | .zh-images .zh-images-items .zh-cover i { 57 | color: #fff; 58 | font-size: 14px; 59 | line-height: 30px; 60 | } 61 | 62 | .zh-images .zh-images-items:hover .zh-cover { 63 | display: block; 64 | color: #ffffff; 65 | } 66 | 67 | .file-btn { 68 | position: relative; 69 | z-index: 2; 70 | } 71 | 72 | .file-btn input[type="file"] { 73 | position: absolute; 74 | top: 0; 75 | right: 0; 76 | min-width: 100%; 77 | min-height: 100%; 78 | text-align: right; 79 | opacity: 0; 80 | background: none; 81 | display: block; 82 | cursor: pointer; 83 | z-index: 1; 84 | } 85 | 86 | /*# sourceMappingURL=qiniu-input.css.map */ 87 | -------------------------------------------------------------------------------- /Auth.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | class Auth 10 | { 11 | private $accessKey; 12 | private $secretKey; 13 | 14 | 15 | // 上传策略 16 | public $policy = []; 17 | 18 | // 上传空间 19 | public $scope; 20 | 21 | // 凭证过期时间 22 | public $expires = 3600; 23 | 24 | public function __construct($accessKey, $secretKey, $scope) 25 | { 26 | $this->accessKey = $accessKey; 27 | $this->secretKey = $secretKey; 28 | $this->scope = $scope; 29 | } 30 | 31 | /** 32 | * 获取上传策略凭证json字符串 33 | * @return string 34 | */ 35 | public function getPolicyJson() 36 | { 37 | return Json::encode(ArrayHelper::merge([ 38 | 'scope' => $this->scope, 39 | 'deadline' => time() + $this->expires 40 | ], $this->policy)); 41 | } 42 | 43 | /** 44 | * 获取上传凭证 45 | * @return string 46 | */ 47 | public function uploadToken() 48 | { 49 | $data = $this->_base64_urlSafeEncode($this->getPolicyJson()); 50 | return $this->accessKey . ':' . $this->sign($data) . ':' . $data; 51 | } 52 | 53 | /** 54 | * 签名算法 55 | * @param string $data 56 | * @return string 57 | */ 58 | public function sign($data) 59 | { 60 | return $this->_base64_urlSafeEncode(hash_hmac('sha1', $data, $this->secretKey, true)); 61 | } 62 | 63 | /** 64 | * 对提供的数据进行urlsafe的base64编码。 65 | * @param string $data 待编码的数据,一般为字符串 66 | * @return string 编码后的字符串 67 | * @link http://developer.qiniu.com/docs/v6/api/overview/appendix.html#urlsafe-base64 68 | */ 69 | private function _base64_urlSafeEncode($data) 70 | { 71 | $find = array('+', '/'); 72 | $replace = array('-', '_'); 73 | return str_replace($find, $replace, base64_encode($data)); 74 | } 75 | } -------------------------------------------------------------------------------- /assets/css/qiniu-input.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["qiniu-input.scss"],"names":[],"mappings":"AAAA;EACE,wBAAuB;EACvB,oBAAmB;EACnB,oBAAmB;EACnB,kBAAiB;EACjB,cAAa;CAkDd;;AAvDD;EAOI,aAAY;EACZ,eAAc;EACd,0BAAyB;EACzB,kBAAiB;EACjB,mBAAkB;EAClB,mBAAkB;CAQnB;;AApBH;EAcM,kBAAiB;EACjB,kBAAiB;EACjB,YAAW;EACX,YAAW;EACX,aAAY;CACb;;AAnBL;EAsBI,sBAAqB;EACrB,iBAAgB;EAChB,0CAAiC;UAAjC,kCAAiC;EACjC,aAAY;EACZ,aAAY;EACZ,uBAAsB;EACtB,gBAAe;EACf,mBAAkB;CAyBnB;;AAtDH;EA+BM,kBAAiB;CAClB;;AAhCL;EAkCM,mBAAkB;EAClB,YAAW;EACX,aAAY;EACZ,kBAAiB;EACjB,mBAAkB;EAClB,qCAAiC;EACjC,QAAO;EACP,UAAS;EACT,cAAa;EACb,yCAAgC;EAAhC,iCAAgC;CAMjC;;AAjDL;EA6CQ,YAAW;EACX,gBAAe;EACf,kBAAiB;CAClB;;AAhDP;EAmDM,eAAc;EACd,eAAc;CACf;;AAIL;EACE,mBAAkB;EAClB,WAAS;CAeV;;AAjBD;EAII,mBAAkB;EAClB,OAAM;EACN,SAAQ;EACR,gBAAe;EACf,iBAAgB;EAChB,kBAAiB;EACjB,WAAU;EACV,iBAAgB;EAChB,eAAc;EACd,gBAAe;EACf,WAAU;CAEX","file":"qiniu-input.css","sourcesContent":[".zh-images{\r\n border: 1px dashed #999;\r\n border-radius: 10px;\r\n margin-bottom: 10px;\r\n min-height: 100px;\r\n padding: 10px;\r\n .err-box{\r\n height: 50px;\r\n color: #a94442;\r\n background-color: #f2dede;\r\n line-height: 50px;\r\n border-radius: 5px;\r\n padding-left: 10px;\r\n .close {\r\n line-height: 50px;\r\n margin-right: 5px;\r\n color: #fff;\r\n opacity: .8;\r\n float: right;\r\n }\r\n }\r\n .zh-images-items{\r\n display: inline-block;\r\n overflow: hidden;\r\n box-shadow: 1px 1px 5px 0 #a2958a;\r\n padding: 6px;\r\n margin: 10px;\r\n background-color: #fff;\r\n cursor: pointer;\r\n position: relative;\r\n img{\r\n max-height: 150px;\r\n }\r\n .zh-cover{\r\n position: absolute;\r\n width: 100%;\r\n height: 30px;\r\n line-height: 30px;\r\n text-align: center;\r\n background-color: rgba(0,0,0,0.6);\r\n left: 0;\r\n bottom: 0;\r\n display: none;\r\n transition: opacity 6s linear 0s;\r\n i{\r\n color: #fff;\r\n font-size: 14px;\r\n line-height: 30px;\r\n }\r\n }\r\n &:hover .zh-cover{\r\n display: block;\r\n color: #ffffff;\r\n }\r\n }\r\n}\r\n\r\n.file-btn{\r\n position: relative;\r\n z-index:2;\r\n input[type=\"file\"]{\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n min-width: 100%;\r\n min-height: 100%;\r\n text-align: right;\r\n opacity: 0;\r\n background: none;\r\n display: block;\r\n cursor: pointer;\r\n z-index: 1;\r\n\r\n }\r\n}"]} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | yii2 七牛多图直传 2 | =========== 3 | 一款直传七牛的yii2图片widget 浏览器直传(没试过IE) 没有做分片上传 4 | 5 | Installation 6 | ------------ 7 | 8 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 9 | 10 | Either run 11 | 12 | ``` 13 | php composer.phar require --prefer-dist zh/yii2-qiniu-images "dev-master" 14 | ``` 15 | 16 | or add 17 | 18 | ``` 19 | "zh/yii2-qiniu-images": "dev-master" 20 | ``` 21 | 22 | to the require section of your `composer.json` file. 23 | 24 | 25 | Usage 26 | ----- 27 | 28 | Once the extension is installed, simply use it in your code by : 29 | 30 | ```php 31 | field($model, 'images')->widget(QiniuFileInput::className(),[ 32 | //'options' => [ 33 | // 'class' => 'btn-danger'//按钮class 34 | //], 35 | //'uploadUrl' => 'http://up-z2.qiniu.com',文件上传地址 不同地区的空间上传地址不一样 参见官方文档 36 | 'qlConfig' => [ 37 | 'accessKey' => '你的七牛key', 38 |            'secretKey' => '你的七牛secretKey', 39 |            'scope'=>'你的空间名', 40 |            'cdnUrl' => 'http://URL',//外链域名 41 | ], 42 | 'clientOptions' => [ 43 | 'max' => 5,//最多允许上传图片个数 默认为3 44 | //'size' => 204800,//每张图片大小 45 | //'btnName' => 'upload',//上传按钮名字 46 | //'accept' => 'image/jpeg,image/gif,image/png'//上传允许类型 47 | ], 48 | //'pluginEvents' => [ 49 | // 'delete' => 'function(item){console.log(item)}', 50 | // 'success' => 'function(res){console.log(res)}' 51 | //] 52 | ]) ?> 53 | 54 | ``` 55 | 56 | 57 | 流程 : 58 | 59 | 图片成功上传到七牛后,以数组的形式保存资源地址(外链域名+资源名)到当前模型的属性,例如: 60 | 61 | 当前goods模型 添加一个成员属性 images 只支持required规则 62 | 63 | ----- 64 | model 65 | 66 | ```php 67 | class Goods extends \yii\db\ActiveRecord 68 | { 69 | public $images; 70 | /** 71 | * @inheritdoc 72 | */ 73 | public function rules() 74 | { 75 | return [ 76 | [['images'], 'required'] 77 | ]; 78 | } 79 | } 80 | ``` 81 | ----- 82 | 83 | 当提交form后端将收到如下类型的数据 84 | ```php 85 | [Goods] => Array 86 | ( 87 | [images] => Array 88 | ( 89 | [0] => http://ouv520g7c.bkt.clouddn.com/2017/9/er14pygpvq.jpg 90 | [1] => http://ouv520g7c.bkt.clouddn.com/2017/9/r5c0eidcx8.jpg 91 | ) 92 | ) 93 | ``` 94 | ----- 95 | 96 | 更新如何显示已有数据 97 | 98 | ```php 99 | $model->images = [ 100 | 'http://ouv520g7c.bkt.clouddn.com/2017/9/er14pygpvq.jpg', 101 | 'http://ouv520g7c.bkt.clouddn.com/2017/9/r5c0eidcx8.jpg' 102 | ] 103 | ``` 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /assets/js/qiniu-input.min.js: -------------------------------------------------------------------------------- 1 | "use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"";this.errMessage=e},upload:function(t){var n=this;if(t.target.files.length+this.imageList.length>this.config.max)this.setErrMessage("图片超出最大允许上传个数:"+this.config.max+",请删除一些图片!");else{var i="",s=!0,r=!1,a=void 0;try{for(var o,c=t.target.files[Symbol.iterator]();!(s=(o=c.next()).done);s=!0){var u=o.value;if(u.size>this.config.size)i+=u.name+" ";else{var f=new FormData;f.append("file",u),f.append("token",this.config.token),f.append("key",e.getFileKey(u)),e.requestQiniu({url:this.config.url,data:f,error:function(e){n.setErrMessage(e.message)},success:function(e){"function"==typeof n.config.onsuccess&&n.config.onsuccess(e),n.imageList.push({name:n.config.cdnUrl+"/"+e.key})},progress:function(e){100===e&&setTimeout(function(){n.progress=0},500),n.progress=e}})}}}catch(e){r=!0,a=e}finally{try{!s&&c.return&&c.return()}finally{if(r)throw a}}""!==i&&this.setErrMessage(i+"超出最大限制"+parseInt(this.config.size/1024)+"KB,已忽略上传")}},deleteImg:function(e){"function"==typeof this.config.ondelete&&this.config.ondelete(this.imageList[e]),this.imageList.splice(e,1)}}})}}],[{key:"randomChar",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:5,t="0123456789qwertyuioplkjhgfdsazxcvbnm",n="",i=0;i1&&void 0!==arguments[1]?arguments[1]:10,i=new Date;return i.getFullYear()+"/"+(i.getMonth()+1)+"/"+e.randomChar(n)+"."+t.name.split(".").splice(-1)}}]),e}(); -------------------------------------------------------------------------------- /QiniuFileInput.php: -------------------------------------------------------------------------------- 1 | 3, 50 | 'size' => 204800, 51 | 'accept' => 'image/jpeg,image/gif,image/png', 52 | ]; 53 | 54 | /** 55 | * {@inheritDoc} 56 | * @see \yii\widgets\InputWidget::init() 57 | */ 58 | public function init() 59 | { 60 | if ($this->qlConfig === null) { 61 | throw new InvalidConfigException('QiniuFileInput::qlConfig must be set'); 62 | } 63 | parent::init(); 64 | $this->registerAssetBundle(); 65 | $this->registerPlugin(); 66 | } 67 | 68 | /** 69 | * {@inheritDoc} 70 | * @see \yii\base\Widget::run() 71 | */ 72 | public function run() 73 | { 74 | echo $this->getHtml(); 75 | } 76 | 77 | /** 78 | * @throws InvalidConfigException 79 | * @return string 80 | */ 81 | protected function getToken() 82 | { 83 | try { 84 | $auth = new Auth($this->qlConfig['accessKey'], $this->qlConfig['secretKey'], $this->qlConfig['scope']); 85 | $this->cdnUrl = $this->qlConfig['cdnUrl']; 86 | }catch (Exception $e) { 87 | throw new InvalidConfigException('qlConfig::'.$e->getMessage()); 88 | } 89 | if (!empty($this->policy)) { 90 | $auth->policy = $this->policy; 91 | } 92 | return $auth->uploadToken(); 93 | } 94 | 95 | /** 96 | * @return string 97 | */ 98 | protected function getElName() 99 | { 100 | return $this->model->formName() .'-'. $this->attribute; 101 | } 102 | 103 | /** 104 | * @return string 105 | */ 106 | protected function getHtml() 107 | { 108 | if ($this->hasModel()) { 109 | $el = $this->getElName(); 110 | $id = html::getInputId($this->model, $this->attribute); 111 | $name = Html::getInputName($this->model, $this->attribute); 112 | $butName = isset($this->clientOptions['btnName']) ? $this->clientOptions['btnName'] : '请选择'; 113 | $butClass = isset($this->options['class']) ?$this->options['class'] : 'btn-success'; 114 | $html = << 116 |
117 |
118 | × 119 |
120 |
121 |
122 |
123 |
124 |
125 |
{{progress}}%
126 |
127 |
128 | $butName 129 | 132 | 135 | 136 |
137 | 138 | HTML; 139 | return $html; 140 | } 141 | } 142 | 143 | /** 144 | * Registers js and css 145 | */ 146 | public function registerPlugin() 147 | { 148 | $config = $this->mergeConfig(); 149 | if (!empty($this->pluginEvents)) { 150 | foreach ($this->pluginEvents as $event => $handler) { 151 | $function = $handler instanceof JsExpression ? $handler : new JsExpression($handler); 152 | $config['on'.$event] = $function; 153 | } 154 | } 155 | $js = Json::encode($config); 156 | $this->getView()->registerJs('new ' . self::JS_CLASS_NAME ."($js)",View::POS_END); 157 | } 158 | 159 | 160 | /** 161 | * Registers the asset bundle and locale 162 | */ 163 | public function registerAssetBundle() 164 | { 165 | QiniuInputVueAsset::register($this->getView()); 166 | QiniuInputAsset::register($this->getView()); 167 | } 168 | 169 | public function mergeConfig() 170 | { 171 | $config = ArrayHelper::merge($this->defaultClientOptions,$this->clientOptions); 172 | $config['url'] = $this->uploadUrl; 173 | $config['token'] = $this->getToken(); 174 | $config['cdnUrl'] = $this->cdnUrl; 175 | $config['el'] = '#'.$this->getElName(); 176 | if (($value = Html::getAttributeValue($this->model, $this->attribute)) != null) { 177 | $config['imageList'] = (array) $value; 178 | } 179 | return $config; 180 | } 181 | 182 | } -------------------------------------------------------------------------------- /assets/js/qiniu-input.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["qiniu-input.js"],"names":["QiniuFileInput","config","defaultConfig","max","accept","size","Object","assign","init","Vue","el","data","progress","errMessage","imageList","mounted","item","push","name","methods","setErrMessage","str","upload","event","totalLength","target","files","length","bigImages","FormData","append","token","getFileKey","requestQiniu","url","error","r","message","success","res","onsuccess","cdnUrl","key","p","setTimeout","parseInt","deleteImg","index","ondelete","splice","len","x","tmp","i","charAt","Math","ceil","random","obj","xhr","XMLHttpRequest","open","addEventListener","evt","floor","loaded","total","onreadystatechange","response","readyState","status","responseText","JSON","parse","send","oDate","Date","getFullYear","getMonth","randomChar","split"],"mappings":"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","file":"qiniu-input.js","sourcesContent":["class QiniuFileInput{\r\n\r\n constructor(config)\r\n {\r\n let defaultConfig = {\r\n max : 3,\r\n accept: \"image/jpeg,image/gif,image/png\",\r\n size:204800\r\n };\r\n this.config = Object.assign(defaultConfig,config);\r\n this.init();\r\n }\r\n static randomChar(len = 5)\r\n {\r\n let x= \"0123456789qwertyuioplkjhgfdsazxcvbnm\";\r\n let tmp=\"\";\r\n for(let i=0; i< len; i++) {\r\n tmp += x.charAt(Math.ceil(Math.random() * 100000000) % x.length);\r\n }\r\n return tmp;\r\n }\r\n static requestQiniu(obj)\r\n {\r\n let xhr = new XMLHttpRequest();\r\n xhr.open(\"POST\", obj.url, true);\r\n xhr.upload.addEventListener(\"progress\", (evt)=>{\r\n let p = Math.floor(evt.loaded / evt.total * 100);\r\n typeof obj.progress === \"function\" && obj.progress(p);\r\n });\r\n xhr.onreadystatechange = (response)=>{\r\n if (xhr.readyState === 4) {\r\n if (xhr.status === 200 && xhr.responseText !== '') {\r\n let r = JSON.parse(xhr.responseText);\r\n typeof obj.success === \"function\" && obj.success(r);\r\n }\r\n if (xhr.status !== 200) {\r\n typeof obj.error === \"function\" && obj.error({\r\n message: JSON.parse(xhr.responseText).error,\r\n status: xhr.status\r\n });\r\n }\r\n }\r\n\r\n };\r\n xhr.send(obj.data);\r\n }\r\n static getFileKey(item,len=10)\r\n {\r\n let oDate = new Date();\r\n return `${oDate.getFullYear()}/${oDate.getMonth()+1}/${QiniuFileInput.randomChar(len)}.${item.name.split('.').splice(-1)}`;\r\n }\r\n init()\r\n {\r\n new Vue({\r\n el : this.config.el,\r\n data : {\r\n progress:0,\r\n errMessage : '',\r\n config : this.config,\r\n imageList:[]\r\n },\r\n mounted(){\r\n if (this.config.imageList != null) {\r\n for (let item of this.config.imageList) {\r\n this.imageList.push({\r\n name:item\r\n });\r\n }\r\n }\r\n },\r\n methods:{\r\n setErrMessage(str=''){\r\n this.errMessage = str;\r\n },\r\n upload(event)\r\n {\r\n let totalLength = event.target.files.length + this.imageList.length;\r\n if (totalLength > this.config.max){\r\n this.setErrMessage(`图片超出最大允许上传个数:${this.config.max},请删除一些图片!`);\r\n return;\r\n }\r\n let bigImages = '';\r\n for (let item of event.target.files) {\r\n if (item.size > this.config.size){\r\n bigImages += `${item.name} `;\r\n continue;\r\n }\r\n let data = new FormData();\r\n data.append(\"file\", item);\r\n data.append(\"token\", this.config.token);\r\n data.append(\"key\",QiniuFileInput.getFileKey(item));\r\n QiniuFileInput.requestQiniu({\r\n url:this.config.url,\r\n data : data,\r\n error:(r)=>{\r\n this.setErrMessage(r.message);\r\n },\r\n success:(res)=>{\r\n typeof this.config.onsuccess === \"function\" && this.config.onsuccess(res);\r\n this.imageList.push({\r\n name:`${this.config.cdnUrl}/${res.key}`\r\n });\r\n },\r\n progress:(p)=>{\r\n if ( p === 100 ) {\r\n setTimeout(()=>{\r\n this.progress = 0;\r\n },500)\r\n }\r\n this.progress = p;\r\n }\r\n });\r\n }\r\n if (bigImages !== ''){\r\n this.setErrMessage(`${bigImages}超出最大限制${parseInt(this.config.size/1024)}KB,已忽略上传`)\r\n }\r\n },\r\n deleteImg(index){\r\n typeof this.config.ondelete === \"function\" && this.config.ondelete(this.imageList[index]);\r\n this.imageList.splice(index,1);\r\n }\r\n }\r\n });\r\n }\r\n}"]} -------------------------------------------------------------------------------- /assets/js/qiniu-input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 4 | 5 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 6 | 7 | var QiniuFileInput = function () { 8 | function QiniuFileInput(config) { 9 | _classCallCheck(this, QiniuFileInput); 10 | 11 | var defaultConfig = { 12 | max: 3, 13 | accept: "image/jpeg,image/gif,image/png", 14 | size: 204800 15 | }; 16 | this.config = Object.assign(defaultConfig, config); 17 | this.init(); 18 | } 19 | 20 | _createClass(QiniuFileInput, [{ 21 | key: "init", 22 | value: function init() { 23 | new Vue({ 24 | el: this.config.el, 25 | data: { 26 | progress: 0, 27 | errMessage: '', 28 | config: this.config, 29 | imageList: [] 30 | }, 31 | mounted: function mounted() { 32 | if (this.config.imageList != null) { 33 | var _iteratorNormalCompletion = true; 34 | var _didIteratorError = false; 35 | var _iteratorError = undefined; 36 | 37 | try { 38 | for (var _iterator = this.config.imageList[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 39 | var item = _step.value; 40 | 41 | this.imageList.push({ 42 | name: item 43 | }); 44 | } 45 | } catch (err) { 46 | _didIteratorError = true; 47 | _iteratorError = err; 48 | } finally { 49 | try { 50 | if (!_iteratorNormalCompletion && _iterator.return) { 51 | _iterator.return(); 52 | } 53 | } finally { 54 | if (_didIteratorError) { 55 | throw _iteratorError; 56 | } 57 | } 58 | } 59 | } 60 | }, 61 | 62 | methods: { 63 | setErrMessage: function setErrMessage() { 64 | var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; 65 | 66 | this.errMessage = str; 67 | }, 68 | upload: function upload(event) { 69 | var _this = this; 70 | 71 | var totalLength = event.target.files.length + this.imageList.length; 72 | if (totalLength > this.config.max) { 73 | this.setErrMessage("\u56FE\u7247\u8D85\u51FA\u6700\u5927\u5141\u8BB8\u4E0A\u4F20\u4E2A\u6570:" + this.config.max + ",\u8BF7\u5220\u9664\u4E00\u4E9B\u56FE\u7247!"); 74 | return; 75 | } 76 | var bigImages = ''; 77 | var _iteratorNormalCompletion2 = true; 78 | var _didIteratorError2 = false; 79 | var _iteratorError2 = undefined; 80 | 81 | try { 82 | for (var _iterator2 = event.target.files[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { 83 | var item = _step2.value; 84 | 85 | if (item.size > this.config.size) { 86 | bigImages += item.name + " "; 87 | continue; 88 | } 89 | var data = new FormData(); 90 | data.append("file", item); 91 | data.append("token", this.config.token); 92 | data.append("key", QiniuFileInput.getFileKey(item)); 93 | QiniuFileInput.requestQiniu({ 94 | url: this.config.url, 95 | data: data, 96 | error: function error(r) { 97 | _this.setErrMessage(r.message); 98 | }, 99 | success: function success(res) { 100 | typeof _this.config.onsuccess === "function" && _this.config.onsuccess(res); 101 | _this.imageList.push({ 102 | name: _this.config.cdnUrl + "/" + res.key 103 | }); 104 | }, 105 | progress: function progress(p) { 106 | if (p === 100) { 107 | setTimeout(function () { 108 | _this.progress = 0; 109 | }, 500); 110 | } 111 | _this.progress = p; 112 | } 113 | }); 114 | } 115 | } catch (err) { 116 | _didIteratorError2 = true; 117 | _iteratorError2 = err; 118 | } finally { 119 | try { 120 | if (!_iteratorNormalCompletion2 && _iterator2.return) { 121 | _iterator2.return(); 122 | } 123 | } finally { 124 | if (_didIteratorError2) { 125 | throw _iteratorError2; 126 | } 127 | } 128 | } 129 | 130 | if (bigImages !== '') { 131 | this.setErrMessage(bigImages + "\u8D85\u51FA\u6700\u5927\u9650\u5236" + parseInt(this.config.size / 1024) + "KB,\u5DF2\u5FFD\u7565\u4E0A\u4F20"); 132 | } 133 | }, 134 | deleteImg: function deleteImg(index) { 135 | typeof this.config.ondelete === "function" && this.config.ondelete(this.imageList[index]); 136 | this.imageList.splice(index, 1); 137 | } 138 | } 139 | }); 140 | } 141 | }], [{ 142 | key: "randomChar", 143 | value: function randomChar() { 144 | var len = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 5; 145 | 146 | var x = "0123456789qwertyuioplkjhgfdsazxcvbnm"; 147 | var tmp = ""; 148 | for (var i = 0; i < len; i++) { 149 | tmp += x.charAt(Math.ceil(Math.random() * 100000000) % x.length); 150 | } 151 | return tmp; 152 | } 153 | }, { 154 | key: "requestQiniu", 155 | value: function requestQiniu(obj) { 156 | var xhr = new XMLHttpRequest(); 157 | xhr.open("POST", obj.url, true); 158 | xhr.upload.addEventListener("progress", function (evt) { 159 | var p = Math.floor(evt.loaded / evt.total * 100); 160 | typeof obj.progress === "function" && obj.progress(p); 161 | }); 162 | xhr.onreadystatechange = function (response) { 163 | if (xhr.readyState === 4) { 164 | if (xhr.status === 200 && xhr.responseText !== '') { 165 | var r = JSON.parse(xhr.responseText); 166 | typeof obj.success === "function" && obj.success(r); 167 | } 168 | if (xhr.status !== 200) { 169 | typeof obj.error === "function" && obj.error({ 170 | message: JSON.parse(xhr.responseText).error, 171 | status: xhr.status 172 | }); 173 | } 174 | } 175 | }; 176 | xhr.send(obj.data); 177 | } 178 | }, { 179 | key: "getFileKey", 180 | value: function getFileKey(item) { 181 | var len = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10; 182 | 183 | var oDate = new Date(); 184 | return oDate.getFullYear() + "/" + (oDate.getMonth() + 1) + "/" + QiniuFileInput.randomChar(len) + "." + item.name.split('.').splice(-1); 185 | } 186 | }]); 187 | 188 | return QiniuFileInput; 189 | }(); 190 | //# sourceMappingURL=qiniu-input.js.map 191 | --------------------------------------------------------------------------------