├── GET与POST区别..md ├── README.md ├── TCP.md ├── axios_.md ├── book ├── JavaScript正则表达式迷你书(1.1版).pdf ├── JavaScript高级程序设计(第3版).pdf ├── 《图解HTTP》完整彩色版.pdf └── 学习JavaScript数据结构与算法(第2版).pdf ├── css ├── Sticky-footers布局.md ├── ios,andriod问题.md └── 移动端1px的解决方案.md ├── db ├── mongodb.md ├── mongodb数据库迁移备份.md └── mongoose多条件模糊查询.md ├── dev-tools ├── chrome跨域启动.md ├── git.md ├── nginx.md ├── npm.md ├── nrm.md ├── vscode.md └── vue-pracel试玩.md ├── electron-vue初体验.md ├── fn-tools └── 常见html正则操作.md ├── js ├── js常见位运算.md ├── js生成重复字符串.md └── js题.md ├── js内存分配.md ├── learnEnglish.md ├── lession1.md ├── lession2.md ├── linux-ubuntu16常见问题.md ├── md-img ├── _.png ├── border-img.png ├── btn.png ├── django-progect.png ├── h-w.png ├── myapp.png ├── pip-setup.png └── pip.png ├── nuxt配置.md ├── pm2快速使用.md ├── pm2进阶使用.md ├── python ├── django写个helloword.md └── python-pip安装.md ├── react └── 实战之react.md ├── richText.md ├── vue ├── 1.写个vue组件库.md ├── 2.vue组件库之button实现.md └── demo │ └── mvvm.html ├── 正反向代理.md ├── 移动端滚动穿透解决方案.md ├── 表单默认提交问题.md └── 雅虎性能优化的十四条规则.md /GET与POST区别..md: -------------------------------------------------------------------------------- 1 | GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二。 2 | 3 | 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数。 4 | 5 | 你可能自己写过无数个GET和POST请求,或者已经看过很多权威网站总结出的他们的区别,你非常清楚知道什么时候该用什么。 6 | 7 | 当你在面试中被问到这个问题,你的内心充满了自信和喜悦。 8 | 9 | 你轻轻松松的给出了一个“标准答案”: 10 | 11 | GET在浏览器回退时是无害的,而POST会再次提交请求。 12 | 13 | GET产生的URL地址可以被Bookmark,而POST不可以。 14 | 15 | GET请求会被浏览器主动cache,而POST不会,除非手动设置。 16 | 17 | GET请求只能进行url编码,而POST支持多种编码方式。 18 | 19 | GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。 20 | 21 | GET请求在URL中传送的参数是有长度限制的,而POST么有。 22 | 23 | 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。 24 | 25 | GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。 26 | 27 | GET参数通过URL传递,POST放在Request body中。 28 | (本标准答案参考自w3schools) 29 | 30 | “很遗憾,这不是我们要的回答!” 31 | 32 | 请告诉我真相。。。 33 | 34 | 如果我告诉你GET和POST本质上没有区别你信吗? 35 | 36 | 让我们扒下GET和POST的外衣,坦诚相见吧! 37 | 38 | 39 | GET和POST是什么?HTTP协议中的两种发送请求的方法。 40 | 41 | HTTP是什么?HTTP是基于TCP/IP的关于数据如何在万维网中如何通信的协议。 42 | 43 | HTTP的底层是TCP/IP。所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。你要给GET加上request body,给POST带上url参数,技术上是完全行的通的。 44 | 45 | 那么,“标准答案”里的那些区别是怎么回事? 46 | 47 | 48 | 49 | 在我大万维网世界中,TCP就像汽车,我们用TCP来运输数据,它很可靠,从来不会发生丢件少件的现象。但是如果路上跑的全是看起来一模一样的汽车,那这个世界看起来是一团混乱,送急件的汽车可能被前面满载货物的汽车拦堵在路上,整个交通系统一定会瘫痪。为了避免这种情况发生,交通规则HTTP诞生了。HTTP给汽车运输设定了好几个服务类别,有GET, POST, PUT, DELETE等等,HTTP规定,当执行GET请求的时候,要给汽车贴上GET的标签(设置method为GET),而且要求把传送的数据放在车顶上(url中)以方便记录。如果是POST请求,就要在车上贴上POST的标签,并把货物放在车厢里。当然,你也可以在GET的时候往车厢内偷偷藏点货物,但是这是很不光彩;也可以在POST的时候在车顶上也放一些数据,让人觉得傻乎乎的。HTTP只是个行为准则,而TCP才是GET和POST怎么实现的基本。 50 | 51 | 但是,我们只看到HTTP对GET和POST参数的传送渠道(url还是requrest body)提出了要求。“标准答案”里关于参数大小的限制又是从哪来的呢? 52 | 53 | 54 | 55 | 在我大万维网世界中,还有另一个重要的角色:运输公司。不同的浏览器(发起http请求)和服务器(接受http请求)就是不同的运输公司。 虽然理论上,你可以在车顶上无限的堆货物(url中无限加参数)。但是运输公司可不傻,装货和卸货也是有很大成本的,他们会限制单次运输量来控制风险,数据量太大对浏览器和服务器都是很大负担。业界不成文的规定是,(大多数)浏览器通常都会限制url长度在2K个字节,而(大多数)服务器最多处理64K大小的url。超过的部分,恕不处理。如果你用GET服务,在request body偷偷藏了数据,不同服务器的处理方式也是不同的,有些服务器会帮你卸货,读出数据,有些服务器直接忽略,所以,虽然GET可以带request body,也不能保证一定能被接收到哦。 56 | 57 | 好了,现在你知道,GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。 58 | 59 | 你以为本文就这么结束了? 60 | 61 | 62 | 我们的大BOSS还等着出场呢。。。 63 | 64 | 这位BOSS有多神秘?当你试图在网上找“GET和POST的区别”的时候,那些你会看到的搜索结果里,从没有提到他。他究竟是什么呢。。。 65 | 66 | GET和POST还有一个重大区别,简单的说: 67 | GET产生一个TCP数据包;POST产生两个TCP数据包。 68 | 69 | 长的说: 70 | 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据); 71 | 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。 72 | 73 | 也就是说,GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。 74 | 75 | 因为POST需要两步,时间上消耗的要多一点,看起来GET比POST更有效。因此Yahoo团队有推荐用GET替换POST来优化网站性能。但这是一个坑!跳入需谨慎。为什么? 76 | 1. GET与POST都有自己的语义,不能随便混用。 77 | 2. 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。 78 | 3. 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。 79 | 80 | 现在,当面试官再问你“GET与POST的区别”的时候,你的内心是不是这样的? 81 | 82 | (转自微信公众号WebTechGarden) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > 不积跬步无以至千里 2 | > 好记性不如烂笔头 -------------------------------------------------------------------------------- /TCP.md: -------------------------------------------------------------------------------- 1 | TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义 2 | 3 | 建立TCP需要三次握手才能建立,而断开连接则需要四次握手 4 | ## 三次握手Three-way Handshake 5 | 首先Client端发送连接请求报文,Server端接受连接后回复ACK报文,并为这次连接分配资源。Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP连接就建立了。 6 | 7 | > SYN(synchronous)是TCP/IP建立连接时使用的握手信号。在客户机和服务器之间建立正常的TCP网络连接时,客户机首先发出一个SYN消息,服务器使用SYN+ACK应答表示接收到了这个消息,最后客户机再以ACK消息响应。这样在客户机和服务器之间才能建立起可靠的TCP连接,数据才可以在客户机和服务器之间传递。 8 | > ACK (Acknowledgement)即是确认字符,在数据通信中,接收站发给发送站的一种传输类控制字符。表示发来的数据已确认接收无误。 9 | 在TCP/IP协议中,如果接收方成功的接收到数据,那么会回复一个ACK数据。通常ACK信号有自己固定的格式,长度大小,由接收方回复给发送方。 10 | 11 | ## 四次握手Four-way Handshake 12 | > 【注意】中断连接端可以是Client端,也可以是Server端。 13 | 假设Client端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,"告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息"。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,"告诉Client端,好了,我这边数据发完了,准备好关闭连接了"。Client端收到FIN报文后,"就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。“,Server端收到ACK后,"就知道可以断开连接了"。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok,TCP连接就这样关闭了! 14 | > 在TIME_WAIT状态中,如果TCP client端最后一次发送的ACK丢失了,它将重新发送。TIME_WAIT状态中所需要的时间是依赖于实现方法的。典型的值为30秒、1分钟和2分钟。等待之后连接正式关闭,并且所有的资源(包括端口号)都被释放。 15 | 16 | ## 【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手? 17 | 答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。 18 | 19 | ## 【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态? 20 | 21 | 答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。 -------------------------------------------------------------------------------- /axios_.md: -------------------------------------------------------------------------------- 1 | Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。 2 | 3 | ## Features 4 | 从浏览器中创建 XMLHttpRequests 5 | 从 node.js 创建 http 请求 6 | 支持 Promise API 7 | 拦截请求和响应 8 | 转换请求数据和响应数据 9 | 取消请求 10 | 自动转换 JSON 数据 11 | 客户端支持防御 XSRF 12 | ## 浏览器支持 13 | 14 | 15 | ## 安装 16 | 17 | 使用 npm: 18 | ``` 19 | $ npm install axios 20 | ``` 21 | 使用 bower: 22 | ``` 23 | $ bower install axios 24 | ``` 25 | 使用 cdn: 26 | ``` 27 | 28 | ``` 29 | ## Example 30 | 执行 GET 请求 31 | ``` 32 | // 为给定 ID 的 user 创建请求 33 | axios.get('/user?ID=12345') 34 | .then(function (response) { 35 | console.log(response); 36 | }) 37 | .catch(function (error) { 38 | console.log(error); 39 | }); 40 | 41 | // 可选地,上面的请求可以这样做 42 | axios.get('/user', { 43 | params: { 44 | ID: 12345 45 | } 46 | }) 47 | .then(function (response) { 48 | console.log(response); 49 | }) 50 | .catch(function (error) { 51 | console.log(error); 52 | }); 53 | ``` 54 | 执行 POST 请求 55 | ``` 56 | axios.post('/user', { 57 | firstName: 'Fred', 58 | lastName: 'Flintstone' 59 | }) 60 | .then(function (response) { 61 | console.log(response); 62 | }) 63 | .catch(function (error) { 64 | console.log(error); 65 | }); 66 | ``` 67 | 执行多个并发请求 68 | ``` 69 | function getUserAccount() { 70 | return axios.get('/user/12345'); 71 | } 72 | 73 | function getUserPermissions() { 74 | return axios.get('/user/12345/permissions'); 75 | } 76 | 77 | axios.all([getUserAccount(), getUserPermissions()]) 78 | .then(axios.spread(function (acct, perms) { 79 | // 两个请求现在都执行完成 80 | })); 81 | ``` 82 | ## axios API 83 | 可以通过向 axios 传递相关配置来创建请求 84 | ``` 85 | axios(config) 86 | // 发送 POST 请求 87 | axios({ 88 | method: 'post', 89 | url: '/user/12345', 90 | data: { 91 | firstName: 'Fred', 92 | lastName: 'Flintstone' 93 | } 94 | }); 95 | axios(url[, config]) 96 | // 发送 GET 请求(默认的方法) 97 | axios('/user/12345'); 98 | ``` 99 | ## 请求方法的别名 100 | 为方便起见,为所有支持的请求方法提供了别名 101 | ``` 102 | axios.request(config) 103 | axios.get(url[, config]) 104 | axios.delete(url[, config]) 105 | axios.head(url[, config]) 106 | axios.post(url[, data[, config]]) 107 | axios.put(url[, data[, config]]) 108 | axios.patch(url[, data[, config]]) 109 | ``` 110 | NOTE 111 | 在使用别名方法时, url、method、data 这些属性都不必在配置中指定。 112 | ## 并发 113 | 处理并发请求的助手函数 114 | ``` 115 | axios.all(iterable) 116 | axios.spread(callback) 117 | ``` 118 | ## 创建实例 119 | 可以使用自定义配置新建一个 axios 实例 120 | ``` 121 | axios.create([config]) 122 | var instance = axios.create({ 123 | baseURL: 'https://some-domain.com/api/', 124 | timeout: 1000, 125 | headers: {'X-Custom-Header': 'foobar'} 126 | }); 127 | ``` 128 | ## 实例方法 129 | 以下是可用的实例方法。指定的配置将与实例的配置合并 130 | ``` 131 | axios#request(config) 132 | axios#get(url[, config]) 133 | axios#delete(url[, config]) 134 | axios#head(url[, config]) 135 | axios#post(url[, data[, config]]) 136 | axios#put(url[, data[, config]]) 137 | axios#patch(url[, data[, config]]) 138 | ``` 139 | ## 请求配置 140 | 这些是创建请求时可以用的配置选项。只有 url 是必需的。如果没有指定 method,请求将默认使用 get 方法。 141 | ``` 142 | { 143 | // `url` 是用于请求的服务器 URL 144 | url: '/user', 145 | 146 | // `method` 是创建请求时使用的方法 147 | method: 'get', // 默认是 get 148 | 149 | // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。 150 | // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL 151 | baseURL: 'https://some-domain.com/api/', 152 | 153 | // `transformRequest` 允许在向服务器发送前,修改请求数据 154 | // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法 155 | // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream 156 | transformRequest: [function (data) { 157 | // 对 data 进行任意转换处理 158 | 159 | return data; 160 | }], 161 | 162 | // `transformResponse` 在传递给 then/catch 前,允许修改响应数据 163 | transformResponse: [function (data) { 164 | // 对 data 进行任意转换处理 165 | 166 | return data; 167 | }], 168 | 169 | // `headers` 是即将被发送的自定义请求头 170 | headers: {'X-Requested-With': 'XMLHttpRequest'}, 171 | 172 | // `params` 是即将与请求一起发送的 URL 参数 173 | // 必须是一个无格式对象(plain object)或 URLSearchParams 对象 174 | params: { 175 | ID: 12345 176 | }, 177 | 178 | // `paramsSerializer` 是一个负责 `params` 序列化的函数 179 | // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/) 180 | paramsSerializer: function(params) { 181 | return Qs.stringify(params, {arrayFormat: 'brackets'}) 182 | }, 183 | 184 | // `data` 是作为请求主体被发送的数据 185 | // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH' 186 | // 在没有设置 `transformRequest` 时,必须是以下类型之一: 187 | // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams 188 | // - 浏览器专属:FormData, File, Blob 189 | // - Node 专属: Stream 190 | data: { 191 | firstName: 'Fred' 192 | }, 193 | 194 | // `timeout` 指定请求超时的毫秒数(0 表示无超时时间) 195 | // 如果请求话费了超过 `timeout` 的时间,请求将被中断 196 | timeout: 1000, 197 | 198 | // `withCredentials` 表示跨域请求时是否需要使用凭证 199 | withCredentials: false, // 默认的 200 | 201 | // `adapter` 允许自定义处理请求,以使测试更轻松 202 | // 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)). 203 | adapter: function (config) { 204 | /* ... */ 205 | }, 206 | 207 | // `auth` 表示应该使用 HTTP 基础验证,并提供凭据 208 | // 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头 209 | auth: { 210 | username: 'janedoe', 211 | password: 's00pers3cret' 212 | }, 213 | 214 | // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream' 215 | responseType: 'json', // 默认的 216 | 217 | // `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称 218 | xsrfCookieName: 'XSRF-TOKEN', // default 219 | 220 | // `xsrfHeaderName` 是承载 xsrf token 的值的 HTTP 头的名称 221 | xsrfHeaderName: 'X-XSRF-TOKEN', // 默认的 222 | 223 | // `onUploadProgress` 允许为上传处理进度事件 224 | onUploadProgress: function (progressEvent) { 225 | // 对原生进度事件的处理 226 | }, 227 | 228 | // `onDownloadProgress` 允许为下载处理进度事件 229 | onDownloadProgress: function (progressEvent) { 230 | // 对原生进度事件的处理 231 | }, 232 | 233 | // `maxContentLength` 定义允许的响应内容的最大尺寸 234 | maxContentLength: 2000, 235 | 236 | // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte 237 | validateStatus: function (status) { 238 | return status >= 200 && status < 300; // 默认的 239 | }, 240 | 241 | // `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目 242 | // 如果设置为0,将不会 follow 任何重定向 243 | maxRedirects: 5, // 默认的 244 | 245 | // `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项: 246 | // `keepAlive` 默认没有启用 247 | httpAgent: new http.Agent({ keepAlive: true }), 248 | httpsAgent: new https.Agent({ keepAlive: true }), 249 | 250 | // 'proxy' 定义代理服务器的主机名称和端口 251 | // `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据 252 | // 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。 253 | proxy: { 254 | host: '127.0.0.1', 255 | port: 9000, 256 | auth: : { 257 | username: 'mikeymike', 258 | password: 'rapunz3l' 259 | } 260 | }, 261 | 262 | // `cancelToken` 指定用于取消请求的 cancel token 263 | // (查看后面的 Cancellation 这节了解更多) 264 | cancelToken: new CancelToken(function (cancel) { 265 | }) 266 | } 267 | ``` 268 | ## 响应结构 269 | 某个请求的响应包含以下信息 270 | ``` 271 | { 272 | // `data` 由服务器提供的响应 273 | data: {}, 274 | 275 | // `status` 来自服务器响应的 HTTP 状态码 276 | status: 200, 277 | 278 | // `statusText` 来自服务器响应的 HTTP 状态信息 279 | statusText: 'OK', 280 | 281 | // `headers` 服务器响应的头 282 | headers: {}, 283 | 284 | // `config` 是为请求提供的配置信息 285 | config: {} 286 | } 287 | ``` 288 | 使用 then 时,你将接收下面这样的响应: 289 | ``` 290 | axios.get('/user/12345') 291 | .then(function(response) { 292 | console.log(response.data); 293 | console.log(response.status); 294 | console.log(response.statusText); 295 | console.log(response.headers); 296 | console.log(response.config); 297 | }); 298 | ``` 299 | 在使用 catch 时,或传递 rejection callback 作为 then 的第二个参数时,响应可以通过 error 对象可被使用,正如在错误处理这一节所讲。 300 | ## 配置的默认值/defaults 301 | 你可以指定将被用在各个请求的配置默认值 302 | 303 | ### 全局的 axios 默认值 304 | ``` 305 | axios.defaults.baseURL = 'https://api.example.com'; 306 | axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; 307 | axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; 308 | ``` 309 | ### 自定义实例默认值 310 | ``` 311 | // 创建实例时设置配置的默认值 312 | var instance = axios.create({ 313 | baseURL: 'https://api.example.com' 314 | }); 315 | 316 | // 在实例已创建后修改默认值 317 | instance.defaults.headers.common['Authorization'] = AUTH_TOKEN; 318 | ``` 319 | ### 配置的优先顺序 320 | 配置会以一个优先顺序进行合并。这个顺序是:在 lib/defaults.js 找到的库的默认值,然后是实例的 defaults 属性,最后是请求的 config 参数。后者将优先于前者。这里是一个例子: 321 | ``` 322 | // 使用由库提供的配置的默认值来创建实例 323 | // 此时超时配置的默认值是 `0` 324 | var instance = axios.create(); 325 | 326 | // 覆写库的超时默认值 327 | // 现在,在超时前,所有请求都会等待 2.5 秒 328 | instance.defaults.timeout = 2500; 329 | 330 | // 为已知需要花费很长时间的请求覆写超时设置 331 | instance.get('/longRequest', { 332 | timeout: 5000 333 | }); 334 | ``` 335 | ### 拦截器 336 | 在请求或响应被 then 或 catch 处理前拦截它们。 337 | ``` 338 | // 添加请求拦截器 339 | axios.interceptors.request.use(function (config) { 340 | // 在发送请求之前做些什么 341 | return config; 342 | }, function (error) { 343 | // 对请求错误做些什么 344 | return Promise.reject(error); 345 | }); 346 | 347 | // 添加响应拦截器 348 | axios.interceptors.response.use(function (response) { 349 | // 对响应数据做点什么 350 | return response; 351 | }, function (error) { 352 | // 对响应错误做点什么 353 | return Promise.reject(error); 354 | }); 355 | ``` 356 | 如果你想在稍后移除拦截器,可以这样: 357 | ``` 358 | var myInterceptor = axios.interceptors.request.use(function () {/*...*/}); 359 | axios.interceptors.request.eject(myInterceptor); 360 | ``` 361 | 可以为自定义 axios 实例添加拦截器 362 | ``` 363 | var instance = axios.create(); 364 | instance.interceptors.request.use(function () {/*...*/}); 365 | ``` 366 | ### 错误处理 367 | ``` 368 | axios.get('/user/12345') 369 | .catch(function (error) { 370 | if (error.response) { 371 | // 请求已发出,但服务器响应的状态码不在 2xx 范围内 372 | console.log(error.response.data); 373 | console.log(error.response.status); 374 | console.log(error.response.headers); 375 | } else { 376 | // Something happened in setting up the request that triggered an Error 377 | console.log('Error', error.message); 378 | } 379 | console.log(error.config); 380 | }); 381 | ``` 382 | 可以使用 validateStatus 配置选项定义一个自定义 HTTP 状态码的错误范围。 383 | ``` 384 | axios.get('/user/12345', { 385 | validateStatus: function (status) { 386 | return status < 500; // 状态码在大于或等于500时才会 reject 387 | } 388 | }) 389 | ``` 390 | ### 取消 391 | 使用 cancel token 取消请求 392 | Axios 的 cancel token API 基于cancelable promises proposal,它还处于第一阶段。 393 | 可以使用 CancelToken.source 工厂方法创建 cancel token,像这样: 394 | ``` 395 | var CancelToken = axios.CancelToken; 396 | var source = CancelToken.source(); 397 | 398 | axios.get('/user/12345', { 399 | cancelToken: source.token 400 | }).catch(function(thrown) { 401 | if (axios.isCancel(thrown)) { 402 | console.log('Request canceled', thrown.message); 403 | } else { 404 | // 处理错误 405 | } 406 | }); 407 | 408 | // 取消请求(message 参数是可选的) 409 | source.cancel('Operation canceled by the user.'); 410 | ``` 411 | 还可以通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token: 412 | ``` 413 | var CancelToken = axios.CancelToken; 414 | var cancel; 415 | 416 | axios.get('/user/12345', { 417 | cancelToken: new CancelToken(function executor(c) { 418 | // executor 函数接收一个 cancel 函数作为参数 419 | cancel = c; 420 | }) 421 | }); 422 | 423 | // 取消请求 424 | cancel(); 425 | ``` 426 | Note : 可以使用同一个 cancel token 取消多个请求 427 | 428 | ### Promise 429 | axios 依赖原生的 ES6 Promise 实现而被支持. 430 | 如果你的环境不支持 ES6 Promise,你可以使用 polyfill. 431 | ### TypeScript 432 | axios includes TypeScript definitions. 433 | ``` 434 | import axios from 'axios'; 435 | axios.get('/user?ID=12345'); 436 | ``` -------------------------------------------------------------------------------- /book/JavaScript正则表达式迷你书(1.1版).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/book/JavaScript正则表达式迷你书(1.1版).pdf -------------------------------------------------------------------------------- /book/JavaScript高级程序设计(第3版).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/book/JavaScript高级程序设计(第3版).pdf -------------------------------------------------------------------------------- /book/《图解HTTP》完整彩色版.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/book/《图解HTTP》完整彩色版.pdf -------------------------------------------------------------------------------- /book/学习JavaScript数据结构与算法(第2版).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/book/学习JavaScript数据结构与算法(第2版).pdf -------------------------------------------------------------------------------- /css/Sticky-footers布局.md: -------------------------------------------------------------------------------- 1 | # 什么是Sticky footers布局 2 | - 在网页设计中,Sticky footers设计是最古老和最常见的效果之一,大多数人都曾经经历过。它可以概括如下:如果页面内容不够长的时候,页脚块粘贴在视窗底部;如果内容足够长时,页脚块会被内容向下推送。 3 | 4 | # 固定高度的实现方式 5 | html 6 | ``` 7 |
8 |
9 |
10 |
11 |
@Artiely
12 |
13 | 14 | 15 | ``` 16 | css 17 | ``` 18 | .sticker { 19 | height: auto; 20 | padding: 0 0 40px 0; 21 | min-height: 100vh; 22 | box-sizing: border-box; 23 | } 24 | .stickerCon { 25 | padding-bottom: 40px; 26 | box-sizing: inherit; 27 | } 28 | .sfooter { 29 | margin-top: -40px; 30 | height: 40px; 31 | width: 100%; 32 | line-height: 40px; 33 | position: relative; 34 | } 35 | ``` 36 | 37 | # Flexbox解决方案 38 | 解决这类问题,Flexbox是最完美的方案。我们只需要几行CSS代码就可以完美的实现,而且不需要一些奇怪的计算或添加额外的HTML元素。 39 | html 40 | ``` 41 | 42 |
43 | 44 | 45 | ``` 46 | css 47 | ``` 48 | body{ 49 | display:flex; 50 | flex-flow:colum; 51 | min-height:100vh; 52 | } 53 | .main{ 54 | flex:1; 55 | } 56 | ``` 57 | 58 | # 其他参考 59 | >- [https://css-tricks.com/snippets/css/sticky-footer/](https://css-tricks.com/snippets/css/sticky-footer/) 60 | >- https://pixelsvsbytes.com/2011/09/sticky-css-footers-the-flexible-way/](https://pixelsvsbytes.com/2011/09/sticky-css-footers-the-flexible-way/) 61 | 62 | -------------------------------------------------------------------------------- /css/ios,andriod问题.md: -------------------------------------------------------------------------------- 1 | # ios 下定位的层如果有表单,在输入时键盘弹起,表单的光标不会跟随(系统bug) 2 | 解决办法:有表单数据尽量在页面完成,不用类似popup的浮层 3 | 4 | # ios 下滑动不平滑 5 | ``` 6 | html, 7 | body { 8 | -webkit-overflow-scrolling: touch; 9 | } 10 | ``` 11 | # ios 下表单的默认外观样式 12 | ``` 13 | input select{ 14 | -webkit-appearance: none; 15 | } 16 | ``` 17 | 18 | ## 禁止ios 长按时不触发系统的菜单,禁止ios&android长按时下载图片 19 | 20 | ``` 21 | .css{-webkit-touch-callout: none} 22 | ``` 23 | ## 禁止ios和android用户选中文字 24 | ``` 25 | .css{-webkit-user-select:none} 26 | ``` 27 | 消除transition闪屏 28 | ``` 29 | .css{ 30 | /*设置内嵌的元素在 3D 空间如何呈现:保留 3D*/ 31 | -webkit-transform-style: preserve-3d; 32 | /*(设置进行转换的元素的背面在面对用户时是否可见:隐藏)*/ 33 | -webkit-backface-visibility: hidden; 34 | } 35 | ``` 36 | 开启硬件加速 37 | 38 | 解决页面闪白 39 | 保证动画流畅 40 | ``` 41 | .css { 42 | -webkit-transform: translate3d(0, 0, 0); 43 | -moz-transform: translate3d(0, 0, 0); 44 | -ms-transform: translate3d(0, 0, 0); 45 | transform: translate3d(0, 0, 0); 46 | } 47 | ``` 48 | # 文字超出隐藏 49 | ``` 50 | // 文字超出两行隐藏 51 | .textover2{ 52 | display: -webkit-box; 53 | -webkit-box-orient: vertical; 54 | -webkit-line-clamp: 2; 55 | overflow: hidden; 56 | line-height:1.5; 57 | } 58 | // 文字超出一行隐藏 59 | .textover1{ 60 | overflow: hidden; 61 | text-overflow:ellipsis; 62 | white-space: nowrap; 63 | } 64 | ``` 65 | # 清浮动 66 | ``` 67 | // 清浮动 68 | .clearfix{ 69 | &:after{ 70 | content:''; 71 | height: 0; 72 | display: block; 73 | overflow: hidden; 74 | clear: both; 75 | } 76 | } 77 | ``` -------------------------------------------------------------------------------- /css/移动端1px的解决方案.md: -------------------------------------------------------------------------------- 1 | # 1.用小数来写px值 2 | 3 | IOS8以上已经支持带小数的px值, media query对应devicePixelRatio有个查询值-webkit-min-device-pixel-ratio, css可以写成这样 4 | ``` 5 | .border { border: 1px solid #999 } 6 | @media screen and (-webkit-min-device-pixel-ratio: 2) { 7 | .border { border: 0.5px solid #999 } 8 | } 9 | @media screen and (-webkit-min-device-pixel-ratio: 3) { 10 | .border { border: 0.333333px solid #999 } 11 | } 12 | ``` 13 | 如果使用less/sass的话只是加了1句mixin 14 | 15 | > 缺点: 安卓与低版本IOS不适用, 这个或许是未来的标准写法, 现在不做指望 16 | # 2.border-image 17 | ![](md-img/border-img.png) 18 | 这样的1张6X6的图片, 9宫格等分填充border-image, 这样元素的4个边框宽度都只有1px 19 | ``` 20 | @media screen and (-webkit-min-device-pixel-ratio: 2){ 21 | .border{ 22 | border: 1px solid transparent; 23 | border-image: url(border.gif) 2 repeat; 24 | } 25 | } 26 | ``` 27 | 图片可以用gif, png, base64多种格式, 以上是上下左右四条边框的写法, 需要单一边框只要定义单一边框的border, 代码比较直观. 28 | > 缺点: 对于圆角样式, 将图片放大修改成圆角也能满足需求, 但这样无形中增加了border的宽度存在多种边框颜色或者更改的时候麻烦 29 | 30 | # 3. background渐变 31 | 背景渐变, 渐变在透明色和边框色中间分割, frozenUI用的就是这种方法, 借用它的上边框写法: 32 | ``` 33 | @media screen and (-webkit-min-device-pixel-ratio: 2){ 34 | .ui-border-t { 35 | background-position: left top; 36 | background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0.5,transparent),color-stop(0.5,#e0e0e0),to(#e0e0e0)); 37 | } 38 | } 39 | ``` 40 | 这样更改颜色比border-image方便, 兼容性 41 | > 缺点: 代码量大, 而且需要针对不同边框结构, frozenUI就定义9种基本样式而且这只是背景, 这样做出来的边框实际是在原本的border空间内部的, 如果元素背景色有变化的样式, 边框线也会消失.最后不能适应圆角样式 42 | 43 | # 4. :before, :after与transform 44 | 之前说的frozenUI的圆角边框就是采用这种方式, 构建1个伪元素, 将它的长宽放大到2倍, 边框宽度设置为1px, 再以transform缩放到50%. 45 | ``` 46 | .radius-border{ 47 | position: relative; 48 | } 49 | @media screen and (-webkit-min-device-pixel-ratio: 2){ 50 | .radius-border:before{ 51 | content: ""; 52 | pointer-events: none; /* 防止点击触发 */ 53 | box-sizing: border-box; 54 | position: absolute; 55 | width: 200%; 56 | height: 200%; 57 | left: 0; 58 | top: 0; 59 | border-radius: 8px; 60 | border:1px solid #999; 61 | -webkit-transform(scale(0.5)); 62 | -webkit-transform-origin: 0 0; 63 | transform(scale(0.5)); 64 | transform-origin: 0 0; 65 | } 66 | } 67 | ``` 68 | 需要注意是没有:before, :after伪元素的 69 | 70 | 优点: 其实不止是圆角, 其他的边框也可以这样做出来 71 | 72 | > 缺点: 代码量也很大, 占据了伪元素, 容易引起冲突 73 | 74 | # 5. flexible.js 75 | 这是淘宝移动端采取的方案, github的地址:https://github.com/amfe/lib-flexible. 前面已经说过1px变粗的原因就在于一刀切的设置viewport宽度, 如果能把viewport宽度设置为实际的设备物理宽度, css里的1px不就等于实际1px长了么. flexible.js就是这样干的. 76 | 77 | 里面的scale值指的是对ideal viewport的缩放, flexible.js检测到IOS机型, 会算出scale = 1/devicePixelRatio, 然后设置viewport 78 | 79 | ``` 80 | metaEl = doc.createElement('meta'); 81 | metaEl.setAttribute('name', 'viewport'); 82 | metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no'); 83 | ``` 84 | devicePixelRatio=2时输出meta如下, 这样viewport与ideal viewport的比是0.5, 也就与设备物理像素一致 85 | ``` 86 | 87 | ``` 88 | 另外html元素上的font-size会被设置为屏幕宽的1/10, 这样css可以以rem为基础长度单位进行改写, 比如rem是28px, 原先的7px就是0.25rem. border的宽度能直接写1px. 89 | ``` 90 | function refreshRem() { 91 | var width = docEl.getBoundingClientRect().width; 92 | if (width / dpr > 540) { //大于540px可以不认为是手机屏 93 | width = 540 * dpr; 94 | } 95 | var rem = width / 10; 96 | docEl.style.fontSize = rem + 'px'; 97 | flexible.rem = win.rem = rem; 98 | } 99 | ``` 100 | px和rem相互转换的计算方法会暴露在window.lib.flexible中. 这样可以为less/sass编写宏方法. 具体的css改写方法参照大漠的文章http://www.w3cplus.com/mobile/lib-flexible-for-html5-layout.html 101 | 102 | 项目中特别指出了为了防止字体模糊, 出现奇数字号的字体, 字体的实际单位还是要以px为单位. 103 | 104 | > 缺点: 不适用安卓, flexible内部做了检测 非iOS机型还是采用传统的scale=1.0, 原因在于安卓手机不一定有devicePixelRatio属性, 就算有也不一定能响应scale小于1的viewport缩放设置, 例如我的手机设置了scale=0.33333333, 显示的结果也与scale=1无异. 105 | 106 | # 使用 107 | 108 | 个人比较偏爱 FrozenUI 的解决方案 -------------------------------------------------------------------------------- /db/mongodb.md: -------------------------------------------------------------------------------- 1 | # windows本地启动 2 | ``` 3 | // 我本地启动mongo bin下 C:\Program Files\MongoDB\Server\3.4\bin 4 | mongod --dbpath d:/MongoDB/data 5 | ``` -------------------------------------------------------------------------------- /db/mongodb数据库迁移备份.md: -------------------------------------------------------------------------------- 1 | # mongodb数据库简单迁移 windows -> linux 2 | 3 | cd 到本机mongodb的安装目录 如: 4 | `C:\Program Files\MongoDB\Server\3.4\bin` 可以发现里面除了可以启动mongodb的`mongod.exe`还有很多启动程序 5 | 6 | 其中`mongodump.exe`和`mongorestore.exe`就分别是用来数据备份迁移的 7 | 8 | ## mongodump备份数据库 9 | 10 | 1. 常用命令格 11 | ``` 12 | mongodump -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -o 文件存在路径 13 | ``` 14 | 如果没有用户,可以去掉-u和-p。 15 | 如果导出本机的数据库,可以去掉-h。 16 | 如果是默认端口,可以去掉--port。 17 | 如果想导出所有数据库,可以去掉-d。 18 | 如果不指定-o,文件备份在当前目录下 19 | 20 | 2. 导出所有数据库 21 | 22 | ``` 23 | mongodump 24 | 25 | ``` 26 | 27 | 3. 导出指定数据库 28 | 29 | ``` 30 | mongodump -h 192.168.1.108 -d movie 31 | ``` 32 | 33 | 导出后会在当前的bin目录下生成一个dump的文件夹,里面就是备份的数据打包上传到服务器等待恢复 34 | 35 | 36 | ## mongorestore还原数据库 37 | 38 | > 注意事项 mongorestore 并不是在mongo shell里执行 39 | 40 | 可以执行查看命令在哪 41 | ``` 42 | root@:~# whereis mongorestore 43 | mongorestore: /usr/bin/mongorestore /usr/share/man/man1/mongorestore.1.gz 44 | ``` 45 | 然后 46 | ``` 47 | cd /usr/bin 48 | ``` 49 | 1. 常用命令格式 50 | ``` 51 | mongorestore -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 --drop 文件存在路径 52 | ``` 53 | 54 | 55 | --drop的意思是,先删除所有的记录,然后恢复。 56 | 57 | 2. 恢复所有数据库到mongodb中 58 | ``` 59 | root@bin:# mongorestore /root/dump/myblog/ #这里的路径是所有库的备份路径 60 | ``` 61 | 62 | 63 | 3. 还原指定的数据库 64 | ``` 65 | root@bin:# mongorestore -d movie /root/dump/myblog/movie/ #movie这个数据库的备份路径 66 | 67 | root@bin:# mongorestore -d movie_new /root/dump/myblog/movie/ #将movie还有movie_new数据库中 68 | ``` 69 | 70 | 这二个命令,可以实现数据库的备份与还原,文件格式是json和bson的。无法指写到表备份或者还原。`mongoexport` 和`mongoimport`实现表的导入导出。 -------------------------------------------------------------------------------- /db/mongoose多条件模糊查询.md: -------------------------------------------------------------------------------- 1 | # mongoose多条件模糊查询 2 | 3 | 这是今天手头项目中遇到的一个问题,关于mongoose如何实现类似于SQL中 nick LIKE '%keyword%' or email LIKE '%keyword%' 这种多条件模糊搜索的问题。 查阅了mongoose文档才得以实现,特此记录一下。 4 | 5 | [mongodb文档](https://docs.mongodb.com/manual/reference/operator/query/regex/) 6 | 7 | [mongoose文档](http://www.nodeclass.com/api/mongoose.html#index_Mongoose-Document) 8 | 9 | 主要用到了query.$or和query.$regex这两个find参数。 10 | 11 | 其中query.$or用于实现多条件查询,其值是一个数组。[相关文档](http://www.nodeclass.com/api/mongoose.html#query_Query-or) 12 | 13 | 示例代码: 14 | ``` 15 | query.or([{ color: 'red' }, { status: 'emergency' }]) 16 | ``` 17 | query.$regex用于实现模糊查询。[相关文档](http://www.nodeclass.com/api/mongoose.html#query_Query-regex) 18 | 19 | 示例代码: 20 | 21 | ``` 22 | { : { $regex: /pattern/, $options: '' } } 23 | { : { $regex: 'pattern', $options: '' } } 24 | { : { $regex: /pattern/ } } 25 | ``` 26 | 通过以上两个参数就可以实现多条件模糊查询了。以User表为例,通过输入一个关键字,来匹配昵称或者邮箱与关键字相近的记录。 27 | 28 | 示例代码: 29 | ``` 30 | const keyword = this.params.keyword //从URL中传来的 keyword参数 31 | const reg = new RegExp(keyword, 'i') //不区分大小写 32 | const result = yield User.find( 33 | { 34 | $or : [ //多条件,数组 35 | {nick : {$regex : reg}}, 36 | {email : {$regex : reg}} 37 | ] 38 | }, 39 | { 40 | password : 0 // 返回结果不包含密码字段 41 | }, 42 | { 43 | sort : { _id : -1 },// 按照 _id倒序排列 44 | limit : 100 // 查询100条 45 | } 46 | ) 47 | ``` 48 | 实例代码 49 | ``` 50 | var local = require('./models/local') 51 | 52 | app.get('/local/repeat', function (req, res) { 53 | var keyword = req.query.keyword // 获取查询的字段 54 | 55 | var _filter={ 56 | $or: [ // 多字段同时匹配 57 | {cn: {$regex: keyword}}, 58 | {key: {$regex: keyword, $options: '$i'}}, // $options: '$i' 忽略大小写 59 | {en: {$regex: keyword, $options: '$i'}} 60 | ] 61 | } 62 | var count = 0 63 | local.count(_filter, function (err, doc) { // 查询总条数(用于分页) 64 | if (err) { 65 | console.log(err) 66 | } else { 67 | count = doc 68 | } 69 | }) 70 | 71 | local.find(_filter).limit(10) // 最多显示10条 72 | .sort({'_id': -1}) // 倒序 73 | .exec(function (err, doc) { // 回调 74 | if (err) { 75 | console.log(err) 76 | } else { 77 | res.json({code: 0, data: doc, count: count}) 78 | } 79 | }) 80 | }) 81 | ``` 82 | local.js 83 | ``` 84 | var mongoose = require('./db.js'), 85 | Schema = mongoose.Schema; 86 | 87 | var LocalSchema = new Schema({ 88 | key : { type: String }, //变量 89 | en: {type: String}, //英文 90 | cn: {type: String}, //中文 91 | tn : { type: String} //繁体 92 | }); 93 | 94 | module.exports = mongoose.model('Local',LocalSchema); 95 | ``` 96 | db.js 97 | ``` 98 | var mongoose = require('mongoose'); 99 | mongoose.connect('mongodb://localhost/test'); 100 | var db = mongoose.connection; 101 | db.on('error', console.error.bind(console, 'connection error:')); 102 | db.once('open', function (callback) { 103 | // yay! 104 | }); 105 | module.exports = mongoose; 106 | ``` -------------------------------------------------------------------------------- /dev-tools/chrome跨域启动.md: -------------------------------------------------------------------------------- 1 | 跨域的解决办法有很多 2 | 这里先来个简单暴力一劳永逸的办法 3 | 1.找到chrome的安装目录chrome.exe新建快捷方式 4 | 2.重命名快捷方式`跨域.exe`右键属性 目标 加入参数` --disable-web-security` 记得前面空格 5 | 3.快捷方式发送到桌面 6 | 7 | > 关闭所有chrome然后启动`跨域.exe` 会提示 您使用的是不受支持的命令行标记disable-web-security 安全和稳定性有所下降 8 | 9 | 这样你就有了一个支持跨域的chrome -------------------------------------------------------------------------------- /dev-tools/git.md: -------------------------------------------------------------------------------- 1 | 这段时间一直在自学前端框架,做了很多小东西,眼看着自己的github也在不断的变绿,没想到人的满足感竟然被这一面墙的绿格子所驯服 2 | 3 | 满屏的深绿估计是很多人炫耀的资本,本人不是什么大牛,不过自己辛辛苦苦一行一行调试好了,最后连这点炫耀的记录都不给显示!!git你要翻天啊! 4 | 5 | 本来想着就这几天的,没了自己认倒霉,可是今天一搜索,没想到是可以恢复的,太NM的神奇了,一下是我查询到的恢复github commits记录及统计的办法 6 | 7 | 首先要分析为什么你的提交记录没有被github识别: 8 | 9 | 进行Commits的用户没有被关联到你的Github帐号中。 10 | 11 | 不是在这个版本库的默认分支进行的Commit。 12 | 13 | 这个仓库是一个Fork仓库,而不是独立仓库。 14 | 15 | 我估计很多人和我一样都是第一个原因,初用github远程管理代码和那些经常更换使用机器的猿极有可能用错账户名和邮箱,其实我在修改自己的原来的用户名和邮箱是就发现, 16 | 17 | 当初设置的用户名竟然是自己的密码。。。。用户名是邮箱,但是为什么平时可以正常提交呢。。。想想才反应过来,我都不用bash去push,而是在git的图形工具里进行diff和push, 18 | 19 | 那就难怪了,在GUI里,一般都是默认提交时输入邮箱和密码的,这里又有一个坑,我每次都是在用户那一个alert里输入自己的邮箱,然后是密码,这里要说,如果你输入邮箱, 20 | 21 | 就一定要注意你的这个提交账户和简历repo的账户名要关联,不然够呛了,你辛辛苦苦改了几个月发现那个炫富的绿墙里什么鬼都没有,呵呵 22 | 23 | 至于下面的两个原因应该在多人合作开发中会遇到吧 24 | 25 | 下面是解决的办法: 26 | 27 | 这是github官方的办法,全英文 28 | 29 | https://help.github.com/articles/changing-author-info/ 30 | 31 | 然后我一直在疑惑里面说的那个script在哪里,后来在另外一个大侠那里找到答案了。。。那块被墙了。。。对,那块代码在天朝看不到 32 | 33 | ## 开始 34 | 然后在bash里执行如下代码,user替换成你的github账户名,repo.git替换成你的repo的名字 35 | ``` 36 | git clone --bare https://github.com/user/repo.git 37 | cd repo.git 38 | ``` 39 | ## 复制粘贴脚本,并根据你的信息修改以下变量:旧的Email地址,正确的用户名,正确的邮件地址 40 | 41 | ``` 42 | #!/bin/sh 43 | git filter-branch --env-filter ' 44 | OLD_EMAIL="旧的Email地址" 45 | CORRECT_NAME="正确的用户名" 46 | CORRECT_EMAIL="正确的邮件地址" 47 | if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ] 48 | then 49 | export GIT_COMMITTER_NAME="$CORRECT_NAME" 50 | export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL" 51 | fi 52 | if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ] 53 | then 54 | export GIT_AUTHOR_NAME="$CORRECT_NAME" 55 | export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL" 56 | fi 57 | ' --tag-name-filter cat -- --branches --tags 58 | ``` 59 | 60 | 按 Enter键 执行脚本。 61 | 用git log命令看看新 Git 历史有没有错误 62 | ## 把正确历史 push 到 Github 63 | ``` 64 | git push --force --tags origin 'refs/heads/*' 65 | ``` 66 | 删掉刚刚临时创建的 clone 67 | ``` 68 | cd .. 69 | rm -rf repo.git 70 | ``` 71 | 72 | ## 接下来全局设置好你的正确信息,以后就放心的用Github进行版本管理吧 ^_^ 73 | ``` 74 | git config --global user.email "你的邮件地址" 75 | git config --global user.name "你的Github用户名" 76 | ``` 77 | 78 | ## 如果后面出现无法push的情况 79 | ``` 80 | git pull origin master --allow-unrelated-histories 81 | # 或者 82 | git commit -a 83 | ``` -------------------------------------------------------------------------------- /dev-tools/nginx.md: -------------------------------------------------------------------------------- 1 | 环境:ubuntu 16.04 2 | nginx 最新版本 3 | 4 | 提示错误: 5 | Starting nginx (via systemctl): nginx.serviceJob for nginx.service failed because the control process exited with error code. See "systemctl status nginx.service" and "journalctl -xe" for details. 6 | 7 | 解决方案1: 8 | systemctl status nginx.service可以看到具体的错误是什么 9 | 10 | 得到错误: 11 | Failed to start A high performance web server and a reverse proxy server 12 | 13 | I am running nginx on Raspbian Jessie operating system. 14 | 15 | I just created new virtual host and reloaded nginx service: 16 | ``` 17 | /etc/init.d/nginx restart 18 | ``` 19 | Now I got: 20 | ``` 21 | [....] Reloading nginx configuration (via systemctl): nginx.serviceJob for nginx.service failed. See 'systemctl status nginx.service' and 'journalctl -xn' for details. 22 | failed! 23 | ``` 24 | 25 | Turns out I can test if the configuration file is OK with: 26 | ``` 27 | nginx -t -c /etc/nginx/nginx.conf 28 | ``` 29 | This time it says: 30 | ``` 31 | nginx: [emerg] could not build the server_names_hash, you should increase server_names_hash_bucket_size: 32 32 | nginx: configuration file /etc/nginx/nginx.conf test failed 33 | ``` 34 | Lets check what this setting is in config: 35 | ``` 36 | grep server_names_hash_bucket_size /etc/nginx/nginx.conf 37 | ``` 38 | 39 | And it says that it is not configured: 40 | ``` 41 | # server_names_hash_bucket_size 64; 42 | ``` 43 | OK lets increase this as it says: 44 | ``` 45 | sed -i "s/^.*server_names_hash_bucket_size..*; 46 | $/server_names_hash_bucket_size 64;/" /etc/nginx/nginx.conf 47 | ``` 48 | 49 | Check again: 50 | ``` 51 | grep server_names_hash_bucket_size /etc/nginx/nginx.conf 52 | ``` 53 | 54 | Its good now: 55 | ``` 56 | server_names_hash_bucket_size 64; 57 | ``` 58 | 59 | Lets test config file: 60 | ``` 61 | nginx -t -c /etc/nginx/nginx.conf 62 | ``` 63 | 64 | This now says: 65 | ``` 66 | nginx: the configuration file /etc/nginx/nginx.conf syntax is ok 67 | nginx: configuration file /etc/nginx/nginx.conf test is 68 | successful 69 | ``` 70 | 71 | Got to go: 72 | ``` 73 | /etc/init.d/nginx restart 74 | ``` -------------------------------------------------------------------------------- /dev-tools/npm.md: -------------------------------------------------------------------------------- 1 | 在执行 npm install时,出现如下错误 2 | 3 | npm ERR! phantomjs-prebuilt@2.1.14 install: `node install.js` 4 | 5 | npm ERR! Exit status 1 6 | 7 | npm ERR! 8 | 9 | npm ERR! Failed at the phantomjs-prebuilt@2.1.14 install script 'node install.js 10 | 应该在命令后加参数 --ignore-scripts 11 | 12 | npm install --ignore-scripts 13 | 14 | 15 | 16 | 如果觉得安装速度慢,安装源和原来 npm 是一样的,可以通用,修改方法如下: 17 | 18 | yarn config get registry 19 | # -> https://registry.yarnpkg.com 20 | 可以改成 taobao 的源: 21 | 22 | yarn config set registry https://registry.npm.taobao.org 23 | # -> yarn config v0.15.0 24 | # -> success Set "registry" to "https://registry.npm.taobao.org". 25 | # -> Done in 0.04s. 26 | 27 | 28 | ***一定注意源地址不能带引号 29 | 30 | 31 | # npm 报发布注意事项 32 | 33 | 1.如果使用了淘宝源 要切回到默认的npm源 建议使用mrn切换 34 | 35 | 2.如果发布包的时候提示权限不足(windows) 请使用管理员权限打开cmd 登录npm 36 | ``` 37 | npm login 38 | ``` -------------------------------------------------------------------------------- /dev-tools/nrm.md: -------------------------------------------------------------------------------- 1 | nrm 镜像源 2 | 3 | ``` 4 | $ nrm -h 5 | 6 | Usage: cli [options] [command] 7 | 8 | 9 | Options: 10 | 11 | -V, --version output the version number 12 | -h, --help output usage information 13 | 14 | 15 | Commands: 16 | 17 | ls List all the registries 18 | current Show current registry name 19 | use Change registry to registry 20 | add [home] Add one custom registry 21 | del Delete one custom registry 22 | home [browser] Open the homepage of registry with optional browser 23 | test [registry] Show response time for specific or all registries 24 | help Print this help 25 | 26 | ``` -------------------------------------------------------------------------------- /dev-tools/vscode.md: -------------------------------------------------------------------------------- 1 | 解决vscode格式化代码时自动把''变成"" 并加上了; 2 | 3 | 4 | 将 "vetur.format.defaultFormatter.ts": "prettier", 5 | 6 | 更改为下面的 7 | 8 | "vetur.format.defaultFormatter.js": "vscode-typescript" 9 | 10 | 可以解决 -------------------------------------------------------------------------------- /dev-tools/vue-pracel试玩.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | github https://github.com/parcel-bundler/parcel?utm_source=gold_browser_extension 3 | 4 | 5 | 首先通过 Yarn 或者 npm 安装 Parcel : 6 | ``` 7 | npm install -g parcel-bundler 8 | ``` 9 | 10 | 在你正在使用的项目目录下创建一个 package.json 文件: 11 | 12 | ``` 13 | npm init -y 14 | ``` 15 | 我用的原来项目的package.json 16 | 加入或修改原来的script 17 | ``` 18 | "dev2": "parcel index.html", 19 | "build2": "parcel build index.html --public-url /" 20 | ``` 21 | 22 | # 安装依赖 23 | ``` 24 | npm i parcel-bundler parcel-plugin-vue babel-preset-env --dev 25 | ``` 26 | 其中parcel-bundler是主要的工具,对于vue结尾的单文件,需要单独处理文件类型, 27 | parcel-plugin-vue这个插件会通过vueify来生成对应的代码,parcel会自动加载parcel-plugin开头的依赖。 28 | 29 | # 配置.babelrc 30 | ``` 31 | { 32 | "presets": [ 33 | ["env"] 34 | ] 35 | } 36 | 37 | ``` 38 | # 配置postcss.config.js 39 | ``` 40 | // postcss.config.js 41 | module.exports = { 42 | plugins: [ 43 | require('autoprefixer')({ 44 | browsers: [ 45 | 'last 20 versions', 46 | 'IE 9', 47 | 'iOS >= 8' 48 | ] 49 | }) 50 | ] 51 | } 52 | 53 | ``` 54 | # index.html引入 入口js 55 | ``` 56 | 57 |
58 | 59 | 60 | 61 | ``` 62 | # 运行 63 | ``` 64 | npm run dev2 65 | ``` -------------------------------------------------------------------------------- /electron-vue初体验.md: -------------------------------------------------------------------------------- 1 | # electron-vue 初体验 2 | 3 | ## 注意事项 4 | * 首先确保node和npm是最新版本 5 | 6 | 避免使用镜像(我淘宝镜像安装有报错现象) 7 | * 避免window的一些坑 8 | 9 | 若上一项检查完成,我们可以继续设置所需的构建工具。使用 [windows-build-tools](https://github.com/felixrieseberg/windows-build-tools) 来为我们完成大部分烦人的工作。全局安装此工具将依次设置 Visual C++ 软件包、Python 等等。(安装时间可能会很久) 10 | ``` 11 | npm install --global --production windows-build-tools 12 | ``` 13 | 到现在为止,所有工具都应该成功安装了,如果没有,那么你就会需要安装一个干净的 Visual Studio。请注意,这些并不是 electron-vue 自身的问题 (Windows 有时候可能会很难用 ¯\_(ツ)_/¯)。 14 | 15 | > 该样板代码被构建为 vue-cli 的一个模板,并且包含多个选项,可以自定义你最终的脚手架程序。本项目需要使用 node@^7 或更高版本。electron-vue 官方推荐 yarn 作为软件包管理器,因为它可以更好地处理依赖关系,并可以使用 yarn clean 帮助减少最后构建文件的大小。 16 | 17 | ``` 18 | # 安装 vue-cli 和 脚手架样板代码 19 | npm install -g vue-cli 20 | vue init simulatedgreg/electron-vue my-project 21 | 22 | # 安装依赖并运行你的程序 23 | cd my-project 24 | yarn # 或者 npm install 25 | yarn run dev # 或者 npm run dev 26 | ``` 27 | 到此为止项目已经可以跑起来了(真正自己动手的时候可能远没有你看起来的那么容易,各种环境问题都会是绊脚石) 28 | 29 | 30 | -------------------------------------------------------------------------------- /fn-tools/常见html正则操作.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 一个在线正则表达式验证网站 4 | http://regex.zjmainstay.cn/ 5 | 6 | ## 去除回车换行 7 | ``` 8 | function getText(str) { 9 | var resultStr = str.replace(/\ +/g, "") // 去掉空格 10 | resultStr = str.replace(/[ ]/g, "") // 去掉空格 11 | resultStr = str.replace(/[\r\n]/g, "") // 去掉回车换行 12 | return resultStr 13 | } 14 | ``` 15 | ## 去掉html 标签 16 | ``` 17 | function delHtmlTag(str) { 18 | return str.replace(/<[^>]+>/g, '') // 去掉所有的html标记 19 | } 20 | ``` 21 | 22 | ## 去掉html 特定属性 23 | 如 `
` 中的`width=500` 24 | ``` 25 | str.replace(/\s+width="[^"]*"/ig,'') 26 | ``` -------------------------------------------------------------------------------- /js/js常见位运算.md: -------------------------------------------------------------------------------- 1 | 我们可能很少在编程中用位运算,如果没深入学习,可能也很难理解。平时的数值运算,其实是要先转换成二进制再进行运算的,而位运算就是直接进行二进制运算,所以位运算的执行效率肯定是更高的。下面通过一些实例来加深对位运算的理解。 2 | 3 | ## 按位与(&) 4 | 5 | &&运算符我们都知道,只有两个都为真,结果才为真。&道理是一样的,只有两个数的值为1时,才返回1。例如1和3的按位与操作: 6 | ``` 7 | 0001 8 | & 0011 9 | --------- 10 | 0001 11 | ``` 12 | 只有对应的数为1时,结果才为1,其他都为0。 13 | 判断一个数是奇数还是偶数,我们会用求余数来判断: 14 | ``` 15 | function assert(n) { 16 | if (n % 2 === 1) { 17 | console.log("n是奇数"); 18 | } else { 19 | console.log("n是偶数"); 20 | } 21 | } 22 | 23 | assert(3); // "n是奇数" 24 | ``` 25 | 我们也可以用一个数和1进行按位&操作来判断,而且速度更快: 26 | ``` 27 | function assert(n) { 28 | if (n & 1) { 29 | console.log("n是奇数"); 30 | } else { 31 | console.log("n是偶数"); 32 | } 33 | } 34 | 35 | assert(3); // "n是奇数" 36 | ``` 37 | 下面是位运算过程: 38 | ``` 39 | 1 = 0001 40 | 3 = 0011 41 | -------- 42 | & = 0001 43 | ``` 44 | 奇数的二进制码的最后一位数肯定是1,而1只有最后一位为1,按位&操作之后,结果肯定只有最后一位数为1。而偶数的二进制表示的最后一位数是0,和1进行按位&操作,结果所有位数都为0。 45 | 46 | ## 按位或(|) 47 | 48 | |与||操作符的道理也是一样的,只要两个数中有一个数为1,结果就为1,其他则为0。 49 | ``` 50 | 0001 51 | | 0011 52 | --------- 53 | 0011 54 | ``` 55 | 对浮点数向下求整,我们会用下面的方法: 56 | ``` 57 | var num = Math.floor(1.1); // 1 58 | ``` 59 | 我们也可以用位运算来求整: 60 | ``` 61 | var num = 1.1 | 0; // 1 62 | ``` 63 | 其实浮点数是不支持位运算的,所以会先把1.1转成整数1再进行位运算,就好像是对浮点数向下求整。所以1|0的结果就是1。 64 | 65 | ## 按位非(~) 66 | 67 | 按位非就是求二进制的反码: 68 | ``` 69 | var num = 1; // 二进制 00000000000000000000000000000001 70 | var num1 = ~num; // 二进制 11111111111111111111111111111110 71 | ``` 72 | 我们知道,js中的数字默认是有符号的。有符号的32位二进制的最高位也就是第一位数字代表着正负,1代表负数,0代表整数。那到底11111111111111111111111111111110等于多少呢?最高位为1代表负数,负数的二进制转化为十进制:符号位不变,其他位取反加1。取反之后为10000000000000000000000000000001,加1之后为10000000000000000000000000000010,十进制为-2。 73 | 74 | ## 按位异或(^) 75 | 76 | 按位异或是两个数中只有一个1时返回1,其他情况返回0。 77 | ``` 78 | 0001 79 | ^ 0011 80 | --------- 81 | 0010 82 | ``` 83 | 数字与数字本身按位异或操作得到的是0,因为每两个对应的数字都相同,所以最后返回的都是0。 84 | 85 | 我们经常会需要调换两个数字的值: 86 | ``` 87 | var num1 = 1, num2 = 2, temp; 88 | temp = num1; 89 | num1 = num2; // 2 90 | num2 = temp; // 1 91 | ``` 92 | 如果装逼一点的话,可以这样: 93 | ``` 94 | var num1 = 1, num2 = 2; 95 | num1 = [num2, num2 = num1][0]; 96 | console.log(num1); // 2 97 | console.log(num2); // 1 98 | ``` 99 | 如果想再装的稳一点的话,可以这样: 100 | ``` 101 | var num1 = 1, num2 = 2; 102 | num1 ^= num2; // num1 = num1 ^ num2 = 1 ^ 2 = 3 103 | num2 ^= num1; // num2 = num2 ^ (num1 ^ num2) = 2 ^ (1 ^ 2) = 1 104 | num1 ^= num2; // num1 = num1 ^ num2 = 3 ^ 1 = 2 105 | console.log(num1); // 2 106 | console.log(num2); // 1 107 | ``` 108 | ## 有符号左移(<<) 109 | 110 | 有符号左移会将32位二进制数的所有位向左移动指定位数。如: 111 | ``` 112 | var num = 2; // 二进制10 113 | num = num << 5; // 二进制1000000,十进制64 114 | ``` 115 | 如果要求2的n次方,可以这样: 116 | ``` 117 | function power(n) { 118 | return 1 << n; 119 | } 120 | 121 | power(5); // 32 122 | ``` 123 | 1的二进制是01,左移5位就是0100000,十进制就是2的5次方32。 124 | 125 | ## 有符号右移(>>) 126 | 127 | 有符号右移会将32位二进制数的所有位向右移动指定位数。如: 128 | ``` 129 | var num = 64; // 二进制1000000 130 | num = num >> 5; // 二进制10,十进制2 131 | ``` 132 | 求一个数的二分之一: 133 | ``` 134 | var num = 64 >> 1; // 32 135 | var num = 5 >> 1; // 2 小数同样会向下取整 136 | ``` 137 | 有符号左移与右移不会影响符号位。 138 | 139 | ## 无符号右移(>>>) 140 | 141 | 正数的无符号右移与有符号右移结果是一样的。负数的无符号右移会把符号位也一起移动,而且无符号右移会把负数的二进制码当成正数的二进制码: 142 | ``` 143 | var num = -64; // 11111111111111111111111111000000 144 | num = num >>> 5; // 134217726 145 | ``` 146 | 所以,我们可以利用无符号右移来判断一个数的正负: 147 | ``` 148 | function isPos(n) { 149 | return (n === (n >>> 0)) ? true : false; 150 | } 151 | 152 | isPos(-1); // false 153 | isPos(1); // true 154 | ``` 155 | -1>>>0虽然没有向右移动位数,但-1的二进制码已经变成了正数的二进制码: 156 | 157 | 11111111111111111111111111111111 158 | 所以-1>>>0的值为4294967295。 159 | 160 | ## 总结 161 | 162 | 以上的例子在平常可能会比较容易用到或看到,也是属于比较容易理解的。一些比较复杂的、难理解的,我觉得应该尽量少用,因为会给阅读者带来困难,也会给自己带来麻烦。 163 | 164 | ## 例题 165 | 166 | 判断一个字符串是否是镜像字符串 如:abcba 167 | ``` 168 | function mirror (str) { 169 | const length = str.length >> 1 170 | for (let i = 0; i < length; i++) { 171 | if (str[i] !== str[str.length - 1 - i]) return false 172 | } 173 | rturn true 174 | } 175 | ``` -------------------------------------------------------------------------------- /js/js生成重复字符串.md: -------------------------------------------------------------------------------- 1 | 需求: 2 | 我司对其客户公司有设备维修记录文档。特定为该公司维修工程师有权查看文档全部信息 其他工程可查看不敏感信息学习操作流程 3 | 因此对文本私密信息(无权限查看的)转义成符号 4 | 如:一篇内部技术文档中的账号和密码 5 | ``` 6 | function repeatStr(str,len){ 7 | return new Array(len+1).join(str) 8 | } 9 | // repeatStr('*',10) 10 | // "*********" 11 | ``` 12 | 在python你直接 print('*'*10) -------------------------------------------------------------------------------- /js/js题.md: -------------------------------------------------------------------------------- 1 | # 题1 2 | ``` 3 | var Foo = function () { 4 | getName = function () { 5 | console.log(111) 6 | } 7 | return this 8 | } 9 | Foo.prototype.getName = function () { 10 | console.log(222) 11 | } 12 | var getName = function () { 13 | console.log(333) 14 | } 15 | function getName () { 16 | console.log(444) 17 | } 18 | Foo.getName = function () { 19 | console.log(555) 20 | } 21 | getName() 22 | Foo().getName() 23 | Foo.getName() 24 | new Foo().getName() 25 | ``` 26 | ## 分析 27 | 28 | ``` 29 | 第一个getName() 只会去下面两个函数里面找 30 | var getName = function () { 31 | console.log(333) 32 | } 33 | function getName () { 34 | console.log(444) 35 | } 36 | 由于函数声明由于变量(变量提升同名的函数先提升) 37 | 所以先提升的函数被后面的变量覆盖了 结果333 38 | 39 | 第二个Foo().getName() 40 | 我的第一时间认为也是 333 41 | 因为Foo()调用返回的this是window 42 | 而我任务window下还是第一个上面的两个getName 43 | 其实Foo()调用后window下生成一个全局的 44 | getName = function () { 45 | console.log(111) 46 | } 47 | 所以结果 111 48 | 第三个Foo.getName() 49 | 乍一看如下3个都是 50 | var Foo = function () { 51 | getName = function () { 52 | console.log(111) 53 | } 54 | return this 55 | } 56 | Foo.prototype.getName = function () { 57 | console.log(222) 58 | } 59 | Foo.getName = function () { 60 | console.log(555) 61 | } 62 | 第一个函数Foo 结果为 63 | function () { 64 | getName = function () { 65 | console.log(111) 66 | } 67 | return this 68 | } 69 | 是个函数根本没法.getName 70 | 第二个 Foo.prototype.getName = function () { 71 | console.log(222) 72 | } 73 | 只能通过new Foo().getName()获取 74 | 所以结果555 75 | 最后一个 222 76 | ``` 77 | # 题2 ajax的原理 手写ajax 78 | 79 | ajax的技术核心是 XMLHttpRequest 对象; 80 | ajax 请求过程:创建 XMLHttpRequest 对象、连接服务器、发送请求、接收响应数据; 81 | ``` 82 | function creatXml() { 83 | if(XMLHttpRequest){ 84 | return new XMLHttpRequest() 85 | }else{ 86 | throw new Error('浏览器不支持XHR对象!') 87 | } 88 | } 89 | function ajax(obj) { 90 | var xhr = creatXml() 91 | xhr.open("POST", url, false) 92 | xhr.onreadystatechange = function () { 93 | if (xhr.readyState == 4) { 94 | console.log('数据正在加载') 95 | if (xhr.status == 200) { 96 | document.write(xhr.responseText) 97 | } 98 | } 99 | } 100 | xmlhttp.send() 101 | } 102 | 103 | ``` -------------------------------------------------------------------------------- /js内存分配.md: -------------------------------------------------------------------------------- 1 | 原始值和引用值 2 | 在ECMAScript中,变量可以存放两种类型的值,即原始值和引用值。 3 | 原始值指的就是代表原始数据类型(基本数据类型)的值,即Undefined,Null,Number,String,Boolean类型所表示的值。 4 | 引用值指的就是复合数据类型的值,即Object,Function,Array,以及自定义对象,等等 5 | 6 | 栈和堆 7 | 与原始值与引用值对应存在两种结构的内存即栈和堆 8 | 栈是一种后进先出的数据结构,在javascript中可以通过Array来模拟栈的行为 9 | 10 | 原始值是存储在栈中的简单数据,也就是说,他们的值直接存储在变量访问的位置。 11 | 12 | 堆是基于散列算法的数据结构,在javascript中,引用值是存放在堆中的。 13 | 引用值是存储在堆中的对象,也就是说,存储在变量处的值(即指向对象的变量,存储在栈中)是一个指针,指向存储在堆中的实际对象. 14 | 例:var obj = new Object(); obj存储在栈中它指向于new Object()这个对象,而new Object()是存放在堆中的。 15 | 16 | 那为什么引用值要放在堆中,而原始值要放在栈中,不都是在内存中吗,为什么不放在一起呢?那接下来,让我们来探索问题的答案! 17 | 18 | 首先,我们来看一下代码: 19 | ``` 20 | //简单类型都放在栈(stack)里 21 | //对象类型都放在堆(heap)里 22 | function Person(id,name,age){ 23 | this.id = id; 24 | this.name = name; 25 | this.age = age; 26 | } 27 | var num = 10; 28 | var bol = true; 29 | var str = "abc"; 30 | var obj = new Object(); 31 | var arr = ['a','b','c']; 32 | var person = new Person(100,"笨蛋的座右铭",25); 33 | ``` 34 | 然后我们来看一下内存分析图: 35 | 理解js内存分配 36 | ![](md-img/_.png) 37 | 变量num,bol,str为基本数据类型,它们的值,直接存放在栈中,obj,person,arr为复合数据类型,他们的引用变量存储在栈中,指向于存储在堆中的实际对象。 38 | 由上图可知,我们无法直接操纵堆中的数据,也就是说我们无法直接操纵对象,但我们可以通过栈中对对象的引用来操作对象,就像我们通过遥控机操作电视机一样,区别在于这个电视机本身并没有控制按钮。 39 | 40 | 现在让我们来回答为什么引用值要放在堆中,而原始值要放在栈中的问题: 41 | 记住一句话:能量是守衡的,无非是时间换空间,空间换时间的问题 42 | 堆比栈大,栈比堆的运算速度快,对象是一个复杂的结构,并且可以自由扩展,如:数组可以无限扩充,对象可以自由添加属性。将他们放在堆中是为了不影响栈的效率。而是通过引用的方式查找到堆中的实际对象再进行操作。相对于简单数据类型而言,简单数据类型就比较稳定,并且它只占据很小的内存。不将简单数据类型放在堆是因为通过引用到堆中查找实际对象是要花费时间的,而这个综合成本远大于直接从栈中取得实际值的成本。所以简单数据类型的值直接存放在栈中。 -------------------------------------------------------------------------------- /learnEnglish.md: -------------------------------------------------------------------------------- 1 | ## 2017年11月15日20:49:13 2 | 重点词汇 3 | come up with 提出;想出;赶上 4 | execution n. 执行,实行;完成;死刑 5 | delivery n. [贸易] 交付;分娩;递送 6 | 7 | “Coming up with an idea is the least important part of creating something great. It has to be the right idea and have good taste, but the execution and delivery are what's key.” 8 | 9 | – Sergey Brin, Google Co-Founder 10 | 「在建构伟大事物的过程里,构想是最不重要的成分,它必须是正确的想法以及好的理念,但执行与完成才是关键。」–谢尔盖·布林 (Google 共同创办人) 11 | -------------------------------------------------------------------------------- /lession1.md: -------------------------------------------------------------------------------- 1 | # 环境 2 | 3 | ## 安装架手架 4 | ``` 5 | npm i -g create-react-app 6 | ``` 7 | ## 创建名为geek的项目 8 | ``` 9 | create-react-app geek 10 | cd geek 11 | npm start // 如果端口冲突 scripts -> start.js 修改port 12 | ``` 13 | ## 安装第三方库redux 14 | ``` 15 | npm i redux -S 16 | ``` 17 | ## 自定义配置文件 18 | ``` 19 | npm run eject 20 | ``` 21 | ## 目录结构 22 | ``` 23 | │ .gitignore 24 | │ lesson.md 25 | │ package.json 26 | │ README.md 27 | │ tree.text 28 | │ tree.txt 29 | │ yarn.lock 30 | │ 31 | ├─config 32 | │ │ env.js 33 | │ │ paths.js 34 | │ │ polyfills.js 35 | │ │ webpack.config.dev.js 36 | │ │ webpack.config.prod.js 37 | │ │ webpackDevServer.config.js 38 | │ │ 39 | │ └─jest 40 | │ cssTransform.js 41 | │ fileTransform.js 42 | │ 43 | ├─node_modules 44 | │ ... 45 | │ 46 | ├─public 47 | │ favicon.ico 48 | │ index.html 49 | │ manifest.json 50 | │ 51 | ├─scripts 52 | │ build.js 53 | │ start.js 54 | │ test.js 55 | │ 56 | └─src 57 | App.css 58 | App.js 59 | App.test.js 60 | index.css 61 | index.js 62 | logo.svg 63 | registerServiceWorker.js 64 | ``` 65 | 66 | ## 更新react到最新版本 67 | 68 | ``` 69 | npm install react@next react-dom@next 70 | ``` 71 | 72 | ## 安装antd-mobile 73 | 74 | ``` 75 | npm install antd-mobile@next --save 76 | ``` 77 | 忍无可忍的安装速度 78 | 下载nrm插件 79 | ``` 80 | npm install nrm -g 81 | ``` 82 | ``` 83 | $ nrm ls 84 | 85 | * npm ----- https://registry.npmjs.org/ 86 | cnpm ---- http://r.cnpmjs.org/ 87 | taobao -- https://registry.npm.taobao.org/ 88 | nj ------ https://registry.nodejitsu.com/ 89 | rednpm -- http://registry.mirror.cqupt.edu.cn 90 | skimdb -- https://skimdb.npmjs.com/registry 91 | ``` 92 | ``` 93 | $ nrm test 94 | 95 | * npm ---- 702ms 96 | cnpm --- 272ms 97 | taobao - 3124ms 98 | nj ----- Fetch Error 99 | rednpm - Fetch Error 100 | npmMirror 1359ms 101 | edunpm - Fetch Error 102 | // 什么鬼 103 | ``` 104 | ``` 105 | $ nrm use cnpm //switch registry to cnpm 106 | 107 | Registry has been set to: http://r.cnpmjs.org/ 108 | ``` 109 | 110 | ## 按需加载 111 | ``` 112 | npm install babel-plugin-import -D 113 | ``` 114 | 在package.json-> babel对象里加如下一项 115 | ``` 116 | "plugins": [["import", { "libraryName": "antd-mobile", "style": "css" }]] 117 | ``` 118 | 这样就可以直接 119 | ``` 120 | import { Button } from 'antd-mobile' 121 | ``` 122 | ## 如果是vs code编辑器要支持emmet语法 可以点设置->"emmet.triggerExpansionOnTab": true 123 | 124 | ## 安装状态管理redux 125 | ``` 126 | npm install redux -S 127 | ``` 128 | ## redux处理异步插件 redux-thunk 129 | ``` 130 | npm install redux-thunk -S 131 | ``` 132 | 使用applyMiddleware开启redux-thunk插件 133 | index.js 134 | ``` 135 | import {creatStore,applyMiddleware} form 'redux' 136 | import thunk form 'redux-thunk' 137 | const store = createStore(reducer,applyMiddleware(thunk)) 138 | ``` 139 | ## 加入redux调试工具chrome下载扩展应用 reduxDevtoolsExtension 140 | index.js 141 | ``` 142 | /* applyMiddleware 应用中间件的函数 compose组合函数*/ 143 | import { createStore, applyMiddleware,compose } from 'redux' 144 | import thunk from 'redux-thunk' 145 | import reducer from 'store/reducer' 146 | import './index.css'; 147 | import App from './App'; 148 | import registerServiceWorker from './registerServiceWorker'; 149 | const store =createStore(reducer,compose( 150 | applyMiddleware(thunk), 151 | window.devToolsExtension?window.devToolsExtension():()=>{} // 检查浏览器是否有插件,没有就传个空函数 152 | )) 153 | ``` 154 | ## 安装 react-redux 优雅的链接react和redux 155 | ``` 156 | npm install react-redux -S 157 | ``` 158 | index.js 引入 Provider 组件 159 | ``` 160 | import {Provider} from 'react-redux' 161 | //使用 162 | ReactDOM.render( 163 | ( 164 | 165 | ), 166 | document.getElementById('root') 167 | ); 168 | registerServiceWorker(); 169 | ``` 170 | ## 安装npm install babel-plugin-transform-decorators-le 171 | gacy -D 172 | 让redux支持装饰器 173 | package.json按照插件名加入配置 174 | ## 安装 react-router4 175 | ``` 176 | npm install react-router-dom 177 | ``` 178 | index.js 179 | ``` 180 | import {BrowerRouter,Route,Link} from 'react-router-dom' 181 | // BrowerRouter 包裹整个应;可以用this.props访问到路由对象 182 | ReactDOM.render( 183 | ( 184 | 185 | 186 | 187 | ), 188 | document.getElementById('root') 189 | ); 190 | ``` 191 | -------------------------------------------------------------------------------- /lession2.md: -------------------------------------------------------------------------------- 1 | # 开发 2 | 3 | ## 新建anthroute 4 | index.js 5 | ``` 6 | import React from 'react'; 7 | import ReactDOM from 'react-dom'; 8 | /* applyMiddleware 应用中间件的函数 compose组合函数*/ 9 | import {createStore, applyMiddleware, compose} from 'redux' 10 | import {Provider} from 'react-redux' 11 | import {BrowserRouter, Route} from 'react-router-dom' 12 | import thunk from 'redux-thunk' 13 | import reducers from './reducer' 14 | import './index.css'; 15 | // import App from './App'; 16 | import Login from './views/login/login.js' 17 | import Signup from './views/signup/signup.js' 18 | import AuthRoute from './components/authroute/authroute' 19 | import registerServiceWorker from './registerServiceWorker'; 20 | 21 | const store = createStore(reducers, compose( 22 | applyMiddleware(thunk), 23 | window.devToolsExtension ? window.devToolsExtension() : f => f 24 | )) 25 | console.log('123', reducers) 26 | 27 | // BrowserRouter 包裹整个应用 28 | ReactDOM.render( 29 | ( 30 | 31 | 32 |
33 | 34 | 35 | 36 |
37 |
38 |
39 | ), 40 | document.getElementById('root') 41 | ); 42 | registerServiceWorker(); 43 | 44 | ``` 45 | authroute.js 46 | ``` 47 | import React from 'react' 48 | import axios form 'axios' 49 | 50 | class AuthRoute extends React.Component { 51 | compentDidMount() { 52 | axios({ 53 | url:'/api/info' 54 | }) 55 | // 获取用户信息 56 | // 用户是否登陆 57 | // 用户当前的地址是否是登录 58 | // 用户的信息是否完善 59 | // 用户是boos还是牛人 60 | } 61 | } 62 | export default AuthRoute 63 | ``` -------------------------------------------------------------------------------- /linux-ubuntu16常见问题.md: -------------------------------------------------------------------------------- 1 | # unable to resolve host iZlzadavzuzyiwZ 2 | 3 | 那么就需要修改/etc/hosts文件: 4 | 如果之前为 5 | 6 | 127.0.0.1 localhost 7 | 8 | 变更为: 9 | 10 | 127.0.0.1 localhost 11 | 127.0.1.1 hostname 12 | 13 | hostname 为主机名,查看文件:/etc/hostname 获得 -------------------------------------------------------------------------------- /md-img/_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/md-img/_.png -------------------------------------------------------------------------------- /md-img/border-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/md-img/border-img.png -------------------------------------------------------------------------------- /md-img/btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/md-img/btn.png -------------------------------------------------------------------------------- /md-img/django-progect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/md-img/django-progect.png -------------------------------------------------------------------------------- /md-img/h-w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/md-img/h-w.png -------------------------------------------------------------------------------- /md-img/myapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/md-img/myapp.png -------------------------------------------------------------------------------- /md-img/pip-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/md-img/pip-setup.png -------------------------------------------------------------------------------- /md-img/pip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artiely/notes/c05b4b30284555c2acd5338e4f661609de205a50/md-img/pip.png -------------------------------------------------------------------------------- /nuxt配置.md: -------------------------------------------------------------------------------- 1 | Nuxt 是一个基于 Vue 生态的更高层的框架,为开发服务端渲染的 Vue 应用提供了极其便利的开发体验。更酷的是,你甚至可以用它来做为静态站生成器,推荐尝试。目前Nuxt.js官方文档目前已经覆盖了大部分常用需求 , 这篇文章主要讲nuxt工程中一些需要注意的知识点,以及一些比较常用的功能介绍。 2 | 3 | 4 | 5 | 安装和部署 6 | ``` 7 | npm install -g vue-cli //安装vue-cli架子 8 | 9 | vue init nuxt-community/starter-template //安装nuxt 10 | 11 | npm run dev //开发运行, http://localhost:3000 12 | ``` 13 | 14 | 服务器部署:(需要安装node环境和pm2工具) 15 | ``` 16 | npm install pm2 -g //强大的node进程管理器 17 | 18 | npm run build 19 | 20 | npm start //需要先配置package.json,配置如下: 21 | 22 | "scripts": { 23 | "start": "pm2 start ./node_modules/nuxt/bin/nuxt-start -i max --attach",//-i max使用最大cpu核数,不需要可不取消 24 | }, 25 | //如果需要生产静态文件使用命令:npm run generate 26 | 27 | ``` 28 | 29 | nuxt.config.js的一些配置 30 | ``` 31 | head: { 32 | script: [ 33 | { src: '/' }/*外部js的引入,或者static中的js文件引入(/**.js)*/ 34 | ] 35 | }, 36 | env: { 37 | url: 'http://***.com' /*全局asyncData({env})的配置,比如请求头URL常量*/ 38 | }, 39 | /*代理IP的使用*/ 40 | proxy: [ ['/api', {target: 'http://**.com'}] ], 41 | build: { 42 | vendor: ['axios', 'qs'],/*多个地方引用,防止多次打包*/ 43 | } 44 | } 45 | //其他配置请看官网文档 46 | 47 | ``` 48 | nuxt添加静态文件 49 | 当我们在使用nuxt的时候,网站可以会遇到一部分是动态生成,而另一部分直接就是静态文件,在nuxt的文件配置下static目录,直接把文件放入static目录下,就可以通过域名或者IP(/对应的文件名)直接访问。 50 | 51 | 52 | 53 | 过滤器的使用配置 plugins/filter.js 54 | ``` 55 | import Vue from 'vue' 56 | export function trim (str) { 57 | return str.replace(/(^\s*)(\s*$)/g, '') 58 | } 59 | const filters = { 60 | trim 61 | } 62 | export default filters 63 | Object.keys(filters).forEach(key => { 64 | Vue.filter(key, filters[key]) 65 | }) 66 | ``` 67 | 使用{{string | trim}},需要在nuxt.config.js 配置 plugins: [ '~plugins/filters.js' ] 68 | 69 | 70 | 71 | 公用方法的配置 plugins/globle.js 72 | ``` 73 | import Vue from 'vue' 74 | 75 | Vue.mixin({ 76 | methods: { 77 | /* 设置标题描述 */ 78 | $setSeo (title, content) { 79 | return { title: title, meta: [ { hid: 'description', name: 'description', content: content } ] } 80 | }, 81 | } 82 | ``` 83 | 需要在nuxt.config.js 配置 plugins: [ '~plugins/globle.js' ],页面的使用方法: 84 | ``` 85 | head(){ 86 | return this.$setSeo('title','des') 87 | } 88 | ``` 89 | 90 | 中间件的使用 91 | 比如说用户未登录状态下,通过路由闯入了需要鉴权的页面,我们可以自定义一些错误: 92 | ``` 93 | // auth.js 94 | export default function ({ store, error }) { 95 | // 可通过组件的props接收error信息 96 | if (!store.state.token) { 97 | error({ 98 | message: 'cookie失效或未登录,请登录后操作', 99 | statusCode: 403 100 | }) 101 | } 102 | } 103 | ``` 104 | 在组件中使用该中间件: 105 | ``` 106 | export default { 107 | middleware: 'auth', 108 | // 还可以把用户重定位到登录页 109 | fetch ({redirect, store}) { 110 | if (!store.state.token) { 111 | redirect('/login') 112 | } 113 | }, 114 | } 115 | 116 | ``` 117 | 第三方库的引用plugins/element-ui.js 118 | 官方不屏蔽你正常的import,但有提供插件模式且推荐使用插件模式 119 | ``` 120 | import Vue from 'vue' 121 | import Element from 'element-ui' 122 | Vue.use(Element) 123 | /*nuxt.config.js配置*/ 124 | plugins: [{src: '~plugins/element-ui', ssr: true}] 125 | css: ['element-ui/lib/theme-default/index.css'] 126 | vendor: ['element-ui'] 127 | /*按需加载 在build下配置babel,安装插件babel-plugin-component*/ 128 | babel: { 129 | plugins: [['component', [ 130 | { 131 | 'libraryName': 'element-ui', 132 | 'styleLibraryName': 'theme-default' 133 | }, 134 | 'transform-async-to-generator', 135 | 'transform-runtime' 136 | ]]], 137 | comments: false 138 | } 139 | ``` 140 | 141 | Window 或 Document 对象未定义? 142 | 这是因为一些只兼容客户端的脚本被打包进了服务端的执行脚本中去。必须使用该变量process.browser,在引入的地方: 143 | ``` 144 | if (process.BROWSER_BUILD) { 145 | let lib=require('external_library') 146 | } 147 | nuxt.config.js 文件中配置 vendor 配置项 : 148 | 149 | build: { 150 | vendor: ['external_library'] 151 | } 152 | ``` -------------------------------------------------------------------------------- /pm2快速使用.md: -------------------------------------------------------------------------------- 1 | ## 介绍 2 | pm2 是一个带有负载均衡功能的Node应用的进程管理器.。它使您可以永久保持应用程序的活动状态,无需停机即可重新加载应用程序,并且可以方便常见的系统管理任务 3 | ## 特性 4 | - 行为配置 5 | - 源地图支持 6 | - 容器集成 7 | - 观看和重新加载 8 | - 日志管理 9 | - 监控 10 | - 模块系统 11 | - 最大内存重新加载 12 | - 集群模式 13 | - 热重新加载 14 | - 开发工作流程 15 | - 启动脚本 16 | - 部署工作流程 17 | - PaaS兼容 18 | - Keymetrics监测 19 | - API 20 | ## 资料 21 | [官方文档](http://pm2.keymetrics.io/docs/usage/quick-start/) 22 | ## 安装 23 | 安装最新最稳定的版本 24 | ``` 25 | npm install pm2@latest -g 26 | ``` 27 | > linux 此时执行pm2可能会提示找不到pm2命令(如果是nvm安装的node), 28 | 通过创建软链接的方法,使得在任意目录下都可以直接使用pm2命令:前面的地址是pm2安装的地方 29 | ,不知道自己装到哪里去了可以使用命令 whereis pm2 30 | ``` 31 | ln -s /root/node-v6.9.5-linux-x64/bin/pm2 /usr/local/bin/pm2 32 | ``` 33 | 34 | ## 使用 35 | ``` 36 | pm2 start ./bin/www 37 | ``` 38 | 给启动的应用加个名称便于管理 39 | ``` 40 | pm2 start ./bin/www --name myapp 41 | ``` 42 | 43 | ## 安装启动脚本 44 | ``` 45 | pm2 startup 46 | ``` 47 | > 注意:更新nodejs时,pm2二进制路径可能会更改(如果您使用nvm,它将一定会更改)。因此,我们建议您startup在更新后运行该命令 48 | 49 | ## 保存当前进程列表 50 | 一旦启动了要管理的所有应用程序,就可以通过输入以下命令将该列表保存在预期的/意外的服务器重新启动之中: 51 | ``` 52 | pm2 save 53 | ``` 54 | 它会将具有相应环境的进程列表保存到转储文件中$PM2_HOME/.pm2/dump.pm2 55 | ## 更新启动脚本 56 | 57 | 要更新启动脚本(例如,您通过NVM更改了Node.js版本),请运行以下命令: 58 | ``` 59 | pm2 unstartup 60 | pm2 startup 61 | ``` 62 | ## 查看启动的所有的程序 63 | ![](./git-img/pm2list.png) 64 | ## 重启服务看看是否生效(阿里云为例) 65 | ![](./git-img/reset.png) 66 | 重启成功后可以看到应用的id等信息改变了,程序可以继续访问 67 | ![](./git-img/resetpm2.png) 68 | 69 | 快速使用pm2到此结束,如果不想深入研究,其实学到这里就已经可以了。 70 | -------------------------------------------------------------------------------- /pm2进阶使用.md: -------------------------------------------------------------------------------- 1 | ## 启用集群模式 2 | 只需要在启动应用时带上i参数 3 | ``` 4 | pm2 start app.js -i max 5 | ``` 6 | max:意味着PM2将自动检测可用的CPU数量和运行多个进程可以在负载均衡模式(但是不推荐使用) 7 | 8 | 或者使用json文件启动的 9 | ``` 10 | { 11 | "apps" : [{ 12 | "script" : "api.js", 13 | "instances" : "max", 14 | "exec_mode" : "cluster" 15 | }] 16 | } 17 | ``` 18 | 当然还支持js和ylm文件,js示例如下 19 | [相关资料](http://pm2.keymetrics.io/docs/usage/application-declaration/) 20 | ``` 21 | module.exports = { 22 | apps : [{ 23 | name : "worker",//应用名称 24 | script : "./worker.js", //脚本路径相对于pm2开始 25 | watch : true, //开启监察,文件改变自动重启 26 | env: { 27 | "PORT": 3000, 28 | "NODE_ENV": "development", 29 | }, 30 | env_production : { 31 | "PORT": 80 32 | "NODE_ENV": "production" 33 | } 34 | },{ 35 | name : "api-app", 36 | script : "./api.js", 37 | cwd : "/home/www/project_root/current",// 38 | "error_file": "./logs/app.err.log", 39 | "out_file": "./logs/app.out.log", 40 | "log_date_format" : "YYYY-MM-DD HH:mm Z" 41 | instances : 4, // 实例(多核) 42 | exec_mode : "cluster" // 集群模式 43 | }] 44 | } 45 | ``` 46 | 47 | 然后再启动进程 48 | ``` 49 | pm2 start processes.json 50 | ``` 51 | 重载应用 52 | ``` 53 | pm2 reload 54 | ``` 55 | 或者 56 | ``` 57 | pm2 reload process.json 58 | pm2 reload process.json --only api 59 | ``` 60 | 61 | ## 一键发布 62 | yml的书写方式(process.yml) 63 | ``` 64 | apps: 65 | - script : server.js 66 | name : 'pm2 test' 67 | watch : true 68 | env : 69 | NODE_ENV: development 70 | env_production: 71 | NODE_ENV: production 72 | deploy : 73 | production : 74 | user : root 75 | key : C:/Windows/SSH-ubuntu.pem #服务器sshkey(阿里云再服务器镜像创建的时候会生成 然后保存到本地) 76 | host : 77 | - 120.78.174.212 #服务器ip 78 | port : 22 79 | ref : origin/master 80 | repo : git@gitee.com:artiely/pm2test.git #仓库地址 81 | path : /www/pm2test/production #发布地址 82 | ssh_options : StrictHostKeyChecking=no #ssh权限 83 | pre-deploy : git fetch --all #发布前的操作 84 | post-deploy : 'npm install && npm run build && pm2 startOrRestart process.yml --env production' 85 | env : 86 | NODE_ENV : production 87 | ``` 88 | 第一次发布本地执行 89 | ``` 90 | pm2 deploy process.yml production setup 91 | ``` 92 | 然后每次发布只需本地执行如下命令,服务器就会自动拉取创库代码并发布 93 | ``` 94 | pm2 deploy process.yml production 95 | ``` 96 | 97 | ## 注意事项 98 | github上必须有服务器的公钥和本地的公钥 99 | 100 | https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/ 101 | 102 | 这里有各个系统生成id_rsa的方法 103 | 104 | 105 | 1.服务器node版本尽量使用最高稳定版 106 | 2.devDependencies里的代码在发布时不会被下载安装,如有需要请移动到dependencies 107 | 3.如果出现Host key verification failed. 108 | 解决方案 109 | 1. 删除~/.ssh/known_hosts 文件中包含"gitlab.xxx.com"这一行的记录 110 | 111 | 2. 删除~/.ssh/known_hosts整个文件 112 | 113 | 3. 修改open ssh配置文件,安全级别调低(不推荐,仅限内网等安全级别较高的环境,公网不要使用) 114 | 115 | SSH对主机的public_key的检查等级是根据StrictHostKeyChecking变量来配置的。可以通过降低安全级别的方式,来减少这一类提示。 116 | 117 | 修改方法: 118 | 编辑~/.ssh/config(代表个人配置,或/etc/ssh/ssh_config,代表全局配置) 119 | 添加以下行 120 | Shell代码 收藏代码 121 | StrictHostKeyChecking no 122 | UserKnownHostsFile /dev/null # 为了更简化,把known_hosts也省略掉了 123 | 124 | 下面附上StrictHostKeyChecking配置项的说明。 125 | StrictHostKeyChecking=no 126 | 最不安全的级别,当然也没有那么多烦人的提示了,相对安全的内网测试时建议使用。如果连接server的key在本地不存在,那么就自动添加到文件中(默认是known_hosts),并且给出一个警告。 127 | StrictHostKeyChecking=ask 128 | 默认的级别,就是出现刚才的提示了。如果连接和key不匹配,给出提示,并拒绝登录。 129 | StrictHostKeyChecking=yes 130 | 最安全的级别,如果连接与key不匹配,就拒绝连接,不会提示详细信息。 -------------------------------------------------------------------------------- /python/django写个helloword.md: -------------------------------------------------------------------------------- 1 | # 创建应用app 2 | > python3 django2 3 | 4 | 在manage.py同级目录下 python manage.py startapp myapp 5 | 6 | 或者 pycharm tools -> run manage.py task 7 | 8 | ``` 9 | manage.py@django3 > startapp myapp 10 | "C:\Program Files\JetBrains\PyCharm 2017.3\bin\runnerw.exe" C:\Users\Administrator\Desktop\django3\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm 2017.3\helpers\pycharm\django_manage.py" startapp myapp C:/Users/Administrator/Desktop/django3 11 | 12 | Following files were affected 13 | C:\Users\Administrator\Desktop\django3\myapp\admin.py 14 | C:\Users\Administrator\Desktop\django3\myapp\apps.py 15 | C:\Users\Administrator\Desktop\django3\myapp\models.py 16 | C:\Users\Administrator\Desktop\django3\myapp\tests.py 17 | C:\Users\Administrator\Desktop\django3\myapp\views.py 18 | C:\Users\Administrator\Desktop\django3\myapp\__init__.py 19 | C:\Users\Administrator\Desktop\django3\myapp\migrations\__init__.py 20 | ``` 21 | > 注意:App名称不能与python默认的模块名冲突 比如 os 22 | # 并且添加应用名到 settings.py 里 23 | ![](../md-img/myapp.png) 24 | 25 | # 学习应用app目录的结构 26 | Migrations 数据移植模块 涉及数据库的操作 内容是自动生成的 27 | admin.py 是当前app的后台管理系统的配置文件 28 | apps.py 该app的一些配置 是在Django1.9以后自动生成的 29 | models.py 数据模块 ORM框架 对象关系映射 30 | tests.py 自动化测试模块 测试脚本 31 | views.py 执行响应的代码所在的模块 整个项目最主要的代码编辑区 32 | 33 | # 开始hello world 34 | myapp -> views.py 35 | ``` 36 | from django.http import HttpResponse 37 | 38 | def index(request): 39 | return HttpResponse('hello world') 40 | ``` 41 | 42 | django3 -> urls.py 43 | ``` 44 | from django.contrib import admin 45 | from django.urls import path 46 | from myapp.views import index #导入 47 | 48 | urlpatterns = [ 49 | path('admin/', admin.site.urls), 50 | path('index/', index), #匹配 51 | ] 52 | 53 | ``` 54 | 55 | # ok! 56 | 57 | ![](../md-img/h-w.png) 58 | 59 | 线上seeting.py debug要改为false并加入host 60 | ``` 61 | DEBUG = False 62 | 63 | ALLOWED_HOSTS = ['127.0.0.1'] 64 | ``` 65 | # 独立出urls配置 66 | 67 | 一个工程下如果app很多 都写在根urls.py文件中 会 复杂而且很难维护 68 | 所以 另外一种 url的配置方法· 69 | 复制一份urls配置到app项目下,修改为 70 | ``` 71 | from django.urls import path 72 | from . import views # + 73 | 74 | urlpatterns = [ 75 | path('index/', views.index), # + 76 | ] 77 | 78 | ``` 79 | 然后根目录配置修改为 80 | ``` 81 | from django.contrib import admin 82 | from django.urls import path, include # + 83 | 84 | urlpatterns = [ 85 | path('admin/', admin.site.urls), 86 | path('myapp/', include('myapp.urls')), # + 87 | ] 88 | ``` 89 | 然后访问路径为 http://127.0.0.1:8000/myapp/index/ 90 | 91 | # django使用template模板 92 | 93 | 项目下新建templates文件夹,templates下新建项目同名文件夹 如:myapp/templates/myapp/index.html 94 | 95 | index.html 96 | ``` 97 | 98 | 99 | 100 | 101 | Title 102 | 103 | 104 | 你好,世界! 105 | 我是{{ name }} 106 | 107 | 108 | ``` 109 | myapp/views.py 110 | ``` 111 | from django.shortcuts import render 112 | 113 | def index(request): 114 | return render(request, 'myapp/index.html', {'name': 'artiely', 'age': '20'}) 115 | ``` 116 | render() 一般有三个参数:request 模板名 返回给前端的数据 117 | 118 | DTL的使用: 119 | render()函数支持一个dict类型参数 120 | 该字典是后台传递到前端模板的参数,键为参数名 121 | 在前端模板中使用{{参数名}}来直接使用 122 | 123 | DTL 也支持if else for循环这样的逻辑操作 {% %} {{ }} 124 | 125 | > 细节:Django查找Template是按照INSTALLED_APPS中添加的顺序查找的 126 | 如果在两个app中使用了同名的html文件 那么就会有问题 127 | 解决方案:1、改名 2、在app的templates目录下再创建一个与app同名的目录 128 | 然后将html文件放到该目录下即可 129 | 130 | # _ORM之创建models与数据库表 131 | 132 | Render的第三个参数 返回给前端的数据 是从数据库中获取的 133 | Models 模型 对应数据库的一张数据表 以类的形式表现 134 | ORM 对象关系映射:所有对数据库的操作实际上是对类以及对类的对象的操作 135 | 隐藏了数据访问的细节,不需要写任何sql语句 实现了对象与数据库之间的映射 136 | 137 | 步骤: 138 | 1、在应用根目录的models.py 引入models模块 139 | 2、创建类 继承models.Model 该类就是一张数据表 140 | 3、在类中创建字段 141 | models.py 142 | ``` 143 | from django.db import models 144 | 145 | # Create your models here. 146 | class Article (models.Model): 147 | title = models.CharField(max_length=32, default='无标题') 148 | content = models.TextField(default='暂无内容') 149 | ``` 150 | 151 | 字段创建: 152 | 字段即类里面的属性 153 | attr = models.CharField(max_length=64) 154 | 155 | 字段类型看文档:https://docs.djangoproject.com/en/1.11/ref/models/fields/ 156 | 157 | 将模型映射成数据表: 158 | 1、python manage.py makemigrations app名 159 | 2、python manage.py migrate 160 | 161 | Django会在app/migrations/目录下生成移植文件(django2好像没有) 162 | 执行python manage.py sqlmigrate 应用名 文件id 可以查看sql语句 163 | 164 | 生成的数据库在哪里? 使用了默认的sqlite3 165 | 166 | 查看并编辑db.sqlite3 使用第三方 轻量级 完全免费 167 | Windows:sqlite expert personal 168 | Mac:SQLiteStudio (推荐) 169 | 170 | 页面数据获取: 171 | 在views.py中import models 172 | Article = models.Article.objects.get(pk=1) select 主键为1 173 | render(request,page, {‘article’: article}) 174 | 也支持对象的传递 175 | views.py 176 | ``` 177 | from . import models 178 | from django.http import HttpResponse 179 | 180 | def index(request): 181 | article = models.Article.objects.get(pk=1) 182 | return render(request, 'myapp/index.html', {'article':article}) 183 | ``` 184 | 185 | # django admin 186 | django自带的功能强大的后台数据管理系统 187 | 188 | http://127.0.0.1:8000/admin/ 189 | Python manage.py createsuperuser 创建一个超级用户 190 | or 创建用户 tools run manage.py task 191 | ``` 192 | createsuperuser 193 | # 用户名 194 | # 邮箱 195 | # 密码 196 | ``` 197 | 然后登陆 198 | 199 | 改语言 修改settings.py 的LANGUAGE_CODE=‘zh_Hans’ zh_Hant 200 | 201 | setting.py 202 | ``` 203 | # LANGUAGE_CODE = 'en-us' 204 | LANGUAGE_CODE = 'zh-hans' 205 | ``` 206 | 把自己的应用加入到后台管理 207 | 208 | 配置应用:(把应用注册到后台管理模块中) 209 | 在应用下的admin.py中引入自身的models模块 210 | 同时添加注册:admin.site.register(models.Article) 211 | 212 | myapp/admin.py 213 | ``` 214 | # Register your models here. 215 | from . import models 216 | 217 | admin.site.register(models.Article) 218 | ``` 219 | 这样admin后台就会多一个admin站点管理 220 | 221 | 修改`article object`的显示 222 | 修改数据默认显示的名称: 223 | 在models.py中的Article类下添加一个方法 224 | 如果是python3 则__str__(self) 225 | 如果是Python2 则__unicode_(self) 226 | Return self.title or self.content 227 | 228 | models.py 229 | ``` 230 | class Article (models.Model): 231 | title = models.CharField(max_length=32, default='无标题') 232 | content = models.TextField(default='暂无内容') 233 | 234 | def __str__(self): 235 | return self.title 236 | 237 | ``` 238 | # 文章详情 239 | 240 | article_id组名必须与views.py里的响应函数里的参数名保持一致 241 | 正则表达式: 242 | (?P[0-9]+) 243 | 244 | + 匹配1次或者多次前面出现的正则表达式 245 | [0-9] \d 都是匹配数字 246 | (?P…) 向一个仅由name标识而不是数字id标识的正则分组匹配 247 | py3的url的规则https://docs.djangoproject.com/en/2.0/topics/http/urls/ 248 | urls.py 249 | ``` 250 | urlpatterns = [ 251 | path('index/', views.index), 252 | path('article/', views.article), 253 | ] 254 | ``` 255 | views.py 256 | ``` 257 | def article(request, article_id): 258 | article = models.Article.objects.get(pk=article_id) 259 | return render(request, 'myapp/article.html', {'article': article}) 260 | ``` 261 | 262 | # 编辑 263 | 编辑表单的响应函数 action post 264 | 使用request.POST[‘参数名’]获取表单数据 265 | 创建对象: 266 | models.Article.objects.create(title,content) 267 | 268 | CSRF验证失败. 请求被中断. 安全性的问题 Django的安全性是比较高的 269 | 270 | {% csrf_token %} 271 | 272 | 跨站请求伪造 网站攻击 273 | 274 | > 还有命名空间 django2 incloud加了命名空间就必须给项目加`app_name` 275 | 276 | # Templates过滤器:写在模板中,属于DTL 277 | 可以修改模板中的变量 从而显示不同的内容 278 | 怎么使用过滤器? {{value|filter}} 例子:{{ list_nums | length}} 279 | 过滤器可以叠加的 {{ value | filter1 | filter2 | filter3 | …}} 280 | 281 | Django模板的特性:如果没有这个值 则为空值 空字符串 不会报错 282 | run manage.py task 66 | 67 | Sqlite3会自动生成的 68 | 69 | 与项目名称同名的文件夹:是项目容器 目录名称不建议修改 70 | wsgi.py web server gateway interface 71 | Python应用与web服务器之间的接口 72 | 73 | Urls.py 配置url 74 | Django项目中所有地址(页面)都需要我们去配置其url 75 | 76 | settings.py 77 | 项目的最核心配置文件 78 | 79 | __init__.py 空的 声明模块的文件 变成一个模块 可以在代码中引用 80 | 内容默认为空,如果丢失可以直接复制其他的过来 81 | 82 | 83 | -------------------------------------------------------------------------------- /react/实战之react.md: -------------------------------------------------------------------------------- 1 | ## 社会我王哥 人狠话不多 2 | 1.直接撸一个实战,通俗易懂循序渐进 3 | 4 | ## 安装create-react-app 并创建项目 5 | https://github.com/facebookincubator/create-react-app 6 | 7 | ``` 8 | npm i -g create-react-app 9 | create-react-app my-app 10 | cd my-app 11 | npm start // 如果端口冲突 scripts -> start.js 修改port 12 | ``` 13 | 14 | ## 更新react到最新版本 15 | 16 | ``` 17 | npm install react@next react-dom@next 18 | ``` 19 | 20 | ## 首先引入redux 21 | -------------------------------------------------------------------------------- /richText.md: -------------------------------------------------------------------------------- 1 | 几种知名开源富文本编辑器记录和对比(仅供参考) 2 | 3 | # 1、UEditor 百度的。 4 | 5 | 优点:插件多,基本满足各种需求,类似贴吧中的回复界面。 6 | 7 | 缺点:不再维护,文档极少,使用并不普遍,图片只能上传到本地服务器,如果需要上传到其他服务器需要改动源码,较为难办,加载速度慢。 8 | 9 | 总结:小项目,可以用用,不推荐使用。 10 | 11 | 12 | 13 | # 2、kindeditor 14 | 15 | 界面类似百度,效果很像 16 | 17 | 文档齐全但用例较少,使用还算方便。 18 | 19 | 缺点:总感觉样子不是很好看,没有现代那种风格,还是老式的传统图标。 20 | 21 | http://kindeditor.net/demo.php 22 | 23 | 24 | 25 | # 3、simditor 26 | 27 | 样式好看,插件不多,基本满足需求 28 | 29 | 文档英文,使用较为吃力,如果英文水平不好的话 30 | 31 | github上面开源,维护较好 32 | 33 | 因为文档看起来吃力,所以本人没有考虑继续使用。 34 | 35 | http://simditor.tower.im/ 36 | 37 | 38 | 39 | # 4、bootstrap-wysiwyg 40 | 41 | 利用bootstrap实现的,简洁大方好看。 42 | 43 | 优点:轻量,好看,使用方便。 44 | 45 | 缺点:需要一定的浏览器支持,毕竟需要bootstrap 46 | 47 | http://www.bootcss.com/p/bootstrap-wysiwyg/ 48 | 49 | 50 | 51 | # 5、wangEditor 52 | 53 | js和css实现 54 | 55 | 优点:轻量简洁,最重要的是开源且中文文档齐全。设计的UI漂亮。 56 | 57 | 插件基本能满足需求,本人推荐使用。 58 | 59 | http://www.wangeditor.com/index.html 60 | 61 | 62 | 63 | # 6、CKEditor 64 | 65 | 功能强大,使用较多,可以看他们官网的例子,马上就有感觉。 66 | 67 | 优点:编辑能力极强,基本和word差不多了。看起来界面极其优秀的一款。 68 | 69 | 缺点:网站访问速度一般,文档英文,需要花时间开发。 70 | 71 | http://ckeditor.com/ 72 | 73 | 74 | 75 | # 7、tinymce 76 | 77 | 支持图片在线处理,插件多,功能强 78 | 79 | 编辑能力优秀,界面好看。 80 | 81 | 同样文档为英文,开发需要花时间。 82 | 83 | https://www.tinymce.com/ 84 | 85 | 86 | 87 | 使用之前需要考虑的点: 88 | 89 | 1需要插件,是否需要很多的插件,还是说简单的那些功能就行了。 90 | 91 | 2界面考虑,看你喜欢那个界面了。 92 | 93 | 3图片是否需要上传图片服务器。 94 | 95 | 4文档如果为英文是否会影响开发。 96 | 97 | 5支持浏览器类型和版本。 -------------------------------------------------------------------------------- /vue/1.写个vue组件库.md: -------------------------------------------------------------------------------- 1 | # 怎么使用vue写个自己的组件库 2 | 本人用vue写了两年的业务了,用了不少的组件库,也成想过自己来实现一个,一直推到现在,我们用过无数的轮子,宝马的,奔驰的,奥迪的,但是老板就要玛莎的,轮子是有限的,业务时无限的。 3 | 4 | 从零开始 一步步实现自己的组件库,以后可以不断完善,拿来即用 5 | - 需要与众不同 包含自己的特色 6 | 7 | 我们先从一个最简单的button开始 8 | 9 | 大致的项目结构 10 | ``` 11 | package # 组件包 12 | --button # 组件文件夹 13 | --|--button.vue # button组件 14 | --|--button.less # 样式文件 15 | --|--index.js # 组件的出口 16 | --style.less # 公用的 css 样式文件 17 | --index.js # 组件库的出口 18 | ``` 19 | src/package/button/button.vue 20 | ``` 21 | 26 | 27 | 34 | ``` 35 | src/package/button/index.js 36 | ``` 37 | // 引用 scss 文件和组件 38 | import './button.less' 39 | import Button from './button.vue' 40 | 41 | // 导出组件 42 | export default Button 43 | ``` 44 | 45 | src/package/index.js 46 | ``` 47 | // 1.引入组件 48 | import Button from './button' 49 | 50 | // 2.挂载组件对象 51 | const components = { 52 | Button 53 | } 54 | 55 | // 3.注册组件 56 | const install = function(Vue, Option = {}) { 57 | // 4.已经注册的返回 58 | if (install.installed) return 59 | // 5.循环注册组件 60 | Object.keys(components).forEach((key) => { 61 | Vue.component(components[key].name, components[key]) 62 | }) 63 | } 64 | 65 | // 6.导出库 66 | export default { 67 | install 68 | } 69 | ``` 70 | 71 | src/main.js 72 | ``` 73 | import Ivue from './package' 74 | Vue.use(Ivue) 75 | 76 | ``` 77 | 任意组件使用 78 | ``` 79 | 84 | 85 | ``` -------------------------------------------------------------------------------- /vue/2.vue组件库之button实现.md: -------------------------------------------------------------------------------- 1 | # 需求 2 | - 自定义button文本 3 | - button左边icon 右边icon 4 | - button disable 5 | - 背景带进度 6 | - 加载loading 7 | - 点击特效 8 | - 尺寸 大中小 9 | - block 长短型 10 | - 不同色彩 11 | - 不同形状 12 | - 自定义样式 13 | - 按钮组 14 | - 文字超出隐藏 15 | - 1px 16 | - 点击回馈 17 | 18 | 19 | # 样式 20 | 21 | 1.绝对的采用预编译语言 此处我采用less 22 | 23 | 2 单独声明样式变量 提高可维护性 24 | 25 | ``` 26 | // 背景色 27 | @primary:#69c0ff; 28 | @warning:#ffc53d; 29 | @danger:#f5222d; 30 | @base:#13c2c2; 31 | @ghost:#fff; 32 | @body-bg:#f0f0f0; 33 | 34 | // 圆角 35 | @border-radius:4px; 36 | // 边框 37 | @border-color:#d9d9d9; 38 | 39 | // 字体颜色 40 | @color-white:#fff; 41 | @color-light:#999; 42 | @color-dark:#777; 43 | ``` 44 | 3. 混合样式的示例(部分代码) 45 | ``` 46 | 47 | @import '../style/var.less'; 48 | .mix-hover(@arg-color){ 49 | &:hover{ 50 | background:lighten(@arg-color,10%) 51 | } 52 | &:active{ 53 | background:darken(@arg-color,10%) 54 | } 55 | } 56 | .i__button{ 57 | background: @primary; 58 | text-align: center; 59 | color:contrast(@primary,@color-white); 60 | border-radius:@border-radius; 61 | .mix-hover(@primary) 62 | } 63 | 64 | ``` 65 | # button.vue 66 | 67 | 1. 主要根据属性控制样式 68 | 69 | ``` 70 | 90 | 91 | 140 | ``` 141 | 示例效果 142 | ![](../md-img/btn.png) 143 | 144 | > 还有些未完成的效果 145 | -------------------------------------------------------------------------------- /vue/demo/mvvm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 12 | 13 | 14 |
15 | 乞丐版双向数据绑定原理 16 | 17 |

18 |
19 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /正反向代理.md: -------------------------------------------------------------------------------- 1 | 正向代理:代理端代理的是客户端,服务端认代理端不认客户端。 2 | 反向代理:代理端代理的服务端,客户端认代理端不认服务端 -------------------------------------------------------------------------------- /移动端滚动穿透解决方案.md: -------------------------------------------------------------------------------- 1 | ## 问题 2 | 3 | 在滚动模态框里的内容的时候,背景(模态框下面的内容)也在跟着滚动 4 | 5 | ## css 之 overflow: hidden 6 | 7 | ```css 8 | .modal-open { 9 | &, 10 | body { 11 | overflow: hidden; 12 | height: 100%; 13 | } 14 | } 15 | ``` 16 | 17 | 页面弹出层上将 .modal-open 添加到 html 上,禁用 html 和 body 的滚动条,但是这个方案有两个缺点: 18 | 19 | - 由于 html 和 body 的滚动条都被禁用,弹出层后页面的滚动位置会丢失,需要用 js 来还原。 20 | - 页面的背景还是能够有滚的动的效果 21 | 22 | ## js 之 touchmove + preventDefault 23 | 24 | ```js 25 | modal.addEventListener( 26 | 'touchmove', 27 | function(e) { 28 | e.preventDefault() 29 | }, 30 | false 31 | ) 32 | ``` 33 | 34 | 这样用 js 阻止滚动后看起来效果不错了,但是也有一个缺点:弹出层里不能有其它需要滚动的内容(如大段文字需要固定高度,显示滚动条也会被阻止) 35 | 36 | ## css 结合 js 37 | 38 | ```css 39 | body.modal-open { 40 | position: fixed; 41 | width: 100%; 42 | } 43 | ``` 44 | 45 | 如果只是上面的 css,滚动条的位置同样会丢失。 46 | 所以如果需要保持滚动条的位置需要用 js 保存滚动条位置关闭的时候还原滚动位置。 47 | 48 | ```js 49 | /** 50 | * ModalHelper helpers resolve the modal scrolling issue on mobile devices 51 | * https://github.com/twbs/bootstrap/issues/15852 52 | * requires document.scrollingElement polyfill https://github.com/yangg/scrolling-element 53 | */ 54 | var ModalHelper = (function(bodyCls) { 55 | var scrollTop 56 | return { 57 | afterOpen: function() { 58 | scrollTop = document.scrollingElement.scrollTop 59 | document.body.classList.add(bodyCls) 60 | document.body.style.top = -scrollTop + 'px' 61 | }, 62 | beforeClose: function() { 63 | document.body.classList.remove(bodyCls) 64 | // scrollTop lost after set position:fixed, restore it back. 65 | document.scrollingElement.scrollTop = scrollTop 66 | } 67 | } 68 | })('modal-open') 69 | ``` 70 | 71 | 注意兼容 document.scrollingElement 72 | 73 | ## 看一下其他框架的处理办法 74 | 75 | ### vant 有赞 76 | 77 | ```js 78 | // 打开的时候给body动态添加css 关闭的时候移除样式 79 | open() { 80 | /* istanbul ignore next */ 81 | if (this.$isServer || this.opened) { 82 | return; 83 | } 84 | 85 | // 如果属性中传入了`zIndex`,则覆盖`context`中对应的`zIndex` 86 | if (this.zIndex !== undefined) { 87 | context.zIndex = this.zIndex; 88 | } 89 | 90 | this.opened = true; 91 | this.renderOverlay(); 92 | 93 | if (this.lockScroll) { 94 | on(document, 'touchstart', this.touchStart); 95 | on(document, 'touchmove', this.onTouchMove); 96 | if (!context.lockCount) { 97 | document.body.classList.add('van-overflow-hidden'); 98 | } 99 | context.lockCount++; 100 | } 101 | }, 102 | 103 | close() { 104 | if (!this.opened) { 105 | return; 106 | } 107 | 108 | if (this.lockScroll) { 109 | context.lockCount--; 110 | off(document, 'touchstart', this.touchStart); 111 | off(document, 'touchmove', this.onTouchMove); 112 | if (!context.lockCount) { 113 | document.body.classList.remove('van-overflow-hidden'); 114 | } 115 | } 116 | 117 | this.opened = false; 118 | manager.close(this._popupId); 119 | this.$emit('input', false); 120 | }, 121 | ``` 122 | 123 | ### mand-mobile 124 | 125 | ```js 126 | // 滚动的时候阻止默认事件 排除的元素及子节点继续执行绑定事件 127 | $_preventScroll(isBind) { 128 | const handler = isBind ? 'addEventListener' : 'removeEventListener' 129 | const masker = this.$el.querySelector('.md-popup-mask') 130 | const boxer = this.$el.querySelector('.md-popup-box') 131 | masker && masker[handler]('touchmove', this.$_preventDefault, false) 132 | boxer && boxer[handler]('touchmove', this.$_preventDefault, false) 133 | this.$_preventScrollExclude(isBind) 134 | }, 135 | $_preventScrollExclude(isBind, preventScrollExclude) { 136 | const handler = isBind ? 'addEventListener' : 'removeEventListener' 137 | preventScrollExclude = preventScrollExclude || this.preventScrollExclude 138 | const excluder = 139 | preventScrollExclude && typeof preventScrollExclude === 'string' 140 | ? this.$el.querySelector(preventScrollExclude) 141 | : preventScrollExclude 142 | excluder && excluder[handler]('touchmove', this.$_stopImmediatePropagation, false) 143 | }, 144 | $_preventDefault(event) { 145 | event.preventDefault() 146 | }, 147 | $_stopImmediatePropagation(event) { 148 | /* istanbul ignore next */ 149 | event.stopImmediatePropagation() 150 | }, 151 | ``` 152 | -------------------------------------------------------------------------------- /表单默认提交问题.md: -------------------------------------------------------------------------------- 1 | > 当form下只包裹一个input的情况下,在回车时,会自动提交(页面会刷新) 2 | 3 | - 解决办法:加入一个input display:none -------------------------------------------------------------------------------- /雅虎性能优化的十四条规则.md: -------------------------------------------------------------------------------- 1 | 雅虎性能优化的十四条规则 2 | ===================== 3 | 4 | 作为一位前端技术人员,了解网站的性能优化方面的知识是很基本的,但是我很惭愧我现在才了解到这一点T^T,以下是我学习yahoo性能优化十四条规则的笔记: 5 | 6 | - __一、减少http请求次数__ 7 | 8 | 如何减少http请求次数: 9 | 10 | > - 组合页面中的图片到单个文件中,并使用css的background-image和background-position属性来实现所需部分的图片; 11 | > - 组合多个脚本文件到单一文件中。意思就是:把页面中的多个css 或js文件合并在一个文件中。 12 | 13 | 减少http请求次数是性能优化的起点!对提高首次访问效率起到很重要的作用。 14 | 15 | - __二、使用cdn(Content Delivery Network,内容分发网络)__ 16 | 17 | 这条可以忽略之。。。。 18 | 19 | - __三、增加expires header__ 20 | 21 | 浏览器(和代理)使用缓存来减少http请求次数和大小,使得网页加速装载。 22 | 23 | 如何增加expires header 24 | 25 | > - 如果是apache,可以使用expiresDefault基于当期日期来设置过期日期。 26 | > - 记住:如果使用超长的过期时间,则当内容改变时,必须改变文件名称。 27 | > - 版本号内嵌在文件名中,如:useless_1.0.0.js. 28 | 29 | - __四、压缩页面元素__ 30 | 31 | 压缩http响应内容可以减少页面响应时间,同时,对尽量度的文件类型进行压缩是一种减少页面大小和提高用户体验的简便方法。 32 | 33 | 通过Accept-Encoding头来表明支持的压缩类型,如: 34 | 35 | `Accept-Encoding: gzip,deflate` 36 | 37 | PS:这个可以忽略,因为一般浏览器都支持gzip之类压缩,然后服务端前端这边不用管。 38 | 39 | - __五、把样式表放在头上__ 40 | 41 | 把样式表移到head中,可以提高界面的加载速度,因此这使得页面元素可以顺序显示。 42 | 43 | 原因: 避免空白屏幕或闪烁的问题。 44 | 45 | - __六、把脚本文件放在底部__ 46 | 47 | 尽量把脚本文件放在页面底部,好处就是,一能顺序显示,二可达到最大的并行下载。 48 | 49 | - __七、避免css表达式__ 50 | 51 | css表达式是强大的(同时也是危险的)用于动态设置css属性的方式。ie,从版本5开始支持css表达式。 52 | 53 | 所谓的表达式是,看例子: 54 | 55 | `expression((new Date()).getHours()%2?"#B8D4FF":"#F08A00")`,即背景色每个小时切换一次。 56 | 57 | ps:一般很少用css表达式 58 | 59 | - __八、把js和css放到外部文件中__ 60 | 61 | > - 使用外部文件会加快页面显示速度,因为外部文件会被浏览器缓存。 62 | > - 内置的js和css在页面中虽然会减少http请求次数,但是增大了页面的大小。 63 | > - 使用外部文件,会被浏览器缓存,则页面大小会减小,同时又不增加http请求次数。 64 | 65 | - __九、减少DNS查询次数__ 66 | 67 | 这个不说明,了解下,这主要是服务端的优化 68 | 69 | - __十、最小化js代码__ 70 | 71 | 最小化js代码是指在js代码中删除不必要的字符,从而降低下载时间。 72 | 73 | ps:其实就是压缩js。 74 | 75 | - __十一、避免重定向__ 76 | 77 | 重定向功能是通过301和302这两个http状态码完成的,如: 78 | 79 | > - `HTTP/1.1 301 Moved Permanently` 80 | > - `Location:http://example.com/newuri` 81 | > - `Content-Type:text/html` 82 | 83 | ps:没用过这个 84 | 85 | - __十二、删除重复的脚本文件__ 86 | 87 | 在一个页面中包含重复的js脚本会影响性能,即它会建立不必要的http请求和额外的js执行。 88 | 89 | - __十三、配置etags__ 90 | 91 | 忽略吧。。。。 92 | 93 | - __十四、缓存ajax__ 94 | 95 | 提高ajax的性能最重要的方式是使得其response可缓存。 96 | 97 | 学习链接如下: 98 | 99 | > - [https://developer.yahoo.com/performance/rules.html](https://developer.yahoo.com/performance/rules.html) 100 | > - [http://3y.uu456.com/bp-58a2922f647d27284b73512a-2.html](http://3y.uu456.com/bp-58a2922f647d27284b73512a-2.html) 101 | > - [http://fex.baidu.com/blog/2014/03/fis-optimize/](http://fex.baidu.com/blog/2014/03/fis-optimize/) 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | --------------------------------------------------------------------------------