数字点阵的动画实现
预览
原理
数字0的js数组点阵,7x5个 span 元素拼出一个数字出来,同样的方法实现 1-9 的数字
动画效果使用 css3 的 keyframes 实现
[
[0, 1, 1, 1, 0],
[1, 1, 0, 1, 1],
[1, 1, 0, 1, 1],
[1, 1, 0, 1, 1],
[1, 1, 0, 1, 1],
[1, 1, 0, 1, 1],
[0, 1, 1, 1, 0]
]
数字0的js数组点阵,7x5个 span 元素拼出一个数字出来,同样的方法实现 1-9 的数字
动画效果使用 css3 的 keyframes 实现
[
[0, 1, 1, 1, 0],
[1, 1, 0, 1, 1],
[1, 1, 0, 1, 1],
[1, 1, 0, 1, 1],
[1, 1, 0, 1, 1],
[1, 1, 0, 1, 1],
[0, 1, 1, 1, 0]
]
图中的黑色位都可以不关注,然后基本原理就是这样的 (以8位作为例子)
0x55555555
01010101010101010101010101010101
0x33333333
00110011001100110011001100110011
0xf0f0f0f
00001111000011110000111100001111
0x3f
00000000000000000000000000111111
// 1. 通过在页面中执行js代码
chrome.tabs.getSelected(null, function(tab) {
var code = 'window.location.reload();';
chrome.tabs.executeScript(tab.id, {code: code});
});
// 2. 通过chrome的api更新tab的url
chrome.tabs.update(null, {url: url});
// 3. 通过chrome的api刷新
chrome.tabs.reload();
以修改 cookie 为例子:
popup: -> 修改cookie -> 更新UI
background: -> 监听cookie的修改事件 -> 触发监听,与 popup 通讯
// 在background中
chrome.cookies.onChanged.addListener(function (changeInfo) {
var cookie = changeInfo.cookie;
if (cookie.domain == 'tool.lu' && cookie.name == 'X-Backend-Server') {
chrome.runtime.sendMessage({event: "cookie", data: cookie.value}, function (response) {
// ...
});
}
});
// 在popup中
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
// do things
});
// 在popup中绑定 window.onload 事件
window.onload = init;
chrome.webRequest.onHeadersReceived.addListener(function (o) {
// 判断是否是主页面, 因为页面中可能包含 iframe, image, css, js 等其他资源的加载
if (o.frameId != 0 || o.type != "main_frame") {
return;
}
for (var i in o.responseHeaders) {
var header = o.responseHeaders[i];
console.log(header.name, header.value);
}
}, {
"urls":["http://tool.lu/*"]
}, ["responseHeaders"]);
chrome.webNavigation.onCompleted.addListener(function(o) {
if (o.frameId == 0) {
// do something...
}
}, {
url: [
{hostContains: 'tool.lu'}
]
});
先来个 Apache Commons 里面没有的
/*
[
{id: 1, name: "name1", gender: 1},
{id: 2, name: "name2", gender: 1},
{id: 3, name: "name1", gender: 2},
]
*/
/*
[1, 2]
*/
CollectionUtils.pluck(persons, "id", new ArrayList<Integer>())
/*
{
1: [
{id: 1, name: "name1", gender: 1},
{id: 2, name: "name2", gender: 1},
],
2: [
{id: 3, name: "name1", gender: 2},
]
}
*/
CollectionUtils.groupBy(persons, "gender", Integer.class)
/*
去重
*/
CollectionUtils.unique(integers, new ArrayList<Integer>())
Apache Commons 里面的
StringUtils.isEmpty(); // null 和 空字符串
StringUtils.isBlank(); // null 和 空字符串 和 全空白字符串
StringUtils.trim(); // 截取掉字符串两侧的空格
StringUtils.strip(); // 截取掉字符串两侧的空白字符串
StringUtils.equalsIgnoreCase(); // 忽略大小写的比较
StringUtils.indexOf(); // 字符/字符串在指定字符串中第一次出现的位置
StringUtils.indexOfIgnoreCase();
StringUtils.lastIndexOf();
StringUtils.contains(); // 是否包含子符串
StringUtils.left();
StringUtils.right();
StringUtils.mid(); // 截取字符串
StringUtils.split(); // 分割字符串
StringUtils.join(); // join数组为字符串
StringUtils.repeat(); // 重复输出字符串
StringUtils.leftPad();
StringUtils.rightPad(); // 填充字符串
StringUtils.lowerCase();
StringUtils.upperCase();
StringUtils.capitalize(); // 大写首字母
StringUtils.reverse(); // 倒转字符串
额,大多数提供的都跟PHP里面一样
CollectionUtils.union(); // 并集
CollectionUtils.intersection(); // 交集
CollectionUtils.containsAny(); // 是否存在交集
CollectionUtils.disjunction(); // 交集的补集
CollectionUtils.subtract(); // 差集
CollectionUtils.filter(); // 过滤
空List的返回
// new ArrayList<>();
Collections.emptyList();
检测端口可用,(绑定,并关掉),来自 Canal
public static boolean isAvailablePort(int port) {
ServerSocket ss = null;
try {
ss = new ServerSocket(port);
ss.bind(null);
return true;
} catch (IOException e) {
return false;
} finally {
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
}
}
}
}
利用字符串标记,优雅解决内外配置文件的加载
// ...
private static final String CLASSPATH_URL_PREFIX = "classpath:";
// ...
String conf = System.getProperty("canal.conf", "classpath:canal.properties");
Properties properties = new Properties();
if (conf.startsWith(CLASSPATH_URL_PREFIX)) {
conf = StringUtils.substringAfter(conf, CLASSPATH_URL_PREFIX);
properties.load(CanalLauncher.class.getClassLoader().getResourceAsStream(conf));
} else {
properties.load(new FileInputStream(conf));
}