启事 - JS
type: channel
link: https://yangqi.co/js/
items: web版钉钉协议分析
items: 完美的背景图全屏效果
items: jquery.validate修改版

web版钉钉协议分析
type: item
date: 2018-01-11T21:10:00+08:00
description: 验证是否第一次登陆：cookie 中的 deviceid初始化，连接服务器后，发送：{ "lwp": "/reg", "headers": { "cache-header": "token app-key did ua vhost wv", "vhost": "WK", "ua": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 OS(windows/6.1) Browser(chrome/63.0.3239.132) DingWeb/3.6.0 LANG/zh_CN", "app-key": "85A09F60A599F5E1867EAB915A8BB07F", "wv": "im:3,au:3,sy:4", "did": "117851a2126f40aaa2f1a3e2df7c00dc", "mid": "804b0002 0" }, "body": null }主要字段的数据来源(JS实现)：cache-header: 固定vhost：固定ua: 当前浏览器的 navigator.userAgentapp-key：固定为 85A09F60A599F5E1867EAB915A8BB07Fwv: 固定did: cookie 没有 deviceid 时，由客户端生成，详见下面的 getDid（uuid.v4标准）；否则不传该字段，但连接 WebSocket 的 HTTP 请求头应该有包含 Cookie:deviceid=7fc0930dba774fcfa7e1d7aac56fabcd; deviceid_exist=true;mid: genMid() + " 0"涉及到的代码段：var i = 0 , r = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]; function genMid() { var e = Math.floor(Math.random() * Math.pow(2, 16)) , t = i++ , n = ""; return n += r[e >> 12 & 15], n += r[e >> 8 & 15], n += r[e >> 4 & 15], n += r[15 & e], n += r[t >> 12 & 15], n += r[t >> 8 & 15], n += r[t >> 4 & 15], n += r[15 & t] }; function uuid_v4 () { var o = [], i = [], l = {}; for (var e, t = 0; t < 16; t++) 0 === (3 & t) && (e = 4294967296 * Math.random()), o[t] = e >>> ((3 & t) << 3) & 255; for (var u = 0; u < 256; u++) i[u] = (u + 256).toString(16).substr(1) var n = 0; return i[o[n++]] + i[o[n++]] + i[o[n++]] + i[o[n++]] + "-" + i[o[n++]] + i[o[n++]] + "-" + i[o[n++]] + i[o[n++]] + "-" + i[o[n++]] + i[o[n++]] + "-" + i[o[n++]] + i[o[n++]] + i[o[n++]] + i[o[n++]] + i[o[n++]] + i[o[n++]] } function getDid () { return uuid_v4().replace(/\-/g, ""); } 对应PHP代码：function getMid () { static $i = 0; $r = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; $e = rand(1, 65535); $i++; return $r[$e >> 12 & 15] . $r[$e >> 8 & 15] . $r[$e >> 4 & 15] . $r[15 & $e] . $r[$i >> 12 & 15] . $r[$i >> 8 & 15] . $r[$i >> 4 & 15] . $r[15 & $i]; } func…

完美的背景图全屏效果
type: item
date: 2015-04-23T15:46:47+08:00
description: 先看看效果需求 图片以背景的形式铺满整个屏幕，不留空白区域 保持图像的纵横比（图片不变形） 图片居中 不出现滚动条 最简单的实现html{ height: 100%; background: url(1.jpg); background-size: cover; }但是使用该方法后，当屏幕比例和图片比例不一样时，背景的右边或下边会隐藏掉，不符合我们的图片居中的需求。因此我们再结合JS进行偏移量的计算：完整代码 background 回归简单由于前面写CSS的时候没有想到背景居中，而去写了一大段的JS的配合，结果最近发现在用cover的同时再配合背景居中就能搞定：html{ height: 100%; background: url(1.jpg) no-repeat center; background-size: cover; }

jquery.validate修改版
type: item
date: 2014-12-15T12:24:00+08:00
description: 新增了正则表达式验证和自定义函数验证的方法/*! jQuery Validation Plugin - v1.11.1 - 3/22/2013\n* https://github.com/jzaefferer/jquery-validation * Copyright (c) 2013 Jörn Zaefferer; Licensed MIT */ /*! * jQuery Validation Plugin 1.11.1 * * http://bassistance.de/jquery-plugins/jquery-plugin-validation/ * http://docs.jquery.com/Plugins/Validation * * Copyright 2013 Jörn Zaefferer * Released under the MIT license: * http://www.opensource.org/licenses/mit-license.php */ (function($) { $.extend($.fn, { // http://docs.jquery.com/Plugins/Validation/validate validate: function( options ) { // if nothing is selected, return nothing; can't chain anyway if ( !this.length ) { if ( options && options.debug && window.console ) { console.warn( "Nothing selected, can't validate, returning nothing." ); } return; } // check if a validator for this form was already created var validator = $.data( this[0], "validator" ); if ( validator ) { return validator; } // Add novalidate tag if HTML5. this.attr( "novalidate", "novalidate" ); validator = new $.validator( options, this[0] ); $.data( this[0], "validator", validator ); if ( validator.settings.onsubmit ) { this.validateDelegate( ":submit", "click", function( event ) { if ( validator.settings.submitHandler ) { validator.submitButton = event.target; } // allow suppressing validation by adding a cancel class to the submit button if ( $(event.target).hasClass("cancel") ) { validator.cancelSubmit = true; } // allow suppressing validation by adding the html5 formnovalidate attribute to the submit button if ( $(event.target).attr("formnovalidate") !== undefined ) { validator.cancelSubmit = true; } }); // validate the form on submit this.submit( function( event ) { if ( validator.settings.debug ) { // prevent form submit to be able to see console output event.preventDefault(); } function handle() { var hidden; if ( validator.settings.submitHandler ) { if ( validator.submitButton ) { // insert a hidden input as a replacement for the missing submit button hidden = $…