
实用的一个树形算法

前端开发综合文章
使用了 el-upload 的插件,但是一直都是报 404 ,在这个过程中,请注意您使用的 request header 中的 content-type 不同的类型需要的 NodeJS 的 request 解析方式不一样。在 Node 服务端接到用户的数据之后,就需要使用 fs 模块把图片解析成可以保存的文件流,存入磁盘中或者调用后台接口保存。调试了一个小时之后成功通过。把代码留下来,方便日后进行查询。
Vue 层
-------------------------------------
<el-upload class="avatar-uploader" accept="image/jpeg" action="agency/uploadPicForAgency" :data="{agencyId:'1',picFlag:'1'}" :multiple="false" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeBackgroundAvatarUpload">
<img v-if="backgroundUrl" :src="backgroundUrl" width="100%" height="100%" class="avatar">
<i v-else="" class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
express 层
-----------------------------------
/**
* @api {post} agency/uploadPicForAgency 代理商图片上传接口,返回图片存入服务器的URL
* @apiName agency/uploadPicForAgency
* @apiGroup agency
*
* @apiParam {FileObject} imgInfo 图片文件对象
* @apiParam {String} agencyId 代理商ID
* @apiParam {String} picFlag 图片标记(1-登录页logo图,2-登录页背景图,3-内容页logo图)
*
* @apiParamExample {type} Request-Example:
* 传统的FORM表单提交
* Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryzJ4Ys0x4h70Z8heR
*
* ------WebKitFormBoundaryzJ4Ys0x4h70Z8heR
Content-Disposition: form-data; name="agencyId"
000192
------WebKitFormBoundaryzJ4Ys0x4h70Z8heR
Content-Disposition: form-data; name="picFlag"
1
------WebKitFormBoundaryzJ4Ys0x4h70Z8heR
Content-Disposition: form-data; name="file"; filename="Intel-logo.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryzJ4Ys0x4h70Z8heR--
*
* @apiSuccessExample {Object} Success-Response:
* {
* message: ""
* success: true
* data: {
* imageStr: "/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAXA.............."
uploadPath: "agency/2019/05/54e4c76df1db41bbbca80c9a7ef16c5f.jpg"
}
* }
*/
router.post('/uploadPicForAgency', function (req, res, next) {
const methodName = 'MAgencyPlatformDataAPI.uploadPicForAgency';
var form = new formidable.IncomingForm();
form.encoding = 'utf-8'; //设置编辑
form.keepExtensions = true; //保留后缀
form.maxFieldsSize = 2 * 1024 * 1024; //设置单文件大小限制
form.parse(req, function (err, fields, files) {
const agencyId = fields.agencyId;
const picFlag = fields.picFlag;
var imageBuf = fs.readFileSync(files.file.path);
var imagebase = imageBuf.toString("base64");
var imgInfo = {
imgName: files.file.name,
imgStr: imagebase,
}
util.JSONRPC(methodName, [imgInfo,agencyId,picFlag], function (data) {
res.json({
success: true,
data: {
uploadPath: data,
imageStr: imagebase
},
message: ''
})
}, res);
})
});
测试效果如图:
当鼠标划过的时候,需要显示更多的信息,因为GridPanel表格显示区域不够,所以把部分信息移动到 Tip 中显示。代码如下:
store: { type: 'EduCartoonStore', autoLoad: false, listeners: { 'load': function() { // 得到当前的Gird var grid = Ext.getCmp('eduCartoonListGrid'); var view = grid.getView(); // 创建一个 Tip var tip = Ext.create('Ext.tip.ToolTip', { target: view.el, delegate: view.itemSelector, trackMouse: true, renderTo: Ext.getBody(), listeners: { // 显示Tip beforeshow: function updateTipBody(tip) { var record = view.getRecord(tip.triggerElement); var state = ''; var createTime = ''; var packageTime = '-'; var showHtml = ''; // 状态 if (record.data.status === 0) { state = "<span style='color:red'>待审核</span>"; } else if (record.data.status === 1) { state = "<span style='color:green'>已审核</span>"; } else if (record.data.status === -1) { state = "<span style='color:grey'>已关闭</span>"; } // 创建时间 createTime = formatDate(record.data.ctime); // 打包时间 if (record.data.zipGenerateTime !== undefined) { packageTime = formatDate(record.data.zipGenerateTime) } showHtml += '<p><b>ID编号</b>:' + record.data.id + '</p>'; showHtml += '<p><b>状态</b>:' + state + '</p>'; showHtml += '<p><b>创建时间</b>:' + createTime + '</p>'; showHtml += '<p><b>打包时间</b>:' + packageTime + '</p>'; tip.update(showHtml); } } }); } } }
场景是这样的,用户编辑完文本之后,上传了一张图片。而这个时候并没有让编辑器重新获得焦点。就会导致提交的图片为:themes/default/images/spacer.gif 。原因是上传完成图片之后,数据正确返回但是并没有动态绑定到图片的 src 属性中。这个时候需要手动设置一次富文本编辑框的值,触发 change 事件。修改代码如下:
ueditor.all.js 24518行
function callback(){
try{
var link, json, loader,
body = (iframe.contentDocument || iframe.contentWindow.document).body,
result = body.innerText || body.textContent || '';
json = (new Function("return " + result))();
link = me.options.imageUrlPrefix + json.url;
if(json.state == 'SUCCESS' && json.url) {
loader = me.document.getElementById(loadingId);
loader.setAttribute('src', link);
loader.setAttribute('_src', link);
loader.setAttribute('title', json.title || '');
loader.setAttribute('alt', json.original || '');
loader.removeAttribute('id');
domUtils.removeClasses(loader, 'loadingclass');
me.execCommand('inserthtml', ''); // 就是这一行,记住了!!!
} else {
showErrorLoader && showErrorLoader(json.state);
}
}catch(er){
showErrorLoader && showErrorLoader(me.getLang('simpleupload.loadError'));
}
form.reset();
domUtils.un(iframe, 'load', callback);
}
修改源码后就可以解决这个问题啦。
物理分辨率是硬件所支持的,逻辑分辨率是软件可以达到的。
代数 | 设备 | 操作系统 | 逻辑分辨率(point) | 物理分辨率(pixel) | 屏幕尺寸(对角线长度) | 缩放因子 |
---|---|---|---|---|---|---|
iPhone | ||||||
第一代 | iPhone 2G | iOS 1 | 320 x 480 | 480 x 320 | 3.5寸 | 1x |
第二代 | iPhone 3 | iOS 2 | 320 x 480 | 480 x 320 | 3.5寸 | 1x |
第三代 | iPhone 3GS | iOS 3 | 320 x 480 | 480 x 320 | 3.5寸 | 1x |
第四代 | iPhone 4 | iOS 4 | 320 x 480 | 960 × 640 | 3.5寸 | 2x |
第五代 | iPhone 4S | iOS 5 | 320 x 480 | 960 × 640 | 3.5寸 | 2x |
第六代 | iPhone 5 | iOS 6 | 320 x 568 | 1136 x 640 | 4.0寸 | 2x |
第七代 | iPhone 5S/5C | iOS 7 | 320 x 568 | 1136 x 640 | 4.0寸 | 2x |
第八代 | iPhone 6 | iOS 8 | 375 x 667 | 1334 x 750 | 4.7寸 | 2x |
第八代 | iPhone 6 Plus | iOS 8 | 414 x 736 | 2208 x 1242 (1920×1080) | 5.5寸 | 3x |
第九代 | iPhone 6S | iOS 9 | 375 x 667 | 1334 x 750 | 4.7寸 | 2x |
第九代 | iPhone 6S Plus | iOS 9 | 414 x 736 | 2208 x 1242 (1920×1080) | 5.5寸 | 3x |
iPhone SE | iOS 9 | 320 x 568 | 1136 x 640 | 4寸 | 2x | |
第十代 | iPhone 7 | iOS 10 | 375 x 667 | 1334 x 750 | 4.7寸 | 2x |
第十代 | iPhone 7 Plus | iOS 10 | 414 x 736 | 2208 x 1242 (1920×1080) | 5.5寸 | 3x |
如图所示:
Tips:
机型 | 屏幕宽高比 |
---|---|
iPhone 5 | 320÷568=0.563 |
iPhone 6 | 375÷667=0.562 |
iPhone 6 Plus | 414÷736=0.5625 |
最终发现iPhone5和6一个小秘密,它们的比例是不变的
设备 | 操作系统 | 物理分辨率(pixel) | 屏幕尺寸(对角线长度) | 缩放因子 |
---|---|---|---|---|
iPod Touch 1 | iOS 1 | 480 x 320 | 3.5寸 | 1x |
iPod Touch 2 | iOS 2 | 480 x 320 | 3.5寸 | 1x |
iPod Touch 3 | iOS 3 | 480 x 320 | 3.5寸 | 1x |
iPod Touch 4 | iOS 4 | 960 x 640 | 3.5寸 | 2x |
iPod Touch 5 | iOS 6 | 1136 x 640 | 4.0寸 | 2x |
iPod Touch 6 | iOS 8 | 1136 x 640 | 4.0寸 | 2x |
设备 | 操作系统 | 物理分辨率(pixel) | 屏幕尺寸(对角线长度) | 缩放因子 |
---|---|---|---|---|
iPad 1 | iOS 3 | 1024 x 768 | 9.7寸 | 1x |
iPad 2 | iOS 4 | 1024 x 768 | 9.7寸 | 1x |
iPad 3 (The New iPad) | iOS 5 | 2048 x 1536 | 9.7寸 | 2x |
iPad 4 | iOS 6 | 2048 x 1536 | 9.7寸 | 2x |
iPad Air | iOS 7 | 2048 x 1536 | 9.7寸 | 2x |
iPad Air 2 | iOS 8 | 2048 x 1536 | 9.7寸 | 2x |
iPad Pro | iOS 9 | 2732 x 2048 | 12.9寸 | 3x |
iPad mini | iOS 6 | 1024 x 768 | 7.9寸 | 1x |
iPad mini 2 | iOS 7 | 2048 x 1536 | 7.9寸 | 2x |
iPad mini 3 | iOS 8 | 2048 x 1536 | 7.9寸 | 2x |
iPad mini 4 | iOS 9 | 2048 x 1536 | 7.9寸 | 2x |
(经常需要查询的设备像素比:转载自 http://blog.csdn.net/scorpio_27/article/details/52297643)
前端日常工作是什么?拿到PSD图,然后开切!首先我们建立一个app的文件夹,然后在app下,我们建立img文件夹,接下来是 css …… 项目终于搞定之后,我们要使用在线压缩工具把样式表进行合并压缩,把所有的大尺寸图片重新导入Ps,保存为 web 格式,然后调整质量 。。。。。。
你就没想过偷懒的办法么?你就是这么把时间耗在没有意义的简单机械的活儿中么?
或者,很多前端都已经开始使用Grunt这样的工具了,自动压缩、自动打包、文件合并、Less,Sass 编译、文件监控、本地文件服务器调试环境。不错,基于Grunt另外推出了非常多的 generate ,类似 angularJS , Ember , Backbone, webapp, bootstrap 等等等等,但是 Grunt 的学习曲线也是非常陡的。虽然能够通过一些通用脚手架来搭建前端工程作为基础架构。一旦需要修改配置,则是异常痛苦。
gulp 的功效和 Grunt 也是异曲同工、插件也是异常丰富。
通过 Grunt 与 gulp 的对比。我个人还是比较喜欢 gulp 的一些操作模式。不管是从词法、编程语义的理解程度来说。gulp 都是优于 Grunt 。官网的介绍谈到了文件流、以及处理速度。因为没有现成的案例,所以不能妄自评论。下面就浅谈一下两者之间的使用细节。
这里引用?http://markgoodyear.com/2014/01/getting-started-with-gulp/ 中的例子:
Grunt
sass: {
dist: {
options: {
style: 'expanded'
},
files: {
'dist/assets/css/main.css': 'src/styles/main.scss',
}
}
},
autoprefixer: {
dist: {
options: {
browsers: [
'last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'
]
},
src: 'dist/assets/css/main.css',
dest: 'dist/assets/css/main.css'
}
},
grunt.registerTask('styles', ['sass', 'autoprefixer']);
Gulp
gulp.task('sass', function() {
return gulp.src('src/styles/main.scss')
.pipe(sass({ style: 'compressed' }))
.pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
.pipe(gulp.dest('dist/assets/css'))
});
不管从代码还是从阅读性上来说,Gulp 不是更加优越一些嘛?从代码的输入和输出,以及事件的操作顺序一幕了然,完全不用在复杂的GruntFile中间去找各种各样的变量表达式。妈妈再也不用担心我的学习!
那么我们来一个简单的Case吧。
首先确保你安装了NodeJS。
然后运行Continue reading
偶尔翻出来以前写的一些小东西。做应用开发久了,久而久之一开始就很注意框架的选择。但是最初写Javascript那种alert逐步调试。写一些通用的工具类的时间仿佛离我很远了。翻了下以前的一些代码,把他贴出来。就权当是复习下吧。
/** * author: 可乐加糖 * description: 呵呵,不知道写什么好,随便吧。 */ (function (window) { //基础类库 var cola = { get_node: function (elem_id) { if (elem_id.constructor != String) { throw new Error("参数传递错误"); return false; } return document.getElementById(elem_id) || null; }, prev: function (elem) { do { elem = elem.previousElementSibling } while (elem && elem.nodeType != 1); return elem }, next: function (elem) { do { elem = elem.nextSibling; } while (elem && elem.nodeType != 1); return elem }, first_node: function (elem) { elem = elem.firstChild; return elem && elem.nodeType != 1 ? this.next(elem) : elem; }, last: function (elem) { elem = elem.lastChild; return elem && elem.nodeType != 1 ? prev(elem) : elem; }, parent: function (elem, num) { num = num || 1; for (var i = 0; i < num; i++) { if (elem != null) elem = elem.parentNode; return elem; } }, remove: function (elem) { if(elem) elem.parentNode.removeChild(elem); }, empty: function (elem) { while(elem.firstChild) elem.removeChild(elem.firstChild) } } window.cola = cola; })(window)
这是最开始写的一个二级下拉导航条的代码
document.getElementsByClassName = function(clsName){ if(typeof(clsName)!="string" || clsName.constructor != String){ throw new Error("className必须是字符串"); return false; } var nodes = document.getElementsByTagName("*"); var nodeArr = new Array(); for(var i= 0,icount = nodes.length;i<icount;i++){ if(nodes[i].className == clsName) nodeArr.push(nodes[i]); } return nodeArr; } window.onload = function(){ var nodes = document.getElementsByClassName("has-child"); for(var i= 0,icount = nodes.length;i<icount;i++){ nodes[i].onmouseover = function(){ var child_menu = this.getElementsByTagName("ul"); child_menu[0].style.display = "block"; } nodes[i].onmouseout = function () { var child_menu = this.getElementsByTagName("ul"); child_menu[0].style.display = "none"; } } }
还有获取元素的样式表,当初也是在IE下调试了很久才搞定。
function getStyle(elem,name){ if(elem.style[name]) return elem.style[name]; else if(elem.currentStyle) return elem.currentStyle[name]; else if(document.defaultView && document.defaultView.getComputedStyle){ name = name.replace(/([A-Z])/g,"-$1"); name = name.toLowerCase(); var s = document.defaultView.getComputedStyle(elem,""); return s && s.getPropertyValue(name); } else return null; }
Sencha ExtJS 开发中一个比较多的功能就是在编辑某条数据列的时候如果有 datefield 控件时间无法加载入正确的栏目中。
而 textfield 控件则能够通过服务器端返回的数据正确加载到相应的控件中,通过官网的论坛给出的答案是:需要修改服务器端返回的时间格式
{
desc: "成功",
totalResult: 9,
items: [
{
userId: "null1383919764373",
userAccount: "yz",
userIcon: "",
userMobile: "13888889991",
userNick: "园长",
userType: "3",
regTime: "2013-11-08 22:09:24",
updateTime: "2013-11-08 22:09:24",
status: "0",
point: 0,
realName: "园长",
email: "[email protected]",
sex: "0",
birthday: "2013-11-06 00:00:00",
orgs: [{
updateTime: "2013-11-08 22:09:24",
status: "0"
}]
}
...
Ext.getCmp('base_form').getForm().on({ actioncomplete: function(form, action) { if (action.type === 'load') { if (action.result.success) { //绑定开始时间 var date = new Date(action.result.data.regTime); var edate = new Date(action.result.data.updateTime); form.setValues({ regTime: Ext.Date.format(date,"Y-m-d"), updateTime: Ext.Date.format(edate,"Y-m-d") }); } } } });
通过使用 Ext.Date.format(框架内置)方法格式化返回的时间格式就能够正常的把时间设置进入控件中。