├── .editorconfig ├── .gitignore ├── .npmrc ├── a.js ├── aaa.md ├── build ├── addComment.js ├── delComment.js └── findMarkdown.js ├── clockIn.js ├── docs ├── .vuepress │ ├── components │ │ └── _doc.md │ ├── config.js │ ├── enhanceApp.js │ ├── override.styl │ ├── plugins │ │ └── comment │ │ │ ├── comment.vue │ │ │ ├── enhanceAppFile.js │ │ │ ├── index.js │ │ │ └── initComment.js │ └── public │ │ ├── images │ │ └── favicon.png │ │ └── styles │ │ └── reset.css ├── README.md ├── always │ └── README.md ├── basic │ └── sort.md ├── css │ ├── name.md │ ├── pseudo.md │ ├── selector.md │ └── unit.md ├── html │ ├── email.md │ ├── meta.md │ ├── optimal.md │ ├── url.md │ └── wx.md ├── interview │ └── interview.md ├── js │ ├── README.md │ ├── copy.md │ ├── documentFragment.md │ ├── eventloop.md │ ├── getBoundingClientRect.md │ ├── implementation.md │ ├── inherit.md │ ├── insertAdjacentHTML.md │ ├── messageChannel.md │ ├── module.md │ ├── mutationObserver.md │ └── this.md ├── keng │ └── keng.md ├── leetcode │ ├── 13.md │ ├── 14.md │ ├── 20.md │ ├── 9.md │ ├── dynamic-programming.md │ ├── singleNumber.md │ ├── sort.md │ └── twoSum.md ├── realize │ ├── bind.md │ ├── call.md │ ├── curry.md │ ├── new.md │ ├── promise.md │ ├── reactHook.md │ └── throttleDebounce.md └── when │ └── readme.md ├── leetcode ├── 1.js ├── 13.js ├── 136.js ├── 14.js ├── 20.js ├── 3.js ├── 4.js └── 9.js ├── old ├── css中一些不常用的单位.md ├── images │ ├── 2018062201.jpg │ ├── 2018062202.jpg │ ├── 2018062203.png │ └── hover.gif ├── jquery跨域头部配置.md ├── readme.md ├── svg的一点问题.md ├── 一些meta标签.md ├── 函数节流与防抖.md ├── 利用css变量实现的悬停效果.md ├── 很久之前写的gulp相关.md ├── 数组打乱与重排.md ├── 滚动条抖动问题.md └── 记一些css的黑魔法.md ├── other └── sort │ ├── A.js │ ├── bubble.js │ ├── bucket.js │ ├── count.js │ ├── heap.js │ ├── insertion.js │ ├── merge.js │ ├── merge2.js │ ├── quick.js │ ├── quick2.js │ └── selection.js ├── package.json ├── readme.md ├── realize ├── apply.js ├── bind.js ├── call.js ├── curry.js ├── debounce.js ├── new.js ├── promise.ts └── throttle.js └── test.html /.editorconfig: -------------------------------------------------------------------------------- 1 | root = false 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *.log 4 | .temp 5 | vuepress 6 | TODOs.md 7 | .idea 8 | .vscode 9 | dist 10 | config.js 11 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /a.js: -------------------------------------------------------------------------------- 1 | const str = '' 2 | 3 | const arr = [] 4 | for (let i = 20; i < 29; i++) { 5 | const num = i + 1 < 10 ? `0${i + 1}` : i + 1 6 | 7 | const url = `http://storage.360buyimg.com/douya/spring-cms/image0${num}.png` 8 | 9 | arr.push(``) 10 | arr.push(`"descImg": "${url}",`) 11 | arr.push('') 12 | 13 | } 14 | 15 | 16 | console.log('arr', arr.join(`\n`)); 17 | -------------------------------------------------------------------------------- /aaa.md: -------------------------------------------------------------------------------- 1 | 1. 握手挥手 2 | 2. promise 3 | 3. http 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /build/addComment.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const findMarkdown = require('./findMarkdown') 3 | const rootDir = './docs' 4 | 5 | findMarkdown(rootDir, writeComment) 6 | 7 | function writeComment(dir) { 8 | fs.appendFile(dir, `\n \n `, (err) => { 9 | if (err) throw err 10 | console.log(`add comment component to ${dir}`) 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /build/delComment.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const findMarkdown = require('./findMarkdown') 3 | const rootDir = './docs' 4 | 5 | findMarkdown(rootDir,delComment) 6 | 7 | // delComment('./docs/index.md') 8 | function delComment(dir){ 9 | fs.readFile(dir,'utf-8', (err, content) => { 10 | if (err) throw err 11 | 12 | fs.writeFile(dir, content.replace(/\n \n /g,''), (err) => { 13 | if (err) throw err 14 | console.log(`del comment component from ${dir}`) 15 | }) 16 | }) 17 | } -------------------------------------------------------------------------------- /build/findMarkdown.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | function findMarkdown(dir, callback) { 4 | fs.readdir(dir, function (err, files) { 5 | if (err) throw err 6 | 7 | files.forEach((fileName) => { 8 | let innerDir = `${dir}/${fileName}` 9 | 10 | if (fileName.indexOf('.') !== 0) { 11 | fs.stat(innerDir, function (err, stat) { 12 | 13 | if (stat.isDirectory()) { 14 | findMarkdown(innerDir, callback) 15 | } else { 16 | callback(innerDir) 17 | } 18 | }) 19 | } 20 | 21 | }) 22 | }) 23 | } 24 | 25 | module.exports = findMarkdown 26 | -------------------------------------------------------------------------------- /clockIn.js: -------------------------------------------------------------------------------- 1 | // 自动打卡,打开门户网站,复制代码至 console,不可关闭 2 | 3 | const timeReminder = ({ time, around = 0, callback = null }) => { 4 | if (!time) { 5 | return; 6 | } 7 | const targetTime = new Date(time).getTime(); 8 | const currentTime = new Date().getTime(); 9 | if (targetTime < currentTime) { 10 | return; 11 | } 12 | const t = randomNum( 13 | targetTime - currentTime - around, 14 | targetTime - currentTime + around 15 | ); 16 | 17 | console.log(`将于 ${timestampToTime(currentTime + t)} 执行`); 18 | 19 | setTimeout(() => { 20 | callback && callback(); 21 | }, t); 22 | }; 23 | 24 | function randomNum(min, max) { 25 | switch (arguments.length) { 26 | case 1: 27 | return parseInt(Math.random() * min + 1, 10); 28 | case 2: 29 | return parseInt(Math.random() * (max - min + 1) + min, 10); 30 | default: 31 | return 0; 32 | } 33 | } 34 | function timestampToTime(timestamp = Date.parse(new Date()), isMs = true) { 35 | const date = new Date(timestamp * (isMs ? 1 : 1000)); 36 | return `${date.getFullYear()}-${ 37 | date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1 38 | }-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`; 39 | } 40 | const getDate = time => { 41 | const date = new Date(); 42 | return `${date.getFullYear()}/${date.getMonth() + 43 | 1}/${date.getDate()} ${time}`; 44 | }; 45 | 46 | timeReminder({ 47 | time: getDate("12:26"), // 打卡时间 48 | // around: 30 * 60 * 1000, // 在打卡时间的阈值,time +- around 49 | around: 0, // 在打卡时间的阈值,time +- around 50 | callback: () => { 51 | // 执行页面的打卡函数或直接点击按钮 52 | try { 53 | window.checkIn(); 54 | } catch (e) { 55 | document 56 | .querySelector("#clockLink") 57 | .querySelector("button") 58 | .click(); 59 | } 60 | // window.close(); 61 | } 62 | }); 63 | -------------------------------------------------------------------------------- /docs/.vuepress/components/_doc.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | const CONFIG = require("../../config"); 2 | module.exports = { 3 | title: "blog", 4 | description: "blog from Qi", 5 | dest: "./dist", 6 | base: "/blog/", 7 | repo: "https://qishaoxuan.github.io/blog/", 8 | head: [ 9 | ["link", {rel: "icon", href: `/images/favicon.png`}], 10 | ["meta", {name: "theme-color", content: "#00adb5"}], 11 | ["meta", { 12 | name: "apple-mobile-web-app-capable", 13 | content: "yes" 14 | }], 15 | [ 16 | "meta", 17 | { 18 | name: "apple-mobile-web-app-status-bar-style", 19 | content: "black" 20 | } 21 | ], 22 | ["meta", { 23 | name: "msapplication-TileColor", 24 | content: "#00adb5" 25 | }], 26 | [ 27 | "meta", 28 | { 29 | name: "description", 30 | itemprop: "description", 31 | content: "blog from Qi" 32 | } 33 | ], 34 | ["meta", {itemprop: "name", content: "js_trick"}], 35 | ["meta", { 36 | itemprop: "image", 37 | content: "/js_tricks/images/favicon.png" 38 | }] 39 | ], 40 | markdown: { 41 | anchor: {permalink: false}, 42 | toc: {includeLevel: [1, 2]}, 43 | config: md => { 44 | md.use(require("markdown-it-include"), "./"); 45 | } 46 | }, 47 | plugins: [ 48 | require("./plugins/comment/index"), 49 | "vuepress-plugin-cat", 50 | "@vuepress/nprogress" 51 | ], 52 | themeConfig: { 53 | nav: [ 54 | { 55 | text: "css tricks", 56 | link: "https://qishaoxuan.github.io/css_tricks/" 57 | }, 58 | { 59 | text: "js tricks", 60 | link: "https://qishaoxuan.github.io/js_tricks/" 61 | }, 62 | { 63 | text: "about me", 64 | link: "https://qishaoxuan.github.io/animate_resume/" 65 | }, 66 | { 67 | text: "GitHub", 68 | link: "https://github.com/QiShaoXuan/blog" 69 | } 70 | ], 71 | sidebar: [ 72 | { 73 | title: "实现", 74 | collapsable: true, 75 | children: [ 76 | "/realize/promise", 77 | "/realize/call", 78 | "/realize/new", 79 | "/realize/bind", 80 | "/realize/curry", 81 | "/realize/throttleDebounce" 82 | ] 83 | }, 84 | { 85 | title: "JS", 86 | collapsable: true, 87 | children: [ 88 | "/js/eventloop", 89 | "/js/inherit", 90 | "/js/module", 91 | "/js/insertAdjacentHTML", 92 | "/js/implementation", 93 | "/js/messageChannel", 94 | "/js/documentFragment", 95 | "/js/copy", 96 | "/js/mutationObserver", 97 | "/js/getBoundingClientRect" 98 | ] 99 | }, 100 | { 101 | title: "HTML", 102 | collapsable: true, 103 | children: [ 104 | "/html/wx", 105 | "/html/optimal", 106 | "/html/url", 107 | "/html/meta", 108 | "/html/email" 109 | ] 110 | }, 111 | { 112 | title: "CSS", 113 | collapsable: true, 114 | children: ["/css/name", "/css/pseudo", "/css/selector", "/css/unit"] 115 | }, 116 | { 117 | title: "Basic", 118 | collapsable: true, 119 | children: ["/basic/sort"] 120 | }, 121 | { 122 | title: "算法", 123 | collapsable: true, 124 | children: [ 125 | "/leetcode/sort", 126 | "/leetcode/twoSum", 127 | "/leetcode/singleNumber" 128 | ] 129 | }, 130 | { 131 | title: "踩坑", 132 | collapsable: true, 133 | children: ["/keng/keng.md"] 134 | }, 135 | { 136 | title: "如果我是面试官", 137 | collapsable: true, 138 | children: ["/interview/interview.md"] 139 | } 140 | ] 141 | } 142 | }; 143 | -------------------------------------------------------------------------------- /docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | export default ({ 2 | Vue, // VuePress 正在使用的 Vue 构造函数 3 | options, // 附加到根实例的一些选项 4 | router, // 当前应用的路由实例 5 | siteData // 站点元数据 6 | }) => {} 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/.vuepress/override.styl: -------------------------------------------------------------------------------- 1 | $accentColor = #00adb5 2 | $textColor = #222831 3 | $borderColor = #eeeeee 4 | $codeBgColor = #282c34 -------------------------------------------------------------------------------- /docs/.vuepress/plugins/comment/comment.vue: -------------------------------------------------------------------------------- 1 | 606 | 607 | 612 | 631 | -------------------------------------------------------------------------------- /docs/.vuepress/plugins/comment/enhanceAppFile.js: -------------------------------------------------------------------------------- 1 | import Comment from "./comment.vue"; 2 | export default ({ Vue }) => { 3 | Vue.component("Comment", Comment); 4 | }; 5 | -------------------------------------------------------------------------------- /docs/.vuepress/plugins/comment/index.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("path"); 2 | module.exports = (options, ctx) => { 3 | return { 4 | enhanceAppFiles: resolve(__dirname, "enhanceAppFile.js"), 5 | globalUIComponents: "Comment" 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /docs/.vuepress/plugins/comment/initComment.js: -------------------------------------------------------------------------------- 1 | const CONFIG = require("../../../../config"); 2 | 3 | export default function initComment() { 4 | if (location.host.indexOf("localhost") !== -1) { 5 | return; 6 | } 7 | 8 | const body = document.querySelector(".gitalk-container"); 9 | const script = document.createElement("script"); 10 | 11 | script.src = "https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js"; 12 | body.appendChild(script); 13 | script.onload = () => { 14 | const commentConfig = Object.assign(CONFIG.gitalk, { 15 | id: window.location.pathname 16 | }); 17 | const gitalk = new Gitalk(commentConfig); 18 | gitalk.render("gitalk-container"); 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /docs/.vuepress/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiShaoXuan/blog/6a253819533266476e6bda7f0ec16b40ed359b09/docs/.vuepress/public/images/favicon.png -------------------------------------------------------------------------------- /docs/.vuepress/public/styles/reset.css: -------------------------------------------------------------------------------- 1 | html,body,h1,h2,h3,h4,h5,h6,div,dl,dt,dd,ul,ol,li,p,blockquote,pre,hr,figure,table,caption,th,td,form,fieldset,legend,input,button,textarea,menu{margin:0;padding:0;} 2 | header,footer,section,article,aside,nav,hgroup,address,figure,figcaption,menu,details{display:block;} 3 | table{border-collapse:collapse;border-spacing:0;} 4 | caption,th{text-align:left;font-weight:normal;} 5 | html,body,fieldset,img,iframe,abbr{border:0;} 6 | i,cite,em,var,address,dfn{font-style:normal;} 7 | [hidefocus],summary{outline:0;} 8 | li{list-style:none;} 9 | h1,h2,h3,h4,h5,h6,small{font-size:100%;} 10 | sup,sub{font-size:83%;} 11 | pre,code,kbd,samp{font-family:inherit;} 12 | q:before,q:after{content:none;} 13 | textarea{overflow:auto;resize:none;} 14 | label,summary{cursor:default;} 15 | a,button{cursor:pointer;} 16 | h1,h2,h3,h4,h5,h6,em,strong,b{font-weight:bold;} 17 | del,ins,u,s,a,a:hover{text-decoration:none;} 18 | body,textarea,input,button,select,keygen,legend{font:12px/1.14 arial,\5b8b\4f53;color:#333;outline:0;} 19 | body{background:#fff;} 20 | a,a:hover{color:#333;} 21 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # 关于 2 | 最初的设想把平常见到的问题和知识点放在 css tricksjs tricks,这样就能少说些花里胡哨的东西,言简意赅的记录问题和解决方法,但是当写 you need to know js 的时候,发现在 js tricks 这样全是方法代码的地方写大量文字的介绍好像并不合适,所以又重新组织了这个blog,同时把需要大量文字的记录放在这里。 3 | 4 | 这里只是学习的记录,不会过多讲解(或者说只是我懂的讲解) 5 | 6 | ## css tricks 7 | view online 8 | 9 | ## js tricks 10 | view online 11 | -------------------------------------------------------------------------------- /docs/always/README.md: -------------------------------------------------------------------------------- 1 | ## 判断可选链 2 | 3 | ```typescript 4 | function checkChaining(data: {} = {}, chain: string = "") { 5 | const chainArr = chain.split("."); 6 | if (chainArr.length === 0) { 7 | return data; 8 | } 9 | return chainArr.reduce((a, b) => { 10 | return a && a[b] ? a[b] : undefined; 11 | }, data); 12 | } 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/basic/sort.md: -------------------------------------------------------------------------------- 1 | # 排序 2 | 3 | ## 冒泡排序 4 | 5 | 通过重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成 6 | 7 | <<< ./other/sort/bubble.js 8 | 9 | ## 插入排序 10 | 11 | 通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入 12 | 13 | <<< ./other/sort/insertion.js 14 | 15 | ## 快速排序 16 | 17 | 1. 在数据集之中,选择一个元素作为"基准"(pivot)。 18 | 2. 所有小于"基准"的元素,都移到"基准"的左边;所有大于"基准"的元素,都移到"基准"的右边。 19 | 3. 对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。 20 | 21 | <<< ./other/sort/quick.js 22 | 23 | :::tip 24 | 上面的版本缺点是需要额外的存储器配置,以下为原地(in-place)分割方法 25 | ::: 26 | 27 | <<< ./other/sort/quick2.js 28 | 29 | ## 选择排序 30 | 31 | 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕 32 | 33 | <<< ./other/sort/selection.js 34 | 35 | ## 归并排序 36 | 37 | ### 递归法 38 | 39 | 1. 把 n 个元素看成 n 个长度为 l 的有序子表 40 | 2. 进行两两归并使记录关键字有序,得到 n/2 个长度为 2 的有序子表 41 | 3. 重复第 2 步直到所有记录归并成一个长度为 n 的有序表为止 42 | 43 | <<< ./other/sort/merge.js 44 | 45 | ## 堆排序 46 | 47 | <<< ./other/sort/heap.js 48 | 49 | ## 计数排序 50 | 51 | 1. 统计数组中每个值为 `i` 的元素出现的次数,存入数组 `C` 的第 `i` 项 52 | 2. 反向填充目标数组:将每个元素 `i` 放在新数组的第 `C[i]` 项,每放一个元素就将 `C[i]` 减去 1 53 | 54 | <<< ./other/sort/count.js 55 | 56 | ## 桶排序 57 | 58 | 桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点: 59 | 60 | 1. 在额外空间充足的情况下,尽量增大桶的数量 61 | 2. 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中 62 | 63 | 同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要 64 | 65 | <<< ./other/sort/bucket.js 66 | 67 | 68 | -------------------------------------------------------------------------------- /docs/css/name.md: -------------------------------------------------------------------------------- 1 | # 命名规则 2 | 3 | ## 常见难点与痛处 4 | 5 | #### 难以理解 6 | 7 | 每个人起名字的风格不同,可能有人习惯将样式写在同一类名下,有人又习惯将不同的样式区分类名(但是名字又只有作者自己才能意会,也许过一阵子也意会不了了)。 8 | 9 | #### 难以复用 10 | 11 | 通常来说,当我们复用 CSS 代码时,总是会发现有那么一个或两个样式跟现在需要的样式不同,因为这个样式很可能是当时作者认为是为特定元素而写的,或者它是从其他地方继承而来了一些属性,这时我们无法修改,只能再复制出一份代码。 12 | 13 | 于是新的问题又来了,代码不仅没复用成功,还增加了一倍的代码维护负担。 14 | 15 | #### 难以维护 16 | 17 | 不仅是上述的原因导致了维护困难。当我们更新一个页面的样式的时候,却破坏了另一个页面的样式,当我们决定覆盖它时,却又陷于优先度的问题。 18 | 19 | ## 模块化思想 20 | 21 | 在命名和组织 html 标签和 CSS 样式时,我们不应当从页面级的角度去思考,而应当将页面视为由无数个模块组成的,每个模块互不干扰,像乐高积木一样组织页面。 22 | 23 | 推崇模块化方法的三大模式如下 24 | 25 | ## OOCSS 26 | 27 | 面向对象的 CSS,OOCSS 核心思想是:对象是可重用的模式(pattern),其视觉外观不由上下文决定 28 | 29 | ### 核心思想 30 | 31 | #### 上下文无关 32 | 33 | 无论对象的位置在哪里,一个对象都应该看起来无差别,不应根据对象的上下文设置对象的样式。 34 | 35 | 例如,不是将侧边栏中的所有按钮都设置为橙色,将主区域中的所有按钮设置为蓝色,而是应该创建一个蓝色的按钮类,以及一个橙色的 modifier。这样做橙色按钮可以在任何地方使用,它们没有被绑定在侧边栏上,它们只是你的按钮样式之一。 36 | 37 | #### 皮肤(主题) 38 | 39 | 为常见的视觉模式创建可复用的类。 40 | 41 | 一个网页中结构是不可变,也可能是独立的,但是诸如背景颜色,边框等样式时可以抽离并复用的,应当将其分离出来单独创建。 42 | 43 | #### 使用 Class 44 | 45 | CSS 不应当由 HTML 标签决定, `.site-nav` 而不是 `#header ul`。 46 | 47 | #### 不使用 ID 48 | 49 | 尽量使用 class,id 选择器会扰乱优先级。 50 | 51 | ## BEM 52 | 53 | 三个字母分别代表 Block(块)、Element(元素)、Modifier(修饰符)。 54 | 55 | ### Block(块) 56 | 57 | 块是网页逻辑和功能的独立组件。 58 | 59 | 首先,块是可嵌套的。它们应该能被包含在另一个块中,而不会破坏任何样式。例如,可能在侧栏中有一个标签界面小部件的块,该块可能包含按钮,这些按钮也是一种单独的块。按钮的样式和选项卡式元素的样式不会相互影响,一个嵌套在另一个中,仅此而已。 60 | 61 | 其次,块是可重复的。界面应该能够包含同一块的多个实例。 62 | 63 | ### Element(元素) 64 | 65 | 元素是块的组成部分,它不能在块之外使用。一个不错的例子:一个导航菜单,它包含的项目在菜单的上下文之外没有意义。你不会为菜单项定义块,菜单本身应定义为块,而菜单项是其子元素。 66 | 67 | ### Modifier(修饰符) 68 | 69 | 修饰符定义块的外观和行为。例如,菜单块的外观的垂直或水平,取决于所使用的修饰符。 70 | 71 | ### 命名约定 72 | BEM 所做的另一件事是定义了非常严格的命名约定: 73 | 74 | `.block-name__element--modifier` 75 | 76 | 这看起来有点复杂,我来分解一下: 77 | 78 | - 名称以小写字母书写 79 | - 名称中的单词用连字符(-)分隔 80 | - 元素由双下划线(__)分隔 81 | - 修饰符由双连字符(--)分隔 82 | 83 | ### 不嵌套 CSS 84 | 85 | 使用 `.btn__price` 而不是 `.btn .btn__price` 。 86 | 87 | 即使是在 Sass 或 Less 也不该使用层级嵌套,但是可以使用 `.btn__text` 然后用 `.btn--orange .btn__text` 来覆盖应用了修饰符按钮的文本颜色 88 | 89 | ## SMACSS 90 | SMACSS 的含义是 CSS 的可扩展性和模块化架构(Scalable & Modular Architecture) 91 | 92 | SMACSS 更像是对 OOCSS 和 BEM 的扩展,即通过命名规则以更好的识别区分 CSS 类名的作用。 93 | 94 | ### 类别 95 | 96 | CSS 系统可能包含的规则定义的类别: 97 | - 基础(base) 规则是HTML元素的默认样式,如链接,段落和标题。 98 | - 布局(grid) 规则将页面分成几个部分,并将一个或多个模块组合在一起。它们只定义布局,而不管颜色或排版。 99 | - 模块(module)(又名“对象”或“块”)是可重用的,设计中的一个模块。例如,按钮,媒体对象,产品列表等。 100 | - 状态(state) 规则描述了模块或布局在特定状态下的外观。通常使用 JavaScript 应用或删除。例如,隐藏,扩展,激活等。 101 | - 主题(theme) 规则描述了模块或布局在主题应用时的外观,例如,在 Yahoo Mail 中,可以使用用户主题,这会影响页面上的每个模块。 102 | 103 | ### 命名约定前缀 104 | - 布局(grid)(.g-):将页面分割为几个大块,通常有头部、主体、主栏、侧栏、尾部等! 105 | - 模块(module)(.m-):通常是一个语义化的可以重复使用的较大的整体!比如导航、登录、注册、各种列表、评论、搜索等! 106 | - 元件(unit)(.u-):通常是一个不可再分的较为小巧的个体,通常被重复用于各种模块中!比如按钮、输入框、loading、图标等! 107 | - 功能(function)(.f-):为方便一些常用样式的使用,我们将这些使用率较高的样式剥离出来,按需使用,通常这些选择器具有固定样式表现,比如清除浮动等!不可滥用! 108 | - 皮肤(skin)(.s-):如果你需要把皮肤型的样式抽离出来,通常为文字色、背景色(图)、边框色等,非换肤型网站通常只提取文字色!非换肤型网站不可滥用此类! 109 | - 状态(.z-):为状态类样式加入前缀,统一标识,方便识别,她只能组合使用或作为后代出现(.u-ipt.z-dis{},.m-list li.z-sel{}),具体详见命名规则的扩展相关项。 110 | 111 | > 命名约定前缀参考自网易NEC 112 | 113 | ## 总结 114 | 115 | 以上皆为各框架的罗列,具体实践个人认为应当综合使用,命名规则应当更加详细,诸如代码规范应当更加详尽规定(待补充) 116 | 117 | -------------------------------------------------------------------------------- /docs/css/pseudo.md: -------------------------------------------------------------------------------- 1 | # 伪类和伪元素 2 | 3 | ## 区别 4 | 5 | ### 伪类 6 | 7 | - 伪类更多的定义的是状态,如`:hover`,或者说是一个可以使用 CSS 进行修饰的特定的特殊元素 8 | - 伪类使用一个冒号`:` 9 | 10 | ### 伪元素 11 | 12 | - 伪元素简单来说就是不存在于DOM文档树中的虚拟的元素,它们和HTML元素一样,但是你又无法使用JavaScript去获取,如`:before` 13 | - 伪元素使用两个冒号`::` 14 | 15 | 16 | ## 伪类 17 | 18 | 1. `:focus` 19 | 20 | 选择获得焦点的元素 21 | 22 | 2. `:visited` 23 | 24 | 选择已访问的链接 25 | 26 | 3. `:link` 27 | 28 | 选择未被访问的链接 29 | 30 | 4. `:active` 31 | 32 | 选择活动链接,即当链接被点击时的状态 33 | 34 | 35 | 5. `:lang` 36 | 37 | 选取带有以指定值开头的 lang 属性的元素 38 | 39 | ```css 40 | div:lang(hello){ 41 | background:red; 42 | } 43 | ``` 44 | 45 | ```html 46 |

foo

47 | ``` 48 | 49 | 6. `:required` 50 | 51 | 选择具有required 属性的表单元素 52 | 53 | 7. `:valid` 54 | 55 | 选择通过匹配正确的所要求的表单元素 56 | 57 | 8. `:invalid` 58 | 59 | 伪类指定一个不匹配指定要求的表单元素 60 | 61 | 6,7,8虽然能辅助表单验证,但好像并不能阻止提交,只能起到辅助提示的作用 62 | 63 | 9. `:not` 64 | 65 | 排除其他选择器 66 | 67 | ```css 68 | ul > li:not(:last-child)::after { 69 | float:left; 70 | } 71 | ``` 72 | 73 | 除了最后一个li其他都左浮动 74 | 75 | `:not`中可以写任意选择器 76 | 77 | 10. `:nth-child` 78 | 79 | 选择元素的第n个子元素 80 | 81 | ```css 82 | :nth-child(even) /* 下标为偶数的子元素 */ 83 | :nth-child(odd) /* 下标为奇数的子元素 */ 84 | :nth-child(3n) /* 下标为3的倍数的子元素 */ 85 | :nth-child(-n + 4) /* 下标小于4的子元素 */ 86 | ``` 87 | 88 | 11. `:checked` 89 | 选择已被选中的单选元素 90 | 91 | 12. `:only-child` 92 | 选择仅有一个子元素时的子元素 93 | 94 | 13. `:only-of-type` 95 | 选择父节点中仅有一种符合类型的元素 96 | 97 | ## 伪元素 98 | 99 | 1. `::selection` 100 | 101 | 设置选中文本的样式 102 | 103 | 2. `::placeholder` 104 | 105 | 设置表单元素`placeholder`属性的样式 106 | 107 | 3. `::first-letter` 108 | 109 | 设置段落的第一个字体的样式 110 | 111 | 4. `::first-line` 112 | 113 | 设置段落的第一行文字的样式 114 | 115 | 116 | -------------------------------------------------------------------------------- /docs/css/selector.md: -------------------------------------------------------------------------------- 1 | # 选择器 2 | 3 | 伪类和伪元素选择器见伪类和伪元素 4 | 5 | ## `>` 6 | 选择容器下的直接子代,而不是如`.container ul`选择所有符合条件的后代 7 | 8 | ## `+` 9 | 选择紧临的下一个兄弟元素 10 | 11 | ## `~` 12 | 选择随后的所有兄弟元素 13 | 14 | ## `X[attribute]` 15 | 选择所有具有attribute属性的元素 16 | ```css 17 | /* 设置所有带有 hidden 属性的元素为不可见 */ 18 | [hidden]{ 19 | display:none 20 | } 21 | ``` 22 | 23 | ## `X[attribute="yyy"]` 24 | 选择所有attribute属性值为yyy的元素 25 | 26 | ## `X[attribute^="yyy"]` 27 | 选择所有attribute属性值为yyy开头的元素 28 | 29 | ## `X[attribute*="yyy"]` 30 | 选择所有attribute属性值包含yyy的元素 31 | 32 | ## `X[attribute$="yyy"]` 33 | 选择所有attribute属性值为yyy结尾的元素 34 | 35 | ## `X[attribute~="yyy"]` 36 | 选择所有attribute以空格分割的属性值中包含yyy的元素 37 | 38 | -------------------------------------------------------------------------------- /docs/css/unit.md: -------------------------------------------------------------------------------- 1 | # 单位 2 | 3 | ## ch 4 | 5 | 数字 0 的宽度 6 | 7 | ## rem 8 | 9 | 相对长度单位。相对于根元素(html)`font-size`计算值的倍数 10 | 11 | ## em 12 | 13 | 相对长度单位。相对于当前对象内文本的字体尺寸。 14 | 15 | 如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸 16 | 17 | ## ex 18 | 19 | 相对长度单位。相对于字符 `x` 的高度。通常为字体高度的一半。 20 | 21 | 如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。 22 | 23 | > 测试记得设置`line-height:1` 24 | 25 | ## vw 26 | 27 | 相对于视口的宽度。视口被均分为100单位的vw 28 | 29 | 100vw包含滚动条的宽度,而`width:100%`不包括滚动条的宽度 30 | 31 | ## vh 32 | 33 | 相对于视口的高度。视口被均分为100单位的vh 34 | 35 | ## vmax 36 | 37 | 相对于视口的宽度或高度中较大的那个。其中最大的那个被均分为100单位的vmax 38 | 39 | ## vmin 40 | 41 | 相对于视口的宽度或高度中较小的那个。其中最小的那个被均分为100单位的vmin 42 | 43 | ## cm 44 | 45 | 厘米(Centimeters)。绝对长度单位。 46 | 47 | ## mm 48 | 49 | 毫米(Millimeters)。绝对长度单位。 50 | 51 | ## q 52 | 53 | 1/4毫米(quarter-millimeters)。绝对长度单位 54 | 55 | ## in 56 | 57 | 英寸(Inches)。绝对长度单位。 58 | 59 | ## pt 60 | 61 | 点(Points)。绝对长度单位。 62 | 63 | ## pc 64 | 65 | 派卡(Picas)。绝对长度单位。相当于我国新四号铅字的尺寸。 66 | 67 | ## 换算 68 | 69 | 1in = 72pt = 6pc = 96px = 2.54cm = 25.4mm 70 | 71 | ​ 72 | 73 | -------------------------------------------------------------------------------- /docs/html/email.md: -------------------------------------------------------------------------------- 1 | # 邮件 2 | 3 | ## 内容规范 4 | 5 | ### 邮件环境 6 | 邮件内容所在上下文或者说所在外部容器(以下简称环境)都是由邮箱服务商决定的,这就要求邮件内容需要在任何一种情况下都要正确显示。 7 | 8 | 这些环境可能是以下某几种情况: 9 | 10 | - 可能是个iframe,你的内容是被放在body里面的;可能只是个div,你的内容就被放在这个div里面。 11 | - 可能邮箱自身设置了些css,他可能对你产生未知的影响。 12 | - 可能根本没有申明doctype,即使申明了,也不是你想要的doctype。 13 | 14 | ### 避免被嵌套在不正确的容器里 15 | 惑:因为容器可能是body或div,所以,我们邮件内容不应该是一个完整的html。 16 | 17 | 解:所以邮件内容应该是以div为根节点的html片段。 18 | 19 | ### 避免css冲突或被覆盖 20 | 惑:因为环境中可能已经设置了css,比如一些reset、一些.class。 21 | 22 | 解:所以我们只能使用行内style来确保我们的效果,并且在内容根节点上设置基础style,并且尽量使用div、span等无语义标签。 23 | 24 | ```html 25 | 26 |
27 | 内容区域 28 |
29 | 30 |
31 |
32 | 内容区域 33 |
34 |
35 | 36 |

37 | 38 |
39 | ``` 40 | 41 | ### 避免盒模型错误 42 | 惑:因为doctype的不确定性,我们在写style的时候,应该考虑无论doctype是什么情况,都可以正常显示,doctype影响最大的就是盒模型的解析。 43 | 44 | 解:所以我们要将盒模型拆分开来写,比如我们将原本要定义在某个div上的height和padding分别写到这个div和他的父元素或子元素上。 45 | 46 | ```html 47 |
内容
48 | 49 |
内容
50 | ``` 51 | 52 | ### 其他注意事项 53 | - 因为只能使用行内style,所以清除浮动需要使用额外标签。 54 | - 避免使用绝对定位,可能会被过滤。 55 | - 避免使用js,可能会被过滤。 56 | - 避免使用table布局,不易于修改维护。 57 | - 背景图片或内容图片上的文字信息,必须在代码中可见。 58 | - 如果没有特殊要求,所有a链接都要从新窗口打开,即target="_blank",且a标签内容不能为空。 59 | - 所有链接必须设置使用颜色、是否下划线,即style="text-decoration:;color:;"。 60 | - 重点检查ie!!! 61 | 62 | ```html 63 |
64 |
65 |
66 | 69 |

你的iPad够有料吗?iPad不等于愤怒的小鸟!不等于切水果!下载网易阅读,给你的iPad添点料,打造你独一无二的iPad!

70 |
71 |
下载网易阅读
72 |
73 |
74 | ``` 75 | 76 | ### 发现的问题及解决方案 77 | 78 | 问题:部分智能手机的邮件客户端可能会有只显示部分的bug(宽度被截)。 79 | 80 | 解决:在外面套一个同宽的table即可。 81 | 82 | ```html 83 |
84 |
85 | ...... 86 |
87 |
88 | ``` 89 | 90 | ## 邮件模板 91 | 92 | ```html 93 |
94 |
95 | 96 | 97 | 98 |
99 |
100 | 101 |
102 |
103 |
104 | 105 | 106 | 107 |
108 |
109 |
110 | ``` 111 | -------------------------------------------------------------------------------- /docs/html/meta.md: -------------------------------------------------------------------------------- 1 | # 常见 meta 标签 2 | 3 | ## 网页相关信息 4 | 5 | ### 网页关键字 (SEO) 6 | ```html 7 | 8 | ``` 9 | 10 | ### 网页描述 (SEO) 11 | ```html 12 | 13 | ``` 14 | 15 | ### 标注网页的作者或制作组 16 | ```html 17 | 18 | ``` 19 | 20 | ### 编辑器的说明 21 | ```html 22 | 23 | ``` 24 | 25 | ### 标注版权 26 | ```html 27 | 28 | ``` 29 | 30 | ### 通知搜索引擎多少天访问一次 31 | ```html 32 | 33 | ``` 34 | 35 | ## http-equiv 36 | 37 | ### 设定网页的到期时间。一旦网页过期,必须到服务器上重新传输 38 | ```html 39 | 40 | ``` 41 | ### 禁止浏览器从本地计算机的缓存中访问页面内容 42 | ```html 43 | 44 | ``` 45 | 46 | ### 自动刷新并指向新页面。其中的1是指停留1秒钟后自动刷新到URL网址 47 | ```html 48 | 49 | ``` 50 | 51 | ### 如果网页过期,那么存盘的cookie将被删除 52 | 必须使用GMT的时间格式 53 | ```html 54 | 55 | ``` 56 | 57 | ### 设定页面使用的字符集 58 | ```html 59 | 60 | ``` 61 | 62 | ### 设定显示语言 63 | ```html 64 | 65 | ``` 66 | 67 | ### 页面中脚本的类型 68 | ```html 69 | 70 | ``` 71 | 72 | ## IOS 73 | 74 | ### 添加到主屏后的标题 75 | ```html 76 | 77 | ``` 78 | 79 | ### 是否启用 WebApp 全屏模式,删除苹果默认的工具栏和菜单栏 80 | ```html 81 | 82 | ``` 83 | 84 | ### 添加智能 App 广告条 Smart App Banner 85 | ```html 86 | 87 | ``` 88 | 89 | ### 设置苹果工具栏颜色 90 | ```html 91 | 92 | ``` 93 | 94 | ## windows 95 | 96 | ### 网页主题颜色 97 | 目前只发现 chrome 的 app 顶部工具栏会根据该色值变色 98 | 99 | 在移动端使用 chrome app 打开 100 | 101 | ```html 102 | 103 | ``` 104 | ### Windows 8 磁贴图标 (即开始栏的icon) 105 | 106 | ```html 107 | 108 | ``` 109 | 110 | ## QQ 111 | 112 | ### QQ强制竖屏 113 | ```html 114 | 115 | ``` 116 | 117 | ### QQ强制全屏 118 | ```html 119 | 120 | ``` 121 | 122 | ### QQ应用模式 123 | ```html 124 | 125 | ``` 126 | 127 | ## UC 128 | 129 | ### UC强制竖屏 130 | ```html 131 | 132 | ``` 133 | ### UC强制全屏 134 | ```html 135 | 136 | ``` 137 | ### UC应用模式 138 | ```html 139 | 140 | ``` 141 | 142 | 143 | ## 其他 144 | 145 | ### 双内核浏览器优先加载webkit内核 146 | ```html 147 | 148 | ``` 149 | 150 | ### 双内核浏览器优先加载IE兼容模式 151 | ```html 152 | 153 | ``` 154 | 155 | -------------------------------------------------------------------------------- /docs/html/optimal.md: -------------------------------------------------------------------------------- 1 | # 前端性能优化 2 | 3 | ## CSS 4 | 1. 优化选择器路径:健全的css选择器固然是能让开发看起来更清晰,然后对于css的解析来说却是个很大的性能问题,因此相比于 .a .b .c{} ,更倾向于大家写.c{}。 5 | 2. 压缩文件:尽可能的压缩你的css文件大小,减少资源下载的负担。 6 | 3. 选择器合并:把有共同的属性内容的一系列选择器组合到一起,能压缩空间和资源开销 7 | 4. 精准样式:尽可能减少不必要的属性设置,比如你只要设置{padding-left:10px}的值,那就避免{padding:0 0 0 10px}这样的写法 8 | 5. 雪碧图:在合理的地方把一些小的图标合并到一张图中,这样所有的图片只需要一次请求,然后通过定位的方式获取相应的图标,这样能避免一个图标一次请求的资源浪费。 9 | 6. 避免通配符:.a .b *{} 像这样的选择器,根据从右到左的解析顺序在解析过程中遇到通配符(*)回去遍历整个dom的,这样性能问题就大大的了。 10 | 7. 少用Float:Float在渲染时计算量比较大,尽量减少使用。 11 | 8. 0值去单位:对于为0的值,尽量不要加单位,增加兼容性 12 | 13 | ## HTML 14 | 1. 避免再HTML中直接写css代码。 15 | 2. 使用Viewport加速页面的渲染。 16 | 3. 使用语义化标签,减少css的代码,增加可读性和SEO。 17 | 4. 减少标签的使用,dom解析是一个大量遍历的过程,减少无必要的标签,能降低遍历的次数。 18 | 5. 避免src、href等的值为空。 19 | 6. 减少dns查询的次数。 20 | 21 | ## JS 22 | 1. 尽可能把script标签放到body之后,避免页面需要等待js执行完成之后dom才能继续执行,最大程度保证页面尽快的展示出来。 23 | 2. 尽可能合并script代码, 24 | 3. css能干的事情,尽量不要用JavaScript来干。毕竟JavaScript的解析执行过于直接和粗暴,而css效率更高。 25 | 4. 尽可能压缩的js文件,减少资源下载的负担 26 | 5. 尽可能避免在js中逐条操作dom样式,尽可能预定义好css样式,然后通过改变样式名来修改dom样式,这样集中式的操作能减少reflow或repaint的次数。 27 | 6. 尽可能少的在js中创建dom,而是预先埋到HTML中用display:none来隐藏,在js中按需调用,减少js对dom的暴力操作。 28 | 29 | ## 其他 30 | 1. 防抖,节流处理 31 | 2. 懒加载,懒执行 32 | -------------------------------------------------------------------------------- /docs/html/url.md: -------------------------------------------------------------------------------- 1 | # 从用户输入URL到浏览器呈现页面经过了哪些过程 2 | 3 | ### DNS 解析 4 | 1. 浏览器根据地址去本身缓存中查找dns解析记录,如果有,则直接返回IP地址,否则浏览器会查找操作系统中(hosts文件)是否有该域名的dns解析记录,如果有则返回。 5 | 2. 如果浏览器缓存和操作系统hosts中均无该域名的dns解析记录,或者已经过期,此时就会向域名服务器发起请求来解析这个域名。 6 | 3. 请求会先到LDNS(本地域名服务器),让它来尝试解析这个域名,如果LDNS也解析不了,则直接到根域名解析器请求解析 7 | 4. 根域名服务器给LDNS返回一个所查询余的主域名服务器(gTLDServer)地址。 8 | 5. 此时LDNS再向上一步返回的gTLD服务器发起解析请求。 9 | 6. gTLD服务器接收到解析请求后查找并返回此域名对应的Name Server域名服务器的地址,这个Name Server通常就是你注册的域名服务器(比如阿里dns、腾讯dns等) 10 | 7. Name Server域名服务器会查询存储的域名和IP的映射关系表,正常情况下都根据域名得到目标IP记录,连同一个TTL值返回给DNS Server域名服务器 11 | 8. 返回该域名对应的IP和TTL值,Local DNS Server会缓存这个域名和IP的对应关系,缓存的时间有TTL值控制。 12 | 9. 把解析的结果返回给用户,用户根据TTL值缓存在本地系统缓存中,域名解析过程结束。 13 | 14 | ### HTTP请求发起和响应 15 | 16 | 1. 用户输入URL,浏览器获取到URL 17 | 2. 浏览器(应用层)进行DNS解析(如果输入的是IP地址,此步骤省略) 18 | 3. 根据解析出的IP地址+端口,浏览器(应用层)发起HTTP请求,请求中携带(请求头header(也可细分为请求行和请求头)、请求体body), 19 | 20 | > header包含: 21 | > 22 | > > 请求的方法(get、post、put..) 23 | > > 协议(http、https、ftp、sftp…) 24 | > > 目标url(具体的请求路径已经文件名) 25 | > > 一些必要信息(缓存、cookie之类) 26 | > > 27 | > > body包含: 28 | > > 29 | > > 请求的内容 30 | 31 | 4. 请求到达传输层,tcp协议为传输报文提供可靠的字节流传输服务,它通过三次握手等手段来保证传输过程中的安全可靠。通过对大块数据的分割成一个个报文段的方式提供给大量数据的便携传输。 32 | 5. 到网络层, 网络层通过ARP寻址得到接收方的Mac地址,IP协议把在传输层被分割成一个个数据包传送接收方。 33 | 6. 数据到达数据链路层,请求阶段完成 34 | 7. 接收方在数据链路层收到数据包之后,层层传递到应用层,接收方应用程序就获得到请求报文。 35 | 8. 接收方收到发送方的HTTP请求之后,进行请求文件资源(如HTML页面)的寻找并响应报文 36 | 9. 发送方收到响应报文后,如果报文中的状态码表示请求成功,则接受返回的资源(如HTML文件),进行页面渲染。 37 | 38 | ### 网页渲染 39 | 40 | 1. 浏览器通过HTMLParser根据深度遍历的原则把HTML解析成DOM Tree。 41 | 2. 将CSS解析成CSS Rule Tree(CSSOM Tree)。 42 | 3. 根据DOM树和CSSOM树来构造render Tree。 43 | 4. layout:根据得到的render tree来计算所有节点在屏幕的位置。 44 | 5. paint:遍历render树,并调用硬件图形API来绘制每个节点。 45 | 6. 当遇到 `script` 标签时会等待其中 `js` 代码执行完成后继续执行上述步骤(会造成阻塞) 46 | 47 | > [参考](https://juejin.im/post/5bbaa549e51d450e827b6b13) 48 | -------------------------------------------------------------------------------- /docs/html/wx.md: -------------------------------------------------------------------------------- 1 | # 微信小程序的一些注意点 2 | 3 | ## 路由配置 4 | 5 | 在 `app.json` 中 `pages` 定义的第一个页面为路由起始页 6 | 7 | ## 不支持 SVG 8 | 9 | 解决方案: 10 | 11 | 1. 使用 iconfont 替换单色图标 12 | 2. 使用图片代替彩色图标 13 | 14 | ## webview 相关 15 | webview 相当于小程序的 iframe 16 | 17 | 1. webview 加载完成后会自动铺满整个小程序页面,盖住页面上的元素。 18 | 19 | 解决方案: 20 | 21 | 使用 cover-view 标签,在安卓系统中需要通过 `setTimeout`,在加载完成后显示 cover-view 22 | 23 | 2. webview 中不显示 input 24 | 25 | ## === 存在隐式转换 26 | 27 | 解决方案: 28 | 29 | 使用 == 替换 30 | 31 | ## 数组的数据监听存在问题 32 | 33 | ```vue 34 | 35 | 36 | ``` 37 | ```js 38 | nx.Component({ 39 | data: { 40 | activeInput: [] 41 | }, 42 | methods: { 43 | codeInput(inEvent) { 44 | const index = Number(inEvent.target.dataset.index); 45 | const value = inEvent.detail.value; 46 | 47 | this.setData({ [`activeInput.${index}`]: value }); 48 | }, 49 | } 50 | }); 51 | ``` 52 | 53 | 解决方案: 54 | 55 | 将 data 写做类数组的形式 56 | 57 | ```js 58 | nx.Component({ 59 | data: { 60 | activeInput: { 61 | 0: '', 62 | 1: '', 63 | 2: '', 64 | 3: '', 65 | 4: '', 66 | 5: '', 67 | length: 6 68 | } 69 | }, 70 | }); 71 | ``` 72 | 73 | ## cover-view 注意 74 | 75 | 1. 不能通过 `z-index` 来设置 cover-view 的层级,可以使用加载顺序来影响它的层级 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/interview/interview.md: -------------------------------------------------------------------------------- 1 | # 我会考什么 2 | 3 | 1. 写输出,说原因 4 | ```js 5 | const map = new Map() 6 | 7 | map.set(["aa"], 111) 8 | 9 | console.log(map.get(["aa"])) 10 | ``` 11 | 12 | 2. 写输出,如何正确输出 3 13 | 14 | ```js 15 | function createIncrement(i) { 16 | let value = 0; 17 | function increment() { 18 | value += i; 19 | console.log(value); 20 | const message = `Current value is ${value}`; 21 | return function logValue() { 22 | console.log(message); 23 | }; 24 | } 25 | 26 | return increment; 27 | } 28 | 29 | const inc = createIncrement(1); 30 | const log = inc(); // 打印 1 31 | inc(); // 打印 2 32 | inc(); // 打印 3 33 | log(); // 打印 1 34 | ``` 35 | 36 | 3. react hook 中 useEffect 的第二个参数为什么是一个数组而不是可以传多个值 37 | -------------------------------------------------------------------------------- /docs/js/README.md: -------------------------------------------------------------------------------- 1 | # you need to kow 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/js/copy.md: -------------------------------------------------------------------------------- 1 | # 深拷贝 & 浅拷贝 2 | 众所周知,Object是引用数据类型,存储在内存的堆中,浅拷贝只是拷贝了另一个对象的内存地址,所以在修改时会同时修改另一个对象,而深拷贝会开辟新的内存地址,所以不会影响另一个对象 3 | 4 | ### 浅拷贝 5 | ```javascript 6 | let obj1 = {a:'1',b:{c:1}} 7 | // 直接赋值 8 | let obj2 = obj1 9 | // 使用Object.assign 10 | //Object.assign()拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值 11 | let obj3 = Object.assign({},obj1) 12 | ``` 13 | 14 | ### 深拷贝 15 | ```javascript 16 | // JSON.parse && JSON.stringify 17 | // 性能最高,速度最快,但是只能拷贝纯json 18 | function deepClone(obj){ 19 | let str, newobj = obj.constructor === Array ? [] : {}; 20 | if(typeof obj !== 'object'){ 21 | return; 22 | } else if(window.JSON){ 23 | str = JSON.stringify(obj) 24 | newobj = JSON.parse(str) 25 | } else { 26 | for(let i in obj){ 27 | newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i] 28 | } 29 | } 30 | return newobj 31 | } 32 | 33 | // 递归 34 | function deepClone(initalObj, finalObj ={}) { 35 | for (let i in initalObj) { 36 | let prop = initalObj[i] 37 | if(prop === finalObj) { 38 | continue 39 | } 40 | if (typeof prop === 'object') { 41 | finalObj[i] = (prop.constructor === Array) ? [] : {} 42 | arguments.callee(prop, finalObj[i]); 43 | } else { 44 | finalObj[i] = prop 45 | } 46 | } 47 | return finalObj 48 | } 49 | 50 | // Object.create() 51 | function deepClone(initalObj, finalObj) { 52 | let obj = finalObj || {} 53 | for (let i in initalObj) { 54 | let prop = initalObj[i] 55 | if(prop === obj) { 56 | continue 57 | } 58 | if (typeof prop === 'object') { 59 | obj[i] = (prop.constructor === Array) ? [] : Object.create(prop) 60 | } else { 61 | obj[i] = prop 62 | } 63 | } 64 | return obj 65 | } 66 | 67 | // History API 68 | function deepClone(obj) { 69 | const oldState = history.state 70 | history.replaceState(obj, document.title) 71 | const copy = history.state 72 | history.replaceState(oldState, document.title) 73 | return copy 74 | } 75 | 76 | //MessageChannel 77 | //异步方法,用时需注意 78 | const obj = ... 79 | const clone = await deepClone(obj) 80 | function deepClone(obj) { 81 | return new Promise(resolve => { 82 | const {port1, port2} = new MessageChannel() 83 | port2.onmessage = ev => resolve(ev.data) 84 | port1.postMessage(obj) 85 | }); 86 | } 87 | 88 | // lodash 中的方法 89 | function deepClone(obj) { 90 | var copy; 91 | 92 | if (null == obj || "object" != typeof obj) return obj; 93 | 94 | if (obj instanceof Date) { 95 | copy = new Date(); 96 | copy.setTime(obj.getTime()); 97 | return copy; 98 | } 99 | 100 | if (obj instanceof Array) { 101 | copy = []; 102 | for (var i = 0, len = obj.length; i < len; i++) { 103 | copy[i] = deepClone(obj[i]); 104 | } 105 | return copy; 106 | } 107 | 108 | if (obj instanceof Function) { 109 | copy = function() { 110 | return obj.apply(this, arguments); 111 | } 112 | return copy; 113 | } 114 | 115 | if (obj instanceof Object) { 116 | copy = {}; 117 | for (var attr in obj) { 118 | if (obj.hasOwnProperty(attr)) copy[attr] = deepClone(obj[attr]); 119 | } 120 | return copy; 121 | } 122 | 123 | throw new Error("Unable to copy obj as type isn't supported " + obj.constructor.name); 124 | } 125 | ``` 126 | 127 | -------------------------------------------------------------------------------- /docs/js/documentFragment.md: -------------------------------------------------------------------------------- 1 | # DocumentFragment 2 | `DocumentFragment`接口表示没有父级的最小文档对象 3 | 4 | 因为`DocumentFragment`不是真实 DOM 树的其中一部分,它的变化不会引起 DOM 树的重新渲染操作(reflow) ,因此不会导致性能问题。 5 | 6 | 当我们需要修改多个节点时,可以创建一个`DocumentFragment`,在此节点进行添加(append)或被插入(inserted)操作。因为所有的节点会被一次性插入到文档中,而这个操作仅发生一个重渲染的操作,而不是每个节点分别被插入到文档中,因为后者会发生多次重渲染的操作。 7 | 8 | ```javascript 9 | let frag = document.createDocumentFragment() 10 | for (let i = 0; i < 100; i++) { 11 | let p = document.createElement("P") 12 | let text = document.createTextNode(i) 13 | p.appendChild(text) 14 | frag.appendChild(p) 15 | } 16 | document.body.appendChild(frag) 17 | ``` -------------------------------------------------------------------------------- /docs/js/eventloop.md: -------------------------------------------------------------------------------- 1 | # 事件循环(Event Loop) 2 | 3 | ## 单线程的原因 4 | 5 | > 单线程与之用途有关,单线程能够保证一致性,如果有两个线程,一个线程点击了一个元素,另一个删除了一个元素,浏览器以哪一个为准? 6 | 7 | 单线程指的是单个脚本只能在一个线程上运行,而不是 JavaScript 引擎只有一个线程。 8 | 9 | ## Event Loop 10 | 11 | - Javascript是单线程的,所有的同步任务都会在主线程中执行。 12 | 13 | - 主线程之外,还有一个任务队列。每当一个异步任务有结果了,就往任务队列里塞一个事件。 14 | 15 | - 当主线程中的任务,都执行完之后,系统会 “依次” 读取任务队列里的事件。与之相对应的异步任务进入主线程,开始执行。 16 | 17 | - 异步任务之间,会存在差异,所以它们执行的优先级也会有区别。大致分为 微任务(micro task,如:Promise、MutaionObserver等)和宏任务(macro task,如:setTimeout、setInterval、I/O等)。同一次事件循环中,微任务永远在宏任务之前执行。 18 | 19 | - 主线程会不断重复上面的步骤,直到执行完所有任务。 20 | -------------------------------------------------------------------------------- /docs/js/getBoundingClientRect.md: -------------------------------------------------------------------------------- 1 | # getBoundingClientRect 2 | 3 | `rectObject = element.getBoundingClientRect()` 4 | 5 | 返回值是一个 `DOMRect` 对象,`DOMRect` 对象包含了一组用于描述元素边框的只读属性——left、top、right、bottom、x 和 y,单位为像素。除了 width 和 height 外的属性都是相对于**视口**的左上角位置而言的。 6 | 7 | ```javascript 8 | DOMRect = { 9 | bottom: --, 10 | height: --, 11 | left: --, 12 | right: --, 13 | top: --, 14 | width: --, 15 | x: --, 16 | y: --, 17 | } 18 | ``` 19 | 20 | 如需获取相对于整个网页左上角定位的属性值,则还需加上当前的滚动位置,配合 `window.pageXOffset` 和 `window.pageYOffset` 使用 21 | -------------------------------------------------------------------------------- /docs/js/implementation.md: -------------------------------------------------------------------------------- 1 | # document.implementation 2 | 3 | implementation 属性可返回处理该文档的 DOMImplementation 对象。 4 | 5 | 如果需要将一段 html 字符串转换为 Document Object Model (文档对象模型),而不影响到当前的html内容,可以通过document.implementation.createHTMLDocument创建一个新的document实现 6 | 7 | ```javascript 8 | function parseHTML(str) { 9 | let tmp = document.implementation.createHTMLDocument() 10 | tmp.body.innerHTML = str 11 | return tmp.body.children[0] 12 | } 13 | 14 | parseHTML(htmlString) 15 | ``` 16 | 17 | -------------------------------------------------------------------------------- /docs/js/inherit.md: -------------------------------------------------------------------------------- 1 | # 原型继承 2 | 3 | 在 ES6 非常普及的现在,被人突然问到如何使用 ES5 实现原型继承还是真是有点懵。所以特地记下。 4 | 5 | ## ES6 6 | 7 | ```js 8 | class Animal{ 9 | constructor(){} 10 | } 11 | class Cat extends Animal{ 12 | constructor(){ 13 | super() 14 | } 15 | } 16 | ``` 17 | 18 | ## ES5 19 | 20 | ```js 21 | function Animal(){ 22 | this.type = 'Animal' 23 | this.eat = function(){} 24 | } 25 | 26 | function inherit(parent,child) { 27 | const F = function(){} 28 | F.prototype = parent.prototype 29 | child.prototype = new F() 30 | child.constructor = child 31 | } 32 | 33 | function Cat(props){ 34 | Animal.call(this,props) 35 | this.name = 'Cat' 36 | } 37 | 38 | inherit(Animal,Cat) 39 | ``` 40 | 41 | 仅使用 `call` 方法调用 `Animal` 构造函数并不算实现继承,因为对象的原型是: 42 | 43 | ``` 44 | new PrimaryStudent() ----> PrimaryStudent.prototype ----> Object.prototype ----> null 45 | ``` 46 | 47 | 所以需要通过一个媒介(一个空函数),将原型链桥接过来,成为: 48 | 49 | ``` 50 | new PrimaryStudent() ----> PrimaryStudent.prototype ----> Student.prototype ----> Object.prototype ----> null 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/js/insertAdjacentHTML.md: -------------------------------------------------------------------------------- 1 | # insertAdjacent HTML/Text 2 | 3 | ## insertAdjacentHTML 4 | 5 | `insertAdjacentHTML()` 将指定的文本解析为HTML或XML,并将结果节点插入到DOM树中的指定位置。它不会重新解析它正在使用的元素,因此它不会破坏元素内的现有元素。这避免了额外的序列化步骤,使其比直接innerHTML操作更快。 6 | 7 | ```javascript 8 | element.insertAdjacentHTML(position, htmlString) 9 | ``` 10 | 11 | **position是相对于元素的位置,并且必须是以下字符串之一 :** 12 | 13 | - 'beforebegin' 14 | 元素自身的前面。 15 | - 'afterbegin' 16 | 插入元素内部的第一个子节点之前。 17 | - 'beforeend' 18 | 插入元素内部的最后一个子节点之后。 19 | - 'afterend' 20 | 元素自身的后面。 21 | 22 | ## insertAdjacentText 23 | 24 | 使用方法同上 `insertAdjacentHTML()`,应在仅插入文本时使用,这样可以不经过HTML解释器的转换,提高性能。 25 | 26 | ```javascript 27 | element.insertAdjacentText(position, htmlString) 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/js/messageChannel.md: -------------------------------------------------------------------------------- 1 | # MessageChannel 2 | > `MessageChannel`接口允许我们创建一个新的消息通道,并通过它的两个MessagePort 属性发送数据。 3 | 4 | `MessageChannel`创建了两个可通信的频道,每个频道可以通过`postMessage`方法发送信息,而另一个频道通过`onmessage`回调方法接受信息 5 | 6 | ```javascript 7 | const mc = new MessageChannel() 8 | let p1 = mc.port1 9 | let p2 = mc.port2 10 | p1.onmessage = function(e){console.log("port1 receive " + e.data)} 11 | p2.onmessage = function(e){console.log("port2 receive " + e.data)} 12 | p1.postMessage("hello, world") 13 | p2.postMessage("hi,world") 14 | ``` 15 | ### 用途 16 | - html和iframe之间的通讯 17 | - web worker之间的通讯 -------------------------------------------------------------------------------- /docs/js/module.md: -------------------------------------------------------------------------------- 1 | # 模块 2 | 3 | 在使用 `rollup` 或者 `browserify` 时总遇到打包模式选择的问题,这里记录总结一下。 4 | 5 | ## what ? 6 | 7 | - 将一个复杂的程序根据不同的规则(逻辑,分工)分成不同的模块,使之条理的组合在一起工作 8 | - 模块的内部数据与实现是私有的,外部仅能通过模块暴露的方法与属性与之通信或调用 9 | 10 | ## why ? 11 | 12 | - 避免命名冲突(减少命名空间污染) 13 | - 更好的分离, 按需加载 14 | - 更高复用性 15 | - 高可维护性 16 | 17 | ## “原始”的模块化 18 | 19 | “原始”指的是时间上的原始,存在于大部分前后未分离的项目中 20 | 21 | 存在的问题: 22 | - 全局作用域下容易造成变量冲突 23 | - 外部可以随意更改内部的数据和方法,维护困难 24 | - 文件只能按照 `script` 的书写顺序进行加载,会造成多个请求 25 | - 开发人员必须主观解决模块和代码库的依赖关系 26 | - 在大型项目中各种资源难以管理,长期积累的问题导致代码库混乱不堪 27 | 28 | ### 全局function模式 29 | 将不同的功能封装成不同的全局函数 30 | 31 | ```js 32 | function foo(){} 33 | function bar(){} 34 | ``` 35 | 36 | ### namespace (命名空间) 37 | 38 | 将数据和功能放在对象中 39 | 40 | ```js 41 | const module1 = { 42 | data:'https://qishaoxuan.github.io/blog/', 43 | foo:function(){}, 44 | bar:function(){} 45 | } 46 | ``` 47 | 48 | ### IIFE (立即调用的函数表达式) 49 | 50 | 匿名函数自调用(闭包) 51 | 52 | 通过在全局对象 `window` 上挂载属性或方法来暴露接口 53 | 54 | 保证模块独立性的同时,也使得模块之间的依赖关系变得明显 55 | 56 | ```js 57 | (function(window, $) { 58 | let data = 'www.baidu.com' 59 | //操作数据的函数 60 | function foo() { 61 | console.log(otherFun()) 62 | } 63 | function bar() {} 64 | function otherFun() { 65 | return 'hello, world' 66 | } 67 | //暴露行为 68 | window.module1 = { foo, bar } 69 | })(window, jQuery) 70 | ``` 71 | ```html 72 | 73 | 74 | 77 | ``` 78 | 79 | ## 模块化规范 80 | 81 | 为了解决上述“原始”方法的问题,不同的模块规范出现了。 82 | 83 | ### CommonJS 84 | 85 | 通过 `require` 方法来同步加载所要依赖的其他模块,然后通过 `exports` 或 `module.exports` 来导出需要暴露的接口 86 | 87 | nodejs 采用该规范 88 | 89 | ```js 90 | // modle1.js 91 | const foo = 1 92 | const bar = () => {return 'hello, world'} 93 | 94 | module.exports.foo = foo 95 | module.exports.bar = bar 96 | 97 | // 也可以写为 98 | 99 | module.exports = { 100 | foo:foo, 101 | bar:bar 102 | } 103 | ``` 104 | ```js 105 | // main.js 106 | const module1 = require('./module1.js') 107 | 108 | function aa() { 109 | console.log(module1.bar()) 110 | } 111 | ``` 112 | 113 | `CommonJS` 加载模块是同步的,在服务器环境下是没问题的,然而在浏览器中,同步加载会导致性能、可用性、调试和跨域访问等问题。借助 `browserify` 可以解决,但是也使得下述两种规范的诞生。 114 | 115 | ### AMD 116 | 117 | AMD 规范只有一个主要接口 define(id?, dependencies?, factory),它要在声明模块的时候指定所有的依赖 dependencies,并且还要当做形参传到 factory 中,对于依赖的模块提前执行,依赖前置。 118 | 119 | ```js 120 | define("module", ["dep1", "dep2"], function(d1, d2) { 121 | return someExportedValue 122 | }); 123 | require(["module", "../file"], function(module, file) { /* ... */ }) 124 | ``` 125 | 126 | 优点: 127 | - 适合在浏览器环境中异步加载模块 128 | - 可以并行加载多个模块 129 | 130 | 缺点: 131 | - 提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不顺畅 132 | - 不符合通用的模块化思维方式,是一种妥协的实现 133 | 134 | ### CMD 135 | 136 | CMD 与 AMD 的区别 137 | 138 | - 对于依赖的模块AMD是提前执行,CMD是延迟执行。不过RequireJS从2.0开始,也改成可以延迟执行(根据写法不同,处理方式不通过) 139 | - CMD推崇依赖就近,AMD推崇依赖前置 140 | 141 | ```js 142 | // module1.js 143 | //定义没有依赖的模块 144 | define(function(require, exports, module){ 145 | exports.foo = value 146 | module.exports = value 147 | }) 148 | ``` 149 | ```js 150 | // module4.js 151 | //定义有依赖的模块 152 | define(function(require, exports, module){ 153 | //引入依赖模块(同步) 154 | var module2 = require('./module2') 155 | //引入依赖模块(异步) 156 | require.async('./module3', function (m3) { 157 | }) 158 | //暴露模块 159 | exports.xxx = value 160 | }) 161 | ``` 162 | ```js 163 | // main.js 164 | define(function (require) { 165 | var m1 = require('./module1') 166 | var m2 = require('./module4') 167 | }) 168 | ``` 169 | 170 | ### UMD (通用模块规范) 171 | 172 | UMD 兼容了 AMD 和 CommonJS,同时还支持老式的“全局”变量规范: 173 | 174 | ```js 175 | (function (root, factory) { 176 | if (typeof define === 'function' && define.amd) { 177 | // AMD 178 | define(['jquery', 'underscore'], factory); 179 | } else if (typeof exports === 'object') { 180 | // Node, CommonJS之类的 181 | module.exports = factory(require('jquery'), require('underscore')); 182 | } else { 183 | // 浏览器全局变量(root 即 window) 184 | root.returnExports = factory(root.jQuery, root._); 185 | } 186 | }(this, function ($, _) { 187 | // 方法 188 | function a(){} 189 | function b(){} 190 | function c(){} 191 | 192 | // 暴露公共方法 193 | return { 194 | b: b, 195 | c: c 196 | } 197 | })); 198 | ``` 199 | 200 | ### ES6 模块 201 | 202 | ECMAScript6 标准增加的 JavaScript 语言层面的模块体系定义。ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。 203 | 204 | 205 | 206 | ```js 207 | // module1.js 208 | 209 | export default function foo() {} 210 | ``` 211 | ```js 212 | // module2.js 213 | 214 | export function bar () {} 215 | export const a = 1 216 | ``` 217 | 218 | ```js 219 | // main.js 220 | 221 | import jquery as $ from 'jquery' 222 | import foo from './module1' 223 | import {bar,a} from './module2' 224 | ``` 225 | 226 | ES6 模块与 CommonJS 模块的差异 227 | 228 | - CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。 229 | - CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。 230 | -------------------------------------------------------------------------------- /docs/js/mutationObserver.md: -------------------------------------------------------------------------------- 1 | # MutationObserver 2 | Mutation Observer API 用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知。 3 | 4 | DOM 的变动会触发 Mutation Observer 事件,但与事件不同的是,Mutation Observer 是异步触发,也就是说,Mutation Observer 事件会在所有的 DOM 操作完成后才触发一次。 5 | 6 | ### 实例 7 | 回调函数接受两个参数,一个是变动的数组,一个是观察器实例 8 | ```javascript 9 | let observer = new MutationObserver(function (mutations, observer) { 10 | mutations.forEach(function(mutation) { 11 | console.log(mutation) 12 | }) 13 | }) 14 | ``` 15 | 16 | ### 方法 17 | 18 | #### 1. observe 19 | `observe`方法用来启动监听,它接受两个参数 20 | 21 | 第一个是需要观察的节点 22 | 23 | 第二个是配置对象,配置项的前三项必须至少设置一项,否则会报错 24 | 25 | ```javascript 26 | var container = document.querySelector('.container'); 27 | 28 | observer.observe(container, { 29 | childList:true, // 子节点的变动(指新增,删除或者更改) 30 | attributes:true, // 属性的变动 31 | characterData:true, // 节点内容或节点文本的变动 32 | subtree:false, // 是否将该观察器应用于该节点的所有后代节点 33 | attributeOldValue:false, // 观察attributes变动时,是否需要记录变动前的属性值 34 | characterDataOldValue:false, // 表示观察characterData变动时,是否需要记录变动前的值 35 | attributeFilter:[], // 表示需要观察的特定属性,如 ['class','src'] 36 | }) 37 | ``` 38 | 39 | #### 2.disconnect 40 | `disconnect()`方法用来停止观察 41 | 42 | #### 3. takeRecords 43 | `takeRecords()`方法用来清除变动记录,即不再处理未处理的变动。该方法返回变动记录的数组。 44 | 45 | ### MutationRecord 46 | DOM 每次发生变化,就会生成一条变动记录(MutationRecord 实例)。该实例包含了与变动相关的所有信息。Mutation Observer 返回的第一个参数就是一个个MutationRecord实例所组成的数组。 47 | 48 | `MutationRecord`中包含的信息 49 | - type:观察的变动类型(attribute、characterData或者childList)。 50 | - target:发生变动的DOM节点。 51 | - addedNodes:新增的DOM节点。 52 | - removedNodes:删除的DOM节点。 53 | - previousSibling:前一个同级节点,如果没有则返回null。 54 | - nextSibling:下一个同级节点,如果没有则返回null。 55 | - attributeName:发生变动的属性。如果设置了attributeFilter,则只返回预先指定的属性。 56 | - oldValue:变动前的值。这个属性只对attribute和characterData变动有效,如果发生childList变动,则返回null。 57 | -------------------------------------------------------------------------------- /docs/js/this.md: -------------------------------------------------------------------------------- 1 | # this, call, apply, bind 2 | 3 | ## this的指向 4 | 5 | 1. 在没有 `call`,`apply`,`bind` 方法的影响下, 6 | -------------------------------------------------------------------------------- /docs/keng/keng.md: -------------------------------------------------------------------------------- 1 | # 记录 2 | 3 | 1. 在使用 `node.appendChild(childNode)` 时,如果 `childNode` 是另一个元素的子元素,那么在 append 后,该元素会从其父元素中删除。也就是说在父元素中 `forEach` 循环时不应该 `appendChild`。 4 | 2. 在微信小程序中使用 webview 页面跳转链接,链接地址不能使用 `http` 且不能带有 `#` 否则页面会跳转两次 5 | 3. `Object.assign(a,b)` 会将 `b` 对象的属性覆盖至 `a` 属性,但是仅会覆盖第一层。 6 | 7 | ```js 8 | let objA = { 9 | attrs: { 10 | class: "classname", 11 | style: "color: red;" 12 | } 13 | }; 14 | 15 | let objB = { 16 | attrs: { 17 | class: "this is classname" 18 | } 19 | }; 20 | 21 | let assignObj = Object.assign(objA, objB); 22 | 23 | //assignObj = { 24 | // attrs: { 25 | // class: 'this is classname' 26 | // } 27 | //} 28 | ``` 29 | 30 | 4. ios 中日期转换不能识别 '-' 连接的日期 31 | 32 | ```js 33 | const date = "2020-05-21 18:40:03"; 34 | // 通常写法 35 | const currentTime = new Date(date).getTime(); 36 | // 兼容 ios 写法 37 | const currentTime = new Date(date.replace(/-/g, "")).getTime(); 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/leetcode/13.md: -------------------------------------------------------------------------------- 1 | 13. 罗马数字转整数 2 | 3 | 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。 4 | 5 | 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II 6 | ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。 7 | 8 | 通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况: 9 | 10 | I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。 X 可以放在 L (50) 和 C (100)的左边,来表示 40 和 90。 C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。 给定一个罗马数字,将其转换成整数。 11 | 12 | <<< ./leetcode/13.js 13 | -------------------------------------------------------------------------------- /docs/leetcode/14.md: -------------------------------------------------------------------------------- 1 | 14. 最长公共前缀 2 | 3 | 编写一个函数来查找字符串数组中的最长公共前缀。 4 | 5 | 如果不存在公共前缀,返回空字符串 ""。 6 | 7 | <<< ./leetcode/14.js 8 | -------------------------------------------------------------------------------- /docs/leetcode/20.md: -------------------------------------------------------------------------------- 1 | 20. 有效的括号 2 | 3 | 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。 4 | 5 | 有效字符串需满足: 6 | 7 | 左括号必须用相同类型的右括号闭合。 8 | 左括号必须以正确的顺序闭合。 9 | 10 | <<< ./leetcode/20.js 11 | 12 | -------------------------------------------------------------------------------- /docs/leetcode/9.md: -------------------------------------------------------------------------------- 1 | 9. 回文数 2 | 3 | 给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。 4 | 5 | 回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。 6 | 7 | 示例 : 8 | 9 | ``` 10 | 输入:x = 121 11 | 输出:true 12 | 示例 2: 13 | ``` 14 | 15 | ``` 16 | 输入:x = -121 17 | 输出:false 18 | 解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。 19 | 示例 3: 20 | ``` 21 | 22 | ``` 23 | 输入:x = 10 24 | 输出:false 25 | 解释:从右向左读, 为 01 。因此它不是一个回文数。 26 | 示例 4: 27 | ``` 28 | 29 | ``` 30 | 输入:x = -101 31 | 输出:false 32 | ``` 33 | 34 | ## 解 35 | 36 | <<< ./leetcode/9.js 37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/leetcode/dynamic-programming.md: -------------------------------------------------------------------------------- 1 | # 动态规划 2 | 3 | 1. https://blog.csdn.net/zjy_code/article/details/80667631 4 | 5 | 2. https://juejin.im/post/5cde316f6fb9a07ed9118f01#comment 6 | -------------------------------------------------------------------------------- /docs/leetcode/singleNumber.md: -------------------------------------------------------------------------------- 1 | # 只出现一次的数字 2 | 3 | ## 说明 4 | 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 5 | 6 | 示例: 7 | ```js 8 | 输入: [4,1,2,1,2] 9 | 输出: 4 10 | ``` 11 | 12 | ## 解 13 | 14 | <<< ./leetcode/136.js 15 | 16 | :::tip 17 | 这个是自己想到的 18 | 19 | 高阶解法可以看这里 20 | ::: 21 | 22 | -------------------------------------------------------------------------------- /docs/leetcode/sort.md: -------------------------------------------------------------------------------- 1 | # 排序 2 | 3 | ## 插入排序 4 | 5 | 1. 从第一个元素开始,该元素可以认为已经被排序。 6 | 7 | 2. 取出下一个元素,在已经排序的元素序列中从后向前扫描。 8 | 9 | 3. 如果该元素(已排序)大于新元素,将该元素移到下一位置。 10 | 11 | 4. 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置。 12 | 13 | 5. 将新元素插入到该位置后。 14 | 15 | 6. 重复步骤 2~5。 16 | 17 | ```js 18 | function insertSort(arr) { 19 | let temp; 20 | for (let i = 1; i < arr.length; i++) { 21 | temp = arr[i]; 22 | for (let j = i; j >= 0; j--) { 23 | if (temp < arr[j - 1]) { 24 | arr[j] = arr[j - 1]; 25 | } else { 26 | arr[j] = temp; 27 | } 28 | } 29 | } 30 | return arr; 31 | } 32 | ``` 33 | 34 | ## 冒泡排序 35 | 36 | 1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。 37 | 38 | 2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。 39 | 40 | 3. 针对所有的元素重复以上的步骤,除了最后一个。 41 | 42 | 4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 43 | 44 | ```js 45 | function bubbleSort(arr) { 46 | for (let i = arr.length - 1; i >= 0; i--) { 47 | for (let j = 0; j < i; j++) { 48 | if (arr[j] > arr[j + 1]) { 49 | let temp = arr[j + 1]; 50 | arr[j + 1] = arr[j]; 51 | arr[j] = temp; 52 | } 53 | } 54 | } 55 | 56 | return arr; 57 | } 58 | ``` 59 | 60 | ## 选择排序 61 | 62 | 直接从待排序数组中选择一个最小(或最大)数字,放入新数组中。 63 | 64 | ```js 65 | function selectSort(arr) { 66 | for (let i = 0; i < arr.length; i++) { 67 | let minValue; 68 | let minIndex; 69 | let temp; 70 | for (let j = i + 1; j < arr.length; j++) { 71 | if (arr[i] > arr[j]) { 72 | minValue = arr[j]; 73 | minIndex = j; 74 | } 75 | } 76 | 77 | temp = minValue; 78 | arr[minIndex] = arr[i]; 79 | arr[i] = temp; 80 | } 81 | 82 | return arr; 83 | } 84 | ``` 85 | 86 | ## 快速排序 87 | 88 | 1. 在数据集之中,选择一个元素作为”基准”(pivot)。 89 | 90 | 2. 所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。这个操作称为分区 (partition)操作,分区操作结束后,基准元素所处的位置就是最终排序后它的位置。 91 | 92 | 3. 对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。 93 | 94 | ```js 95 | function quickSort(arr) { 96 | if (arr.length <= 1) return arr; 97 | var partitionIndex = Math.floor(arr.length / 2); 98 | var tmp = arr[partitionIndex]; 99 | var left = []; 100 | var right = []; 101 | for (var i = 0; i < arr.length; i++) { 102 | if (arr[i] < tmp) { 103 | left.push(arr[i]); 104 | } else { 105 | right.push(arr[i]); 106 | } 107 | } 108 | return quickSort(left).concat([tmp], quickSort(right)); 109 | } 110 | ``` 111 | -------------------------------------------------------------------------------- /docs/leetcode/twoSum.md: -------------------------------------------------------------------------------- 1 | # 两数之和 2 | 3 | ## 说明 4 | 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的 两个 整数。 5 | 6 | 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 7 | 8 | 示例: 9 | ``` 10 | 给定 nums = [2, 7, 11, 15], target = 9 11 | 12 | 因为 nums[0] + nums[1] = 2 + 7 = 9 13 | 所以返回 [0, 1] 14 | ``` 15 | 16 | ## 解 17 | 18 | <<< ./leetcode/1.js 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/realize/bind.md: -------------------------------------------------------------------------------- 1 | # bind 2 | 3 | :::tip 4 | 参考:[JavaScript深入之bind的模拟实现](https://github.com/mqyqingfeng/Blog/issues/12) 5 | ::: 6 | 7 | <<< ./realize/bind.js 8 | 9 | -------------------------------------------------------------------------------- /docs/realize/call.md: -------------------------------------------------------------------------------- 1 | # call && apply 2 | 3 | 4 | <<< ./realize/call.js 5 | <<< ./realize/apply.js 6 | -------------------------------------------------------------------------------- /docs/realize/curry.md: -------------------------------------------------------------------------------- 1 | # 柯里化 2 | 3 | <<< ./realize/curry.js 4 | -------------------------------------------------------------------------------- /docs/realize/new.md: -------------------------------------------------------------------------------- 1 | # new 2 | 3 | :::tip 4 | 过程: 5 | 1. 创建一个新对象 6 | 2. 将新的对象的 `__proto__` 指向被实例化函数的 `prototype` 7 | 3. 将被实例化函数的 `this` 指向 新的对象 8 | 4. 如果函数返回的是对象则返回函数结果,否则返回新的对象 9 | ::: 10 | 11 | <<< ./realize/new.js 12 | 13 | -------------------------------------------------------------------------------- /docs/realize/promise.md: -------------------------------------------------------------------------------- 1 | # Promise 2 | 3 | ::: tip 4 | 难点: 5 | 1. 异步处理 6 | 2. 兼容不同 `Promise` 的 `resolvePromise` 函数 7 | ::: 8 | 9 | 10 | <<< ./realize/promise.ts 11 | 12 | ### 参考 13 | [Promise之你看得懂的Promise](https://juejin.im/post/5b32f552f265da59991155f0?tdsourcetag=s_pctim_aiomsg) 14 | 15 | [剖析Promise内部结构](https://github.com/xieranmaya/blog/issues/3) 16 | 17 | -------------------------------------------------------------------------------- /docs/realize/reactHook.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/realize/throttleDebounce.md: -------------------------------------------------------------------------------- 1 | # 节流 & 防抖 2 | 3 | ## 函数节流 throttle 4 | 5 | 指定时间间隔内只会执行一次任务 6 | 7 | 常用于滚动条滚动监听等 8 | 9 | <<< ./realize/throttle.js 10 | 11 | ## 函数防抖 debounce 12 | 13 | 任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行 14 | 15 | 即:用户在不触发事件时,才触发相应动作,以抑制本来在事件中要执行的动作。 16 | 17 | 常用于用户输入验证等 18 | 19 | <<< ./realize/debounce.js 20 | 21 | :::tip 22 | 查看 `throttle` 和 `debounce` 可视化的差异 23 | ::: 24 | -------------------------------------------------------------------------------- /docs/when/readme.md: -------------------------------------------------------------------------------- 1 | ## 当我写一个分页器组件时 2 | 3 | ### 当前情况 4 | 5 | 1. 基于 antd 分页器再封装 6 | 2. 请求字段和返回字段,大部分接口相同,小部分不同 7 | 8 | ### 解决 9 | 10 | 1. 11 | -------------------------------------------------------------------------------- /leetcode/1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} target 4 | * @return {number[]} 5 | */ 6 | // 暴力 7 | const twoSum1 = function (nums, target) { 8 | for (let i = 0; i < nums.length; i++) { 9 | const n = nums[i] 10 | const lack = target - n 11 | 12 | for (let j = i + 1; j < nums.length; j++) { 13 | if (nums[j] === lack) { 14 | return [i, j] 15 | } 16 | } 17 | } 18 | } 19 | 20 | // 哈希 21 | const twoSum2 = function (nums, target) { 22 | const map = {} 23 | for (let i = 0; i < nums.length; i++) { 24 | const lack = target - nums[i] 25 | if (map[lack] !== undefined) { 26 | return [map[lack], i] 27 | } 28 | map[nums[i]] = i 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /leetcode/13.js: -------------------------------------------------------------------------------- 1 | const getNum = (s) => { 2 | switch (s) { 3 | case"I": 4 | return 1 5 | case"V": 6 | return 5 7 | case "X": 8 | return 10 9 | case"L": 10 | return 50 11 | case"C": 12 | return 100 13 | case"D": 14 | return 500 15 | case"M": 16 | return 1000 17 | } 18 | } 19 | /** 20 | * @param {string} s 21 | * @return {number} 22 | */ 23 | const romanToInt = function (s) { 24 | let num = 0; 25 | for (let i = 0; i < s.length; i++) { 26 | if (getNum(s[i]) < getNum(s[i + 1])) { 27 | num -= getNum(s[i]) 28 | } else { 29 | num += getNum(s[i]) 30 | } 31 | } 32 | return num 33 | }; 34 | -------------------------------------------------------------------------------- /leetcode/136.js: -------------------------------------------------------------------------------- 1 | var singleNumber = function(arr) { 2 | const first = arr[0] 3 | for (let i = 1; i < arr.length; i++) { 4 | if (first === arr[i]) { 5 | arr.shift() 6 | arr.splice(i-1,1) 7 | return singleNumber(arr) 8 | } 9 | } 10 | return first 11 | } 12 | -------------------------------------------------------------------------------- /leetcode/14.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string[]} strs 3 | * @return {string} 4 | */ 5 | const longestCommonPrefix = function (strs) { 6 | if (!strs || strs.length === 0) { 7 | return '' 8 | } 9 | return splitTow(strs) 10 | } 11 | 12 | function splitTow(arr) { 13 | if (arr.length === 1) { 14 | return arr[0] 15 | } 16 | const middle = Math.floor(arr.length / 2) 17 | const left = arr.slice(0, middle) 18 | const right = arr.slice(middle, arr.length) 19 | return getCommonByTow(splitTow(left), splitTow(right)) 20 | } 21 | 22 | function getCommonByTow(str1, str2) { 23 | let commonStr = '' 24 | for (let i = 0; i < str1.length && i < str2.length; i++) { 25 | if (str1[i] === str2[i]) { 26 | commonStr += str1[i] 27 | } else { 28 | break 29 | } 30 | } 31 | return commonStr 32 | } 33 | -------------------------------------------------------------------------------- /leetcode/20.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {boolean} 4 | */ 5 | 6 | const isValid = function (s) { 7 | const map = { 8 | '(': ")", 9 | "{": "}", 10 | "[": "]" 11 | } 12 | const arr = [] 13 | for (let i = 0; i < s.length; i++) { 14 | if (s[i] in map) { 15 | arr.push(s[i]) 16 | } else { 17 | if (s[i] !== map[arr.pop()]) { 18 | return false 19 | } 20 | } 21 | } 22 | return !arr.length 23 | }; 24 | -------------------------------------------------------------------------------- /leetcode/3.js: -------------------------------------------------------------------------------- 1 | var lengthOfLongestSubstring = function (s) { 2 | const map = {} 3 | var left = 0 4 | 5 | return s.split('').reduce((max, v, i) => { 6 | console.log(left,max) 7 | left = map[v] >= left ? map[v] + 1 : left 8 | map[v] = i 9 | console.log(map) 10 | console.log('----') 11 | // return Math.max(max, i - left + 1) 12 | return i - left + 1 13 | }, 0) 14 | } 15 | // 16 | console.log('res:') 17 | console.log(lengthOfLongestSubstring('dvdf')) 18 | 19 | // var lengthOfLongestSubstring = function(s) { 20 | // var res = 0; // 用于存放当前最长无重复子串的长度 21 | // var str = ""; // 用于存放无重复子串 22 | // var len = s.length; 23 | // for(var i = 0; i < len; i++) { 24 | // var char = s.charAt(i); 25 | // var index = str.indexOf(char); 26 | // if(index === -1) { 27 | // str += char; 28 | // res = res < str.length ? str.length : res; 29 | // } else { 30 | // str = str.substr(index + 1) + char; 31 | // } 32 | // } 33 | // return res; 34 | // }; 35 | // console.log(lengthOfLongestSubstring('dvdf')) 36 | -------------------------------------------------------------------------------- /leetcode/4.js: -------------------------------------------------------------------------------- 1 | var findMedianSortedArrays = function (nums1, nums2) { 2 | var arr = nums1.concat(nums2).sort((a, b) => a - b) 3 | 4 | if (arr.length % 2 === 1) { 5 | return arr[(arr.length - 1) / 2] 6 | } else { 7 | return (arr[arr.length / 2] + arr[arr.length / 2 - 1]) / 2 8 | } 9 | } 10 | 11 | 12 | var findMedianSortedArrays = function (nums1, nums2) { 13 | var total = nums1.length + nums2.length 14 | var half = total % 2 === 1 ? (total - 1) / 2 : total / 2 15 | 16 | if (total % 2 === 1) { 17 | return findKth(nums1, nums1.length, nums2, nums2.length, half + 1) 18 | } 19 | else { 20 | return (findKth(nums1, nums1.length, nums2, nums2.length, half) + findKth(nums1, nums1.length, nums2, nums2.length, half + 1)) / 2 21 | } 22 | } 23 | 24 | function findKth(a, m, b, n, k) { 25 | // always assume that m is equal or smaller than n 26 | if (m > n) 27 | return findKth(b, n, a, m, k) 28 | if (m === 0) 29 | return b[k - 1] 30 | if (k === 1) 31 | return Math.min(a[0], b[0]) 32 | 33 | // divide k into two parts 34 | var pa = Math.min(k >> 1, m) 35 | , pb = k - pa 36 | 37 | if (a[pa - 1] < b[pb - 1]) 38 | return findKth(a.slice(pa), m - pa, b, n, k - pa) 39 | else if (a[pa - 1] > b[pb - 1]) 40 | return findKth(a, m, b.slice(pb), n - pb, k - pb) 41 | else 42 | return a[pa - 1] 43 | } 44 | -------------------------------------------------------------------------------- /leetcode/9.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} x 3 | * @return {boolean} 4 | */ 5 | const isPalindrome = function (x) { 6 | if (x < 0) { 7 | return false 8 | } 9 | const str = String(x) 10 | for (let i = 0; i < str.length; i++) { 11 | if (str[i] !== str[str.length - 1 - i]) { 12 | return false 13 | } 14 | } 15 | return true 16 | } 17 | -------------------------------------------------------------------------------- /old/css中一些不常用的单位.md: -------------------------------------------------------------------------------- 1 | - ch 2 | 3 | - 数字 0 的宽度 4 | 5 | - rem 6 | 7 | - 相对长度单位。相对于根元素(html)`font-size`计算值的倍数 8 | 9 | - em 10 | 11 | - 相对长度单位。相对于当前对象内文本的字体尺寸。 12 | - 如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸 13 | 14 | - ex 15 | 16 | - 相对长度单位。相对于字符“x”的高度。通常为字体高度的一半。 17 | 18 | - 如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。 19 | - 测试记得设置`line-height:1` 20 | 21 | - vw 22 | 23 | - 相对于视口的宽度。视口被均分为100单位的vw 24 | - 100vw包含滚动条的宽度,而`width:100%`不包括滚动条的宽度 25 | 26 | - vh 27 | 28 | - 相对于视口的高度。视口被均分为100单位的vh 29 | 30 | - vmax 31 | 32 | - 相对于视口的宽度或高度中较大的那个。其中最大的那个被均分为100单位的vmax 33 | 34 | - vmin 35 | 36 | - 相对于视口的宽度或高度中较小的那个。其中最小的那个被均分为100单位的vmin 37 | 38 | - cm 39 | 40 | - 厘米(Centimeters)。绝对长度单位。 41 | 42 | - mm 43 | 44 | - 毫米(Millimeters)。绝对长度单位。 45 | 46 | - q 47 | 48 | - 1/4毫米(quarter-millimeters)。绝对长度单位 49 | 50 | - in 51 | 52 | - 英寸(Inches)。绝对长度单位。 53 | 54 | - pt 55 | 56 | - 点(Points)。绝对长度单位。 57 | 58 | - pc 59 | 60 | - 派卡(Picas)。绝对长度单位。相当于我国新四号铅字的尺寸。 61 | 62 | ### 换算 63 | 64 | 1in = 72pt = 6pc = 96px = 2.54cm = 25.4mm 65 | 66 | ​ -------------------------------------------------------------------------------- /old/images/2018062201.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiShaoXuan/blog/6a253819533266476e6bda7f0ec16b40ed359b09/old/images/2018062201.jpg -------------------------------------------------------------------------------- /old/images/2018062202.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiShaoXuan/blog/6a253819533266476e6bda7f0ec16b40ed359b09/old/images/2018062202.jpg -------------------------------------------------------------------------------- /old/images/2018062203.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiShaoXuan/blog/6a253819533266476e6bda7f0ec16b40ed359b09/old/images/2018062203.png -------------------------------------------------------------------------------- /old/images/hover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiShaoXuan/blog/6a253819533266476e6bda7f0ec16b40ed359b09/old/images/hover.gif -------------------------------------------------------------------------------- /old/jquery跨域头部配置.md: -------------------------------------------------------------------------------- 1 | # jquery跨域头部配置 2 | 3 | ```javascript 4 | $.ajax({ 5 | type: "GET", 6 | crossOrigin: true, 7 | xhrFields: {withCredentials: true}, 8 | url: url, 9 | success: function (res) { 10 | console.log(res) 11 | } 12 | }); 13 | ``` 14 | 15 | 在一个老项目里用的,没有在axios等其他插件中使用过 -------------------------------------------------------------------------------- /old/readme.md: -------------------------------------------------------------------------------- 1 | 记点问题和心得 -------------------------------------------------------------------------------- /old/svg的一点问题.md: -------------------------------------------------------------------------------- 1 | 我的浏览器的效果测试的(应该是360浏览器)效果 2 | 3 | 热租和旁边的火焰是一张图片,但是效果不一样 4 | 5 | 6 | 7 | #### 原因 8 | 9 | 图片是svg格式,浏览器解析了svg,热租文字的`font-family`不存在所以转成了默认字体 10 | 11 | #### 解决 12 | 13 | 1. 把图片转成png或者jpg 14 | 2. 把图片拖到编辑器里(我用的是webstrom,不知道vscode可不可以),把字体的改成相近的 15 | 16 | |省事第二种,不过要遵循设计稿还是转一下格式一下比较好 -------------------------------------------------------------------------------- /old/一些meta标签.md: -------------------------------------------------------------------------------- 1 | #### 双内核浏览器优先加载webkit内核 2 | 3 | ```html 4 | 5 | ``` 6 | 7 | #### 双内核浏览器优先加载IE兼容模式 8 | 9 | ```html 10 | 11 | ``` 12 | 13 | #### IE渲染引擎使用最新内核,并尝试调用chrome框架插件 14 | 15 | ```html 16 | 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /old/函数节流与防抖.md: -------------------------------------------------------------------------------- 1 | 官网上写了一个简单tab栏的轮播,但是触发切换的条件是鼠标悬停,这时会遇到两个问题: 2 | 3 | 1. 一个是鼠标不停的晃动会不停的触发切换 4 | 2. 如果设置了简单的动画开关则在动画结束前即使长时间停留在tab上也不会再触发动画 5 | 6 | 解决方法: 7 | 8 | 1. 函数节流 9 | 2. 动画队列 10 | 11 | 动画队列的实现相当简单,只是记得当时学jquery时不理解$.queue,结果需要的是否反倒直接自己写了一个,可能这就是念念不忘,必有回响吧... 12 | 13 | 所以这篇主要记录函数节流和顺带想起来的函数防抖 14 | 15 | #### 函数节流(throttle) 16 | 17 | **指某些代码不可以在没有间断的情况下连续重复执行** 18 | 19 | ```js 20 | function throttle (method,wait=1000,context){ 21 | clearTimeout(method.tid) 22 | method.tid = setTimeout(function(){ 23 | method.call(context) 24 | },wait) 25 | } 26 | ``` 27 | 28 | #### 函数防抖 (debounce) 29 | 30 | **指一个事件如果频繁触发,会隔一段时间执行一次** 31 | 32 | ```js 33 | function debounce(fn,delay,mustRunDelay){ 34 | var timer = null; 35 | var t_start; 36 | return function(){ 37 | var context = this; 38 | var args = arguments; 39 | var t_curr = +new Date(); 40 | clearTimeout(timer); 41 | if(!t_start){ 42 | t_start = t_curr; 43 | } 44 | if(t_curr - t_start >= mustRunDelay) { 45 | fn.apply(context,args); 46 | t_start = t_curr 47 | } else { 48 | timer = setTimeout(function(){ 49 | fn.apply(context,args); 50 | },delay); 51 | } 52 | } 53 | } 54 | ``` 55 | 56 | 参考 57 | 58 | > javascript高级程序设计 59 | 60 | > lodash https://www.lodashjs.com/docs/4.17.5.html#debounce -------------------------------------------------------------------------------- /old/利用css变量实现的悬停效果.md: -------------------------------------------------------------------------------- 1 | ![hover](https://raw.githubusercontent.com/QiShaoXuan/blog/master/images/hover.gif) 2 | 3 | #### css 4 | 5 | ```css 6 | .button { 7 | width:200px; 8 | position: relative; 9 | appearance: none; 10 | background: #f72359; 11 | padding: 1em 2em; 12 | border: none; 13 | color: white; 14 | font-size: 1.2em; 15 | cursor: pointer; 16 | outline: none; 17 | overflow: hidden; 18 | border-radius: 100px; 19 | } 20 | 21 | .button span { 22 | position: relative; 23 | } 24 | 25 | .button::before { 26 | --size: 0; 27 | content: ''; 28 | position: absolute; 29 | left: var(--x); 30 | top: var(--y); 31 | width: var(--size); 32 | height: var(--size); 33 | background: radial-gradient(circle closest-side, #4405f7, transparent); 34 | transform: translate(-50%, -50%); 35 | transition: width .2s ease, height .2s ease; 36 | } 37 | 38 | .button:hover::before { 39 | --size: 400px; 40 | } 41 | ``` 42 | 43 | #### html 44 | 45 | ```html 46 |
hover me to change
47 | ``` 48 | 49 | #### js 50 | 51 | ```js 52 | document.querySelector('.button').onmousemove = (e) => { 53 | 54 | const x = e.pageX - e.target.offsetLeft 55 | const y = e.pageY - e.target.offsetTop 56 | 57 | e.target.style.setProperty('--x', `${ x }px`) 58 | e.target.style.setProperty('--y', `${ y }px`) 59 | 60 | } 61 | ``` 62 | 63 | -------------------------------------------------------------------------------- /old/很久之前写的gulp相关.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ###1.安装 4 | ``` 5 | cnpm install --save-dev gulp 6 | ``` 7 | ###2.使用 8 | ``` 9 | gulp 打包 10 | gulp taskname 执行自定义的某个gulp任务 11 | ``` 12 | ###3.API 13 | ####——需要知道四个API:gulp.task , gulp.src , gulp.dest , gulp.watch 14 | ####3.1 gulp.src 15 | 获取文件(以进行操作) 16 | ``` 17 | gulp.src(globs[, options]) 18 | ``` 19 | globs参数是文件匹配模式(类似正则表达式),用来匹配文件路径(包括文件名),当然这里也可以直接指定某个具体的文件路径。当有多个匹配模式时,该参数可以为一个数组。 20 | 21 | options为可选参数。通常情况下我们不需要用到。 22 | 23 | * `*` 匹配文件路径中的0个或多个字符,但不会匹配路径分隔符,除非路径分隔符出现在末尾 24 | * `**` 匹配路径中的0个或多个目录及其子目录,需要单独出现,即它左右不能有其他东西了。如果出现在末尾,也能匹配文件。 25 | * `?` 匹配文件路径中的一个字符(不会匹配路径分隔符) 26 | * `[...]` 匹配方括号中出现的字符中的任意一个,当方括号中第一个字符为`^`或`!`时,则表示不匹配方括号中出现的其他字符中的任意一个,类似js正则表达式中的用法 27 | * `!(pattern|pattern|pattern)` 匹配任何与括号中给定的任一模式都不匹配的 28 | * `?(pattern|pattern|pattern)` 匹配括号中给定的任一模式0次或1次,类似于js正则中的(pattern|pattern|pattern)? 29 | * `+(pattern|pattern|pattern)` 匹配括号中给定的任一模式至少1次,类似于js正则中的(pattern|pattern|pattern)+ 30 | * `*(pattern|pattern|pattern)` 匹配括号中给定的任一模式0次或多次,类似于js正则中的(pattern|pattern|pattern)* 31 | * `@(pattern|pattern|pattern)` 匹配括号中给定的任一模式1次,类似于js正则中的(pattern|pattern|pattern) 32 | 33 | 此外,还可以使用展开模式。展开模式以花括号作为定界符,根据它里面的内容,会展开为多个模式,最后匹配的结果为所有展开的模式相加起来得到的结果。展开的例子如下: 34 | 35 | * `a{b,c}d` 会展开为 `abd`,`acd` 36 | * `a{b,}c` 会展开为 `abc`,`ac` 37 | * `a{0..3}d` 会展开为 `a0d`,`a1d`,`a2d`,`a3d` 38 | * `a{b,c{d,e}f}g` 会展开为 `abg`,`acdfg`,`acefg` 39 | * `a{b,c}d{e,f}g` 会展开为 `abdeg`,`acdeg`,`abdeg`,`abdfg` 40 | 41 | 当有多种匹配模式时可以使用数组 42 | ``` 43 | //使用数组的方式来匹配多种文件 44 | gulp.src(['js/*.js','css/*.css','*.html']) 45 | ``` 46 | ####3.2 gulp.dest 47 | 输出文件(在文件进行操作后) 48 | ``` 49 | gulp.dest(path[,options]) 50 | ``` 51 | path为写入文件的路径 52 | 53 | options为一个可选的参数对象,通常我们不需要用到 54 | 55 | 要想使用好gulp.dest()这个方法,就要理解给它传入的路径参数与最终生成的文件的关系。 56 | 57 | gulp的使用流程一般是这样子的:首先通过gulp.src()方法获取到我们想要处理的文件流,然后把文件流通过pipe方法导入到gulp的插件中,最后把经过插件处理后的流再通过pipe方法导入到gulp.dest()中,gulp.dest()方法则把流中的内容写入到文件中,这里首先需要弄清楚的一点是,我们给gulp.dest()传入的路径参数,只能用来指定要生成的文件的目录,而不能指定生成文件的文件名,它生成文件的文件名使用的是导入到它的文件流自身的文件名,所以生成的文件名是由导入到它的文件流决定的,即使我们给它传入一个带有文件名的路径参数,然后它也会把这个文件名当做是目录名,例如: 58 | ``` 59 | var gulp = require('gulp'); 60 | gulp.src('script/jquery.js') 61 | .pipe(gulp.dest('dist/foo.js')); 62 | //最终生成的文件路径为 dist/foo.js/jquery.js,而不是dist/foo.js 63 | ``` 64 | 要想改变文件名,可以使用插件gulp-rename 65 | 66 | 下面说说生成的文件路径与我们给`gulp.dest()`方法传入的路径参数之间的关系。 67 | 68 | `gulp.dest(path)`生成的文件路径是我们传入的path参数后面再加上`gulp.src()`中有通配符开始出现的那部分路径。 69 | 如果没有通配符,那么输出路径就是`gulp.dest(path)`中path的路径下 70 | 例如: 71 | ``` 72 | var gulp = reruire('gulp'); 73 | //有通配符开始出现的那部分路径为 **/*.js 74 | gulp.src('script/**/*.js') 75 | .pipe(gulp.dest('dist')); //最后生成的文件路径为 dist/**/*.js 76 | //如果 **/*.js 匹配到的文件为 jquery/jquery.js ,则生成的文件路径为 dist/jquery/jquery.js 77 | ``` 78 | 通过指定`gulp.src()`方法配置参数中的base属性,我们可以更灵活的来改变`gulp.dest()`生成的文件路径。 79 | 当我们没有在`gulp.src()`方法中配置base属性时,base的默认值为通配符开始出现之前那部分路径,例如: 80 | ``` 81 | gulp.src('app/src/**/*.css') //此时base的值为 app/src 82 | ``` 83 | 上面我们说的gulp.dest()所生成的文件路径的规则,其实也可以理解成,用我们给gulp.dest()传入的路径替换掉gulp.src()中的base路径,最终得到生成文件的路径。而base的默认属性就是`gulp.src()`中有通配符开始出现的那部分路径或者是`gulp.src()`中文件前的路径(没有出现通配符的情况下) 84 | 85 | 所以改变base路径后,gulp.dest()生成的文件路径也会改变 86 | ``` 87 | gulp.src(script/lib/*.js) //没有配置base参数,此时默认的base路径为script/lib 88 | //假设匹配到的文件为script/lib/jquery.js 89 | .pipe(gulp.dest('build')) //生成的文件路径为 build/jquery.js 90 | 91 | gulp.src(script/lib/*.js, {base:'script'}) //配置了base参数,此时base路径为script 92 | //假设匹配到的文件为script/lib/jquery.js 93 | .pipe(gulp.dest('build')) //此时生成的文件路径为 build/lib/jquery.js 94 | ``` 95 | 用`gulp.dest()`把文件流写入文件后,文件流仍然可以继续使用。 96 | ####3.3 gulp.task 97 | 定义gulp任务 98 | ``` 99 | gulp.task(name[, deps], fn) 100 | ``` 101 | name 为任务名 102 | 103 | deps 是当前定义的任务需要依赖的其他任务,为一个数组。当前定义的任务会在所有依赖的任务执行完毕后才开始执行。如果没有依赖,则可省略这个参数 104 | 105 | fn 为任务函数,我们把任务要执行的代码都写在里面。该参数也是可选的。 106 | 107 | 在执行多个任务时,可以通过任务依赖实现,即创建一个空的任务来放置其他任务依赖 108 | 109 | 如果任务相互之间没有依赖,任务会按你书写的顺序来执行,如果有依赖的话则会先执行依赖的任务。 110 | 111 | 但是如果某个任务所依赖的任务是异步的,就要注意了,gulp并不会等待那个所依赖的异步任务完成,而是会接着执行后续的任务。例如: 112 | ``` 113 | gulp.task('one',function(){ 114 | //one是一个异步执行的任务 115 | setTimeout(function(){ 116 | console.log('one is done') 117 | },5000); 118 | }); 119 | 120 | //two任务虽然依赖于one任务,但并不会等到one任务中的异步操作完成后再执行 121 | gulp.task('two',['one'],function(){ 122 | console.log('two is done'); 123 | }); 124 | ``` 125 | 上面的例子中我们执行two任务时,会先执行one任务,但不会去等待one任务中的异步操作完成后再执行two任务,而是紧接着执行two任务。所以two任务会在one任务中的异步操作完成之前就执行了。 126 | 127 | 那如果我们想等待异步任务中的异步操作完成后再执行后续的任务 128 | 有三种方法可以实现: 129 | 第一:在异步操作完成后执行一个回调函数来通知gulp这个异步任务已经完成,这个回调函数就是任务函数的第一个参数。 130 | ``` 131 | gulp.task('one',function(cb){ //cb为任务函数提供的回调,用来通知任务已经完成 132 | //one是一个异步执行的任务 133 | setTimeout(function(){ 134 | console.log('one is done'); 135 | cb(); //执行回调,表示这个异步任务已经完成 136 | },5000); 137 | }); 138 | 139 | //这时two任务会在one任务中的异步操作完成后再执行 140 | gulp.task('two',['one'],function(){ 141 | console.log('two is done'); 142 | }) 143 | ``` 144 | 第二:定义任务时返回一个流对象。适用于任务就是操作gulp.src获取到的流的情况。(将流强行带到任务one中,使流在任务one执行完后才能继续) 145 | ``` 146 | gulp.task('one',function(cb){ 147 | var stream = gulp.src('client/**/*.js') 148 | .pipe(dosomething()) //dosomething()中有某些异步操作 149 | .pipe(gulp.dest('build')); 150 | return stream; 151 | }); 152 | 153 | gulp.task('two',['one'],function(){ 154 | console.log('two is done'); 155 | }); 156 | ``` 157 | 第三:返回一个promise对象,例如 158 | ``` 159 | var Q = require('q'); //一个著名的异步处理的库 https://github.com/kriskowal/q 160 | gulp.task('one',function(cb){ 161 | var deferred = Q.defer(); 162 | // 做一些异步操作 163 | setTimeout(function() { 164 | deferred.resolve(); 165 | }, 5000); 166 | return deferred.promise; 167 | }); 168 | 169 | gulp.task('two',['one'],function(){ 170 | console.log('two is done'); 171 | }); 172 | ``` 173 | ####3.4 gulp.watch 174 | 监听文件变化,当出现变化时作出指定的task 175 | ``` 176 | gulp.watch(glob[, opts], tasks) 177 | ``` 178 | glob 为要监视的文件匹配模式,规则和用法与gulp.src()方法中的glob相同 179 | 180 | opts 为一个可选的配置对象,通常不需要用到 181 | 182 | tasks 为文件变化后要执行的任务,为一个数组 183 | ``` 184 | gulp.task('uglify',function(){ 185 | //do something 186 | }); 187 | gulp.task('reload',function(){ 188 | //do something 189 | }); 190 | gulp.watch('js/**/*.js', ['uglify','reload']); 191 | ``` 192 | `gulp.watch()`还有另外一种使用方式: 193 | ``` 194 | gulp.watch(glob[, opts, cb]) 195 | ``` 196 | glob和opts参数与第一种用法相同 197 | 198 | cb参数为一个函数。每当监视的文件发生变化时,就会调用这个函数,并且会给它传入一个对象,该对象包含了文件变化的一些信息,type属性为变化的类型,可以是`added`,`changed`,`deleted`,`path`属性为发生变化的文件的路径 199 | ``` 200 | gulp.watch('js/**/*.js', function(event){ 201 | console.log(event.type); //变化类型 added为新增,deleted为删除,changed为改变 202 | console.log(event.path); //变化的文件的路径 203 | }); 204 | ``` 205 | ###4.使用插件 206 | 207 | ####4.1 快速启动插件 208 | 当我们使用插件时,需要将每一个插件require,如果使用的插件较多,那么需要的require会造成代码十分冗长,所以我们最先使用的是`gulp-load-plugins`插件 209 | 210 | `gulp-load-plugins`插件可以自动加载package.json文件里的gulp插件。例如假设你的package.json文件里的依赖是这样的: 211 | ``` 212 | { 213 | "devDependencies": { 214 | "gulp": "~3.6.0", 215 | "gulp-rename": "~1.2.0", 216 | "gulp-ruby-sass": "~0.4.3", 217 | "gulp-load-plugins": "~0.5.1" 218 | } 219 | } 220 | ``` 221 | 然后我们可以在`gulpfile.js`中使用`gulp-load-plugins`来帮我们加载插件: 222 | ``` 223 | var gulp = require('gulp'); 224 | //加载gulp-load-plugins插件,并马上运行它 225 | var plugins = require('gulp-load-plugins')(); 226 | ``` 227 | 然后我们要使用gulp-rename和gulp-ruby-sass这两个插件的时候,就可以使用`plugins.rename`和`plugins.rubySass`来代替了,也就是原始插件名去掉gulp-前缀,之后再转换为驼峰命名。 228 | 229 | ####4.2 Browsersync 230 | 开启本地货代理服务器,实现同步刷新 231 | ``` 232 | $ npm install browser-sync gulp --save-dev 233 | ``` 234 | 具体设置查看 Browsersync / 说明文档 235 | ####4.3 wiredep 236 | 解决bower前端库引入进html的问题 237 | ``` 238 | $ npm install --save-dev wiredep 239 | ``` 240 | 官方说明 241 | 242 | 网上例子 243 | ####4.4 del 244 | 删除文件和文件夹 245 | ``` 246 | $ npm install --save-dev gulp del 247 | ``` 248 | 官方文档 249 | ####4.5 run-sequence 250 | 是task有序进行 251 | ``` 252 | npm install --save-dev run-sequence 253 | ``` 254 | 官方文档 255 | 256 | #### 参考文档及更多插件介绍 257 | 258 | 259 | 260 | -------------------------------------------------------------------------------- /old/数组打乱与重排.md: -------------------------------------------------------------------------------- 1 | 去单位的路上在掘金上看到一张图大概是程序员找合租,留下的联系方式类似这样 2 | 3 | ```javascript 4 | let arr1 = ["7", "7", "3", "7", "5", "2", "5", "1", "4", "3", "9"] 5 | let arr2 = [6, 10, 7, 1, 9, 3, 5, 0, 2, 8, 4] 6 | ``` 7 | 8 | 貌似使用java写的,然后组合起来是手机号 9 | 10 | 11 | 12 | 然后想自己来写一个 13 | 14 | 1. 核心是把一个数组打乱,用到了**Fisher–Yates shuffle 洗牌算法** (网上查到的,自己改了一下),方法如下 15 | 16 | ```javascript 17 | function shuffle(arr) { 18 | let len = arr.length 19 | let po = [] 20 | while(len){ 21 | let newIndex = Math.floor(Math.random() * len--) 22 | let num = arr[len] 23 | arr[len] = arr[newIndex] 24 | arr[newIndex] = num 25 | } 26 | return arr 27 | } 28 | ``` 29 | 30 | 2. 更改一下,需要返回对应的位置 31 | 32 | ```javascript 33 | function shuffle(str) { 34 | let arr = str.split('').map((v,i) => { 35 | return [v,i] 36 | }) 37 | let len = arr.length 38 | while(len){ 39 | len -= 1 40 | let newIndex = Math.floor(Math.random() * len) 41 | let num = arr[len] 42 | arr[len] = arr[newIndex] 43 | arr[newIndex] = num 44 | } 45 | return { 46 | phone:arr.map(v=>v[0]), 47 | position:arr.map(v=>v[1]) 48 | } 49 | } 50 | ``` 51 | 52 | 3. 上面的返回结果用于复制到装逼的开头,需要输出正常的排序 53 | 54 | ```javascript 55 | let phone = [] 56 | contact['position'].forEach((v,i) => { 57 | phone[v] = contact['phone'][i] 58 | }) 59 | console.log(phone.join('')) 60 | ``` 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 完整的运行 69 | 70 | ```javascript 71 | function shuffle(str) { 72 | let arr = str.split('').map((v, i) => { 73 | return [v, i] 74 | }) 75 | let len = arr.length 76 | while (len) { 77 | len -= 1 78 | let newIndex = Math.floor(Math.random() * len) 79 | let num = arr[len] 80 | arr[len] = arr[newIndex] 81 | arr[newIndex] = num 82 | } 83 | return { 84 | phone: arr.map(v => v[0]), 85 | position: arr.map(v => v[1]) 86 | } 87 | } 88 | 89 | let contact = shuffle('17429573357') 90 | let phone = [] 91 | 92 | contact['position'].forEach((v, i) => { 93 | phone[v] = contact['phone'][i] 94 | }) 95 | console.log(phone.join('')) 96 | ``` 97 | 98 | -------------------------------------------------------------------------------- /old/滚动条抖动问题.md: -------------------------------------------------------------------------------- 1 | 在做一个tab栏的切换时,因为不同栏的高度不同,导致页面的滚动条在切换中出现或消失使页面抖动, 2 | 3 | 另外,在居中布局的页面中,页面内容超出浏览器高度,也会出现页面抖动的情况 4 | 5 | 解决办法 6 | 7 | 1. ```css 8 | html{ 9 | padding-left: calc(100vw - 100%); 10 | } 11 | ``` 12 | 13 | ​ 14 | 15 | 2. ```css 16 | html { 17 | overflow-y: scroll; 18 | } 19 | 20 | :root { 21 | overflow-y: auto; 22 | overflow-x: hidden; 23 | } 24 | 25 | :root body { 26 | position: absolute; 27 | } 28 | 29 | body { 30 | width: 100vw; 31 | overflow: hidden; 32 | } 33 | ``` 34 | 35 | 参考自张鑫旭的博客,自测时两种方法都可以,但是项目中第二种方法不会出现滚动条,可能是我在布局时设置的是body的高度为100%的原因 36 | 37 | 38 | 39 | 40 | 41 | #### 参考 42 | 43 | > http://www.zhangxinxu.com/wordpress/2015/01/css-page-scrollbar-toggle-center-no-jumping/ -------------------------------------------------------------------------------- /old/记一些css的黑魔法.md: -------------------------------------------------------------------------------- 1 | ####先区分伪类和伪元素 2 | 3 | 伪类 4 | 5 | - 伪类更多的定义的是状态,如`:hover`,或者说是一个可以使用CSS进行修饰的特定的特殊元素 6 | - 伪类使用一个冒号`:` 7 | 8 | 伪元素 9 | 10 | - 伪元素简单来说就是不存在于DOM文档树中的虚拟的元素,它们和HTML元素一样,但是你又无法使用JavaScript去获取,如`:before` 11 | - 伪元素使用两个冒号`::` 12 | 13 | #### 一些不太常用的伪类 14 | 15 | 1. `:focus` 16 | 17 | 选择获得焦点的元素 18 | 19 | 2. `:visited` 20 | 21 | 选择已访问的链接 22 | 23 | 3. `:link` 24 | 25 | 选择未被访问的链接 26 | 27 | 4. `:active` 28 | 29 | 选择活动链接,即当链接被点击时的状态 30 | 31 | 5. `:lang` 32 | 33 | 选取带有以指定值开头的 lang 属性的元素 34 | 35 | ```css 36 | div:lang(hello){ 37 | background:red; 38 | } 39 | ``` 40 | 41 | ```html 42 |

enal

43 | ``` 44 | 45 | 6. `:required` 46 | 47 | 选择具有required 属性的表单元素 48 | 49 | 7. `:valid` 50 | 51 | 选择通过匹配正确的所要求的表单元素 52 | 53 | 8. `:invalid` 54 | 55 | 伪类指定一个不匹配指定要求的表单元素 56 | 57 | 6,7,8虽然能辅助表单验证,但好像并不能阻止提交,只能起到辅助提示的作用 58 | 59 | 9. `:not` 60 | 61 | 排除其他选择器 62 | 63 | ```css 64 | ul > li:not(:last-child)::after { 65 | float:left; 66 | } 67 | ``` 68 | 69 | 除了最后一个li其他都左浮动 70 | 71 | `:not`中可以写任意选择器 72 | 73 | 10. `:nth-child` 74 | 75 | 选择元素的第n个子元素 76 | 77 | ```css 78 | :nth-child(even) /* 下标为偶数的子元素 */ 79 | :nth-child(odd) /* 下标为奇数的子元素 */ 80 | :nth-child(3n) /* 下标为3的倍数的子元素 */ 81 | :nth-child(-n + 4) /* 下标小于4的子元素 */ 82 | ``` 83 | 84 | #### 一些不太常用伪元素 85 | 86 | 1. `::selection` 87 | 88 | 设置选中文本的样式 89 | 90 | 2. `::placeholder` 91 | 92 | 设置表单元素`placeholder`属性的样式 93 | 94 | 3. `::first-letter` 95 | 96 | 设置段落的第一个字体的样式 97 | 98 | 4. `:;first-line` 99 | 100 | 设置段落的第一行文字的样式 101 | 102 | -------------------------------------------------------------------------------- /other/sort/A.js: -------------------------------------------------------------------------------- 1 | var helper = { 2 | range: function(min, max) { 3 | var res = []; 4 | for(var i = min; i < max; i++) { 5 | res.push(i); 6 | } 7 | return res; 8 | }, 9 | 10 | shuffle: function(ary) { 11 | for(var i = ary.length - 1; 0 <= i; i--) { 12 | var rnd = Math.random() * (i + 1) | 0; 13 | helper.swap(ary, i, rnd); 14 | } 15 | }, 16 | 17 | swap: function(ary, a, b) { 18 | if(a < 0 || b < 0 || ary.length <= a || ary.length <= b) { 19 | throw new Error('IndexError ' + a + " - " + b); 20 | } 21 | var temp = ary[a]; 22 | ary[a] = ary[b]; 23 | ary[b] = temp; 24 | }, 25 | 26 | insert: function(ary, from, to) { 27 | while(from != to) { 28 | if(from < to) { 29 | helper.swap(ary, from, from + 1); 30 | from += 1; 31 | } else { 32 | helper.swap(ary, from, from - 1); 33 | from -= 1; 34 | } 35 | } 36 | }, 37 | 38 | median3: function(a, b, c) { 39 | if(b <= a) 40 | if (a <= c) 41 | return a; 42 | else if(c <= b) 43 | return b; 44 | else 45 | return c; 46 | else if(c <= a) 47 | return a; 48 | else if(c <= b) 49 | return c; 50 | else 51 | return b; 52 | }, 53 | 54 | getCanvas: function(id) { 55 | var canvas = document.getElementById(id); 56 | if(canvas === null || canvas.nodeName.toLowerCase() !== 'canvas') { 57 | return document.createElement('canvas'); 58 | } 59 | return canvas; 60 | } 61 | }; 62 | 63 | 64 | var graph = {}; 65 | 66 | (function() { 67 | var canvas; 68 | var ctx; 69 | var width; 70 | var height; 71 | 72 | var bgColor = '#333'; 73 | var barColor = '#6cf'; 74 | var highlightColor = '#cf6'; 75 | 76 | graph.init = function(c) { 77 | canvas = c; 78 | ctx = canvas.getContext('2d'); 79 | width = canvas.offsetWidth; 80 | height = canvas.offsetHeight; 81 | }; 82 | 83 | graph.draw = function(highlightIndexes, values) { 84 | ctx.fillStyle = bgColor; 85 | ctx.fillRect(0, 0, width, height); 86 | var idx1 = highlightIndexes[0]; 87 | var idx2 = highlightIndexes[1]; 88 | 89 | var size = values.length; 90 | var barWidth = (width - size + 1) / size; 91 | var barHeightUnit = height / size; 92 | 93 | var x = 0; 94 | var h = 0; 95 | ctx.fillStyle = barColor; 96 | for(var i = 0; i < values.length; i++) { 97 | h = values[i] * barHeightUnit; 98 | if(i === idx1 || i === idx2) { 99 | ctx.fillStyle = highlightColor; 100 | ctx.fillRect(x, height- h, barWidth, h); 101 | ctx.fillStyle = barColor; 102 | } else { 103 | ctx.fillRect(x, height- h, barWidth, h); 104 | } 105 | x = x + barWidth + 1; 106 | } 107 | }; 108 | })(); 109 | 110 | 111 | function SortStep(type, indexes) { 112 | // type = 'swap' | 'highlight' | 'insert' 113 | this.type = type; 114 | // アニメーション時にハイライトさせるインデックスの配列 115 | this.indexes = indexes; 116 | } 117 | 118 | SortStep.SWAP = 'swap'; 119 | SortStep.HIGHLIGHT = 'highlight'; 120 | SortStep.INSERT = 'insert'; 121 | 122 | SortStep.prototype.run = function(ary) { 123 | if(this.type === SortStep.SWAP) { 124 | helper.swap(ary, this.indexes[0], this.indexes[1]); 125 | } else if(this.type === SortStep.INSERT) { 126 | helper.insert(ary, this.indexes[0], this.indexes[1]); 127 | this.indexes[0] = -1; 128 | } 129 | }; 130 | 131 | 132 | function SortAlgorithm(values) { 133 | this.values = values; 134 | this.size = values.length; 135 | this.steps = []; 136 | this.finished = false; 137 | } 138 | 139 | 140 | SortAlgorithm.prototype.sort = function(algorithm) { 141 | this[algorithm](); 142 | this.steps.reverse(); 143 | // ボゴソートはソートが完了せずに終了する 144 | if(algorithm !== 'bogo') { 145 | this.finished = true; 146 | } 147 | }; 148 | 149 | SortAlgorithm.prototype.addStep = function(type, indexes) { 150 | this.steps.push(new SortStep(type, indexes)); 151 | }; 152 | 153 | SortAlgorithm.prototype.swap = function(a, b) { 154 | helper.swap(this.values, a, b); 155 | this.addStep(SortStep.SWAP, [a, b]); 156 | }; 157 | 158 | SortAlgorithm.prototype.highlight = function(a, b) { 159 | this.addStep(SortStep.HIGHLIGHT, [a, b]); 160 | }; 161 | 162 | SortAlgorithm.prototype.insert = function(from, to) { 163 | helper.insert(this.values, from, to); 164 | this.addStep(SortStep.INSERT, [from, to]); 165 | }; 166 | 167 | SortAlgorithm.prototype.bubble = function bubbleSort() { 168 | for(var i = this.size - 1; 0 < i; i--) { 169 | for(var k = 0; k < i; k++) { 170 | if(this.values[k] > this.values[k + 1]) { 171 | this.swap(k, k + 1); 172 | } else { 173 | this.highlight(k, k + 1); 174 | } 175 | } 176 | } 177 | }; 178 | 179 | SortAlgorithm.prototype.selection = function selectionSort() { 180 | for(var i = 0; i < this.size - 1; i++) { 181 | var min = i; 182 | for(var k = i + 1; k < this.size; k++) { 183 | this.highlight(min, k); 184 | if(this.values[k] < this.values[min]) { 185 | min = k; 186 | } 187 | } 188 | this.swap(i, min); 189 | } 190 | }; 191 | 192 | SortAlgorithm.prototype.shaker = function shakerSort() { 193 | var left = 0; 194 | var right = this.size - 1; 195 | var incr = 1; 196 | var i = 0; 197 | var next; 198 | var lastSwapped = 0; 199 | 200 | var count = 0; 201 | while(left < right) { 202 | next = i + incr; 203 | if((incr === 1 && this.values[i] > this.values[next]) || (incr === -1 && this.values[next] > this.values[i])) { 204 | this.swap(i, next); 205 | lastSwapped = i; 206 | } else { 207 | this.highlight(i, next); 208 | } 209 | 210 | if(next === right) { 211 | i = right = lastSwapped; 212 | incr = -incr; 213 | } else if(next === left) { 214 | i = left = lastSwapped; 215 | incr = -incr; 216 | } else { 217 | i = next; 218 | } 219 | } 220 | }; 221 | 222 | SortAlgorithm.prototype.insertion = function insertionSort() { 223 | for(var i = 1; i < this.size; i++) { 224 | for(var k = i; 0 < k; k--) { 225 | if(this.values[k - 1] > this.values[k]) { 226 | this.swap(k - 1, k); 227 | } else { 228 | this.highlight(k - 1, k); 229 | break; 230 | } 231 | } 232 | } 233 | }; 234 | 235 | SortAlgorithm.prototype.shell = function shellSort() { 236 | var gap = 1; 237 | while(gap < this.size) { 238 | gap = gap * 3 + 1; 239 | } 240 | 241 | while(1 < gap) { 242 | gap = gap / 3 | 0; 243 | for(var i = gap; i < this.size; i++) { 244 | for(var k = i; 0 < k; k -= gap) { 245 | if(this.values[k - gap] > this.values[k]) { 246 | this.swap(k - gap, k); 247 | } else { 248 | this.highlight(k - gap, k); 249 | break; 250 | } 251 | } 252 | } 253 | } 254 | }; 255 | 256 | SortAlgorithm.prototype.merge = function mergeSort() { 257 | this.mergeSortImpl(0, this.size - 1); 258 | }; 259 | 260 | SortAlgorithm.prototype.mergeSortImpl = function(left, right) { 261 | if(right <= left) { 262 | return; 263 | } 264 | var middle = (left + right) / 2 | 0; 265 | this.mergeSortImpl(left, middle); 266 | this.mergeSortImpl(middle + 1, right); 267 | 268 | var l = left; 269 | var m = middle + 1; 270 | while(l < m && m <= right) { 271 | this.highlight(l, m); 272 | if(this.values[l] >= this.values[m]) { 273 | this.insert(m, l); 274 | m++; 275 | } 276 | l++; 277 | } 278 | }; 279 | 280 | SortAlgorithm.prototype.quick = function quickSort() { 281 | this.quickSortImpl(0, this.size - 1); 282 | }; 283 | 284 | SortAlgorithm.prototype.quickSortImpl = function(left, right) { 285 | var values = this.values; 286 | var middle = (left + right) / 2 | 0; 287 | var pivot = helper.median3(values[left], values[middle], values[right]); 288 | var l = left; 289 | var r = right; 290 | while(true) { 291 | while(values[l] < pivot) { 292 | this.highlight(l, r); 293 | l++; 294 | } 295 | while(pivot < values[r]) { 296 | this.highlight(l, r); 297 | r--; 298 | } 299 | if(r <= l) { 300 | break; 301 | } 302 | this.swap(l, r); 303 | l++; 304 | r--; 305 | } 306 | 307 | if(left < l - 1) { 308 | this.quickSortImpl(left, l - 1); 309 | } 310 | if(r + 1 < right) { 311 | this.quickSortImpl(r + 1, right); 312 | } 313 | }; 314 | 315 | SortAlgorithm.prototype.heap = function heapSort() { 316 | for(var i = 0; i < this.size; i++) { 317 | this.swapUp(i); 318 | } 319 | 320 | for(i = this.size - 1; 0 < i; i--) { 321 | if(this.values[0] > this.values[i]) { 322 | this.swap(0, i); 323 | } else { 324 | this.highlight(0, i); 325 | } 326 | this.swapDown(0, i); 327 | } 328 | }; 329 | 330 | SortAlgorithm.prototype.swapUp = function(cur) { 331 | var parent; 332 | while(cur !== 0) { 333 | parent = (cur - 1) / 2 | 0; 334 | if(this.values[parent] >= this.values[cur]) { 335 | this.highlight(parent, cur); 336 | break; 337 | } 338 | this.swap(parent, cur); 339 | cur = parent; 340 | } 341 | }; 342 | 343 | SortAlgorithm.prototype.swapDown = function(cur, length) { 344 | var values = this.values; 345 | var child; 346 | while(true) { 347 | child = cur * 2 + 1; 348 | if(values[child] < values[child + 1]) { 349 | child += 1; 350 | } 351 | if(values[cur] >= values[child]) { 352 | this.highlight(cur, child); 353 | break; 354 | } 355 | if(length <= child) { 356 | break; 357 | } 358 | this.swap(cur, child); 359 | cur = child; 360 | } 361 | }; 362 | 363 | SortAlgorithm.prototype.bogo = function bogoSort() { 364 | for(var i = 0; i < this.size; i++) { 365 | var rnd = (Math.random() * (this.size - i) | 0) + i; 366 | this.swap(i, rnd); 367 | } 368 | 369 | // valuesが整列済みになっているか調べる 370 | for(i = 0; i < this.size - 1; i++) { 371 | this.highlight(i, i + 1); 372 | if(this.values[i] > this.values[i + 1]) { 373 | return; 374 | } 375 | } 376 | this.finished = true; 377 | }; 378 | 379 | 380 | function ViewModel() { 381 | this.algorithm = ko.observable('Bubble'); 382 | this.size = ko.observable(50); 383 | this.speed = ko.observable(9); 384 | 385 | this.sort = null; 386 | this.nums = []; 387 | this.algorithmList = ['Bubble', 'Selection', 'Shaker', 'Insertion', 'Shell', 'Merge', 'Heap', 'Quick', 'Bogo']; 388 | this.sizeList = [5, 10, 50, 100, 150]; 389 | this.speedMin = 1; // 2 seconds 390 | this.speedMax = 22; // 4 milliseconds 391 | this.intervalId = -1; 392 | 393 | graph.init(helper.getCanvas('graph-canvas')); 394 | 395 | this.changed = ko.computed({ 396 | read: function() { 397 | this.start(this.algorithm(), this.size()); 398 | }, 399 | owner: this, 400 | deferEvaluation: true, 401 | }); 402 | } 403 | 404 | ViewModel.prototype.start = function(algorithm, size) { 405 | var vm = this; 406 | this.nums = helper.range(1, size + 1); 407 | helper.shuffle(this.nums); 408 | this.sort = new SortAlgorithm(this.nums.slice()); 409 | 410 | clearInterval(this.intervalId); 411 | this.intervalId = setTimeout(animationFrame, 0); 412 | 413 | function animationFrame() { 414 | if(vm.sort.steps.length === 0) { 415 | if(vm.sort.finished) { 416 | graph.draw([-1, -1], vm.nums); 417 | return; 418 | } else { 419 | vm.sort.sort(algorithm.toLowerCase()); 420 | console.log(vm.sort.steps.length); 421 | } 422 | } 423 | 424 | var step = vm.sort.steps.pop(); 425 | step.run(vm.nums); 426 | graph.draw(step.indexes, vm.nums); 427 | vm.intervalId = setTimeout(animationFrame, vm.getIntervalTime()); 428 | } 429 | }; 430 | 431 | ViewModel.prototype.restart = function() { 432 | this.start(this.algorithm.peek(), this.size.peek()); 433 | }; 434 | 435 | ViewModel.prototype.getIntervalTime = function() { 436 | var speed = parseInt(this.speed.peek(), 10); 437 | return 2000 / speed / speed | 0; 438 | }; 439 | 440 | 441 | if(document.documentElement.hasAttribute('sort-visualize-app')) { 442 | document.addEventListener('DOMContentLoaded', main); 443 | } 444 | 445 | function main() { 446 | var vm = window.vm = new ViewModel(); 447 | ko.applyBindings(vm); 448 | vm.changed(); 449 | } 450 | -------------------------------------------------------------------------------- /other/sort/bubble.js: -------------------------------------------------------------------------------- 1 | function bubbleSort(arr) { 2 | for (let i = 0; i < arr.length - 1; i++) { 3 | for (let j = 0; j < arr.length - 1 - i; j++) { 4 | if (arr[j] > arr[j + 1]) { 5 | let temp = arr[j] 6 | arr[j] = arr[j + 1] 7 | arr[j + 1] = temp 8 | } 9 | } 10 | } 11 | return arr 12 | } 13 | -------------------------------------------------------------------------------- /other/sort/bucket.js: -------------------------------------------------------------------------------- 1 | // 不理解,先复制记录下来 ... 2 | Array.prototype.bucketSort = function(num) { 3 | function swap(arr, i, j) { 4 | const temp = arr[i] 5 | arr[i] = arr[j] 6 | arr[j] = temp 7 | } 8 | const max = Math.max(...this) 9 | const min = Math.min(...this) 10 | const buckets = [] 11 | const bucketsSize = Math.floor((max - min) / num) + 1 12 | for(let i = 0; i < this.length; i++) { 13 | const index = ~~(this[i] / bucketsSize) 14 | !buckets[index] && (buckets[index] = []) 15 | buckets[index].push(this[i]) 16 | let l = buckets[index].length 17 | while(l > 0) { 18 | buckets[index][l] < buckets[index][l - 1] && swap(buckets[index], l, l - 1) 19 | l-- 20 | } 21 | } 22 | let wrapBuckets = [] 23 | for(let i = 0; i < buckets.length; i++) { 24 | buckets[i] && (wrapBuckets = wrapBuckets.concat(buckets[i])) 25 | } 26 | return wrapBuckets 27 | } 28 | -------------------------------------------------------------------------------- /other/sort/count.js: -------------------------------------------------------------------------------- 1 | function countSort(arr) { 2 | let C = [] 3 | 4 | for (let i = 0; i < arr.length; i++) { 5 | let num = arr[i] 6 | C[num] >= 1 ? C[num]++ : (C[num] = 1) 7 | } 8 | 9 | let sortArr = [] 10 | 11 | for (let j = 0; j < C.length; j++) { 12 | if(C[j]){ 13 | while(C[j]>0){ 14 | sortArr.push(j) 15 | C[j] -- 16 | } 17 | } 18 | } 19 | return sortArr 20 | } 21 | -------------------------------------------------------------------------------- /other/sort/heap.js: -------------------------------------------------------------------------------- 1 | function heapSort(arr){ 2 | function swap(i, j) { 3 | let tmp = arr[i] 4 | arr[i] = arr[j] 5 | arr[j] = tmp 6 | } 7 | 8 | function max_heapify(start, end) { 9 | let dad = start 10 | let son = dad * 2 + 1 11 | 12 | if (son >= end) return 13 | 14 | if (son + 1 < end && arr[son] < arr[son + 1]){ 15 | son++ 16 | } 17 | 18 | if (arr[dad] <= arr[son]) { 19 | swap(dad, son) 20 | max_heapify(son, end) 21 | } 22 | } 23 | 24 | let len = arr.length 25 | 26 | for (let i = Math.floor(len / 2) - 1; i >= 0; i--){ 27 | max_heapify(i, len) 28 | } 29 | 30 | for (let i = len - 1; i > 0; i--) { 31 | swap(0, i) 32 | max_heapify(0, i) 33 | } 34 | 35 | return arr 36 | } 37 | -------------------------------------------------------------------------------- /other/sort/insertion.js: -------------------------------------------------------------------------------- 1 | function insertion(arr) { 2 | for (let i = 1; i < arr.length; i++) { 3 | for (let j = 0; j < i; j++) { 4 | if (arr[j] > arr[i]) { 5 | arr.splice(j, 0, arr[i]) 6 | arr.splice(i + 1, 1) 7 | break 8 | } 9 | } 10 | } 11 | return arr 12 | } 13 | -------------------------------------------------------------------------------- /other/sort/merge.js: -------------------------------------------------------------------------------- 1 | function mergeSort(arr) { 2 | if (arr.length < 2) return arr 3 | 4 | function merge(left, right) { 5 | let final = [] 6 | 7 | while (left.length && right.length) { 8 | final.push(left[0] <= right[0] ? left.shift() : right.shift()) 9 | } 10 | return final.concat(left, right) 11 | } 12 | 13 | let mid = Math.floor(arr.length / 2) 14 | 15 | return merge(mergeSort(arr.slice(0, mid)), mergeSort(arr.slice(mid))) 16 | } 17 | -------------------------------------------------------------------------------- /other/sort/merge2.js: -------------------------------------------------------------------------------- 1 | function merge(left, right) { 2 | var result = []; 3 | 4 | while (left.length && right.length) { 5 | if (left[0] < right[0]) 6 | result.push(left.shift()); 7 | else 8 | result.push(right.shift()); 9 | } 10 | 11 | return result.concat(left, right); 12 | } 13 | 14 | function mergeSort(a) { 15 | if (a.length === 1) 16 | return a; 17 | 18 | var work = []; 19 | for (var i = 0, len = a.length; i < len; i++) 20 | work.push([a[i]]); 21 | 22 | work.push([]); // 如果数组长度为奇数 23 | 24 | for (var lim = len; lim > 1; lim = ~~((lim + 1) / 2)) { 25 | for (var j = 0, k = 0; k < lim; j++, k += 2) 26 | work[j] = merge(work[k], work[k + 1]); 27 | 28 | work[j] = []; // 如果数组长度为奇数 29 | } 30 | 31 | return work[0]; 32 | } 33 | -------------------------------------------------------------------------------- /other/sort/quick.js: -------------------------------------------------------------------------------- 1 | function quickSort(arr) { 2 | if (arr.length < 2) return arr 3 | 4 | const pivot = arr[0] 5 | const left = [] 6 | const right = [] 7 | 8 | for (let i = 1; i < arr.length; i++) { 9 | arr[i] >= pivot && right.push(arr[i]) 10 | arr[i] < pivot && left.push(arr[i]) 11 | } 12 | 13 | return quickSort(left).concat(pivot, quickSort(right)) 14 | } 15 | -------------------------------------------------------------------------------- /other/sort/quick2.js: -------------------------------------------------------------------------------- 1 | function quickSort(arr, left, right) { 2 | let len = arr.length 3 | let partitionIndex 4 | left = typeof left !== 'number' ? 0 : left 5 | right = typeof right !== 'number' ? len - 1 : right 6 | 7 | if (left < right) { 8 | partitionIndex = partition(arr, left, right) 9 | 10 | quickSort(arr, left, partitionIndex - 1) 11 | 12 | quickSort(arr, partitionIndex + 1, right) 13 | } 14 | 15 | return arr 16 | } 17 | 18 | function partition(arr, left, right) { 19 | let pivot = left 20 | let index = pivot + 1 21 | 22 | for (var i = index; i <= right; i++) { 23 | if (arr[i] < arr[pivot]) { 24 | swap(arr, i, index) 25 | index++ 26 | } 27 | } 28 | 29 | swap(arr, pivot, index - 1) 30 | 31 | return index - 1; 32 | } 33 | 34 | function swap(arr, i, j) { 35 | var temp = arr[i] 36 | arr[i] = arr[j] 37 | arr[j] = temp 38 | } 39 | -------------------------------------------------------------------------------- /other/sort/selection.js: -------------------------------------------------------------------------------- 1 | function selectionSort(arr) { 2 | for (let i = 0; i < arr.length - 1; i++) { 3 | let min = i 4 | 5 | for (let j = i + 1; j < arr.length; j++) { 6 | if (arr[min] > arr[j]) { 7 | min = j 8 | } 9 | } 10 | 11 | let temp = arr[min] 12 | arr[min] = arr[i] 13 | arr[i] = temp 14 | } 15 | 16 | return arr 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "npx vuepress dev docs", 8 | "build": "vuepress build docs", 9 | "deploy": "gh-pages -d dist", 10 | "deploy:build": "npm run build && gh-pages -d dist" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "@vuepress/plugin-google-analytics": "^1.0.0-rc.1", 16 | "@vuepress/plugin-nprogress": "^1.0.0-rc.1", 17 | "element-ui": "^2.9.1", 18 | "gh-pages": "^2.0.1", 19 | "gitalk": "^1.5.0", 20 | "node-sass": "^4.12.0", 21 | "sass-loader": "^7.1.0", 22 | "vuepress": "^1.0.1" 23 | }, 24 | "dependencies": { 25 | "clipboard": "^2.0.4", 26 | "vue-i18n": "^8.14.0", 27 | "vuepress-plugin-cat": "^1.0.2" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 关于 2 | 最初的设想把平常见到的问题和知识点放在 css tricksjs tricks,这样就能少说些花里胡哨的东西,言简意赅的记录问题和解决方法,但是当写 you need to know js 的时候,发现在 js tricks 这样全是方法代码的地方写大量文字的介绍好像并不合适,所以又重新组织了这个blog,同时把需要大量文字的记录放在这里。 3 | 4 | 这里只是学习的记录,不会过多讲解(或者说只是我懂的讲解) 5 | 6 | ## blog 7 | view online 8 | 9 | ## css tricks 10 | view online 11 | 12 | ## js tricks 13 | view online 14 | -------------------------------------------------------------------------------- /realize/apply.js: -------------------------------------------------------------------------------- 1 | Function.prototype.apply = (context = window, args) => { 2 | context.fn = this; 3 | let res; 4 | 5 | if (args.length) { 6 | res = context.fn(args); 7 | } else { 8 | res = context.fn(); 9 | } 10 | 11 | delete context.fn; 12 | return res; 13 | }; 14 | -------------------------------------------------------------------------------- /realize/bind.js: -------------------------------------------------------------------------------- 1 | Function.prototype.bind = context => { 2 | const self = this; 3 | const args = [].slice.call(arguments, 1); 4 | 5 | function resFn() { 6 | return self.apply( 7 | this instanceof resFn ? this : context, 8 | args.concat(...arguments) 9 | ); 10 | } 11 | 12 | function middleFn() {} 13 | 14 | middleFn.prototype = self.prototype; 15 | resFn.prototype = new middleFn(); 16 | 17 | return resFn(); 18 | }; 19 | -------------------------------------------------------------------------------- /realize/call.js: -------------------------------------------------------------------------------- 1 | Function.prototype.call = (context = window) => { 2 | context.fn = this 3 | const args = [...arguments].slice(1) 4 | const res = context.fn(...args) 5 | delete context.fn 6 | return res 7 | } 8 | -------------------------------------------------------------------------------- /realize/curry.js: -------------------------------------------------------------------------------- 1 | function curry(fn, ...args) { 2 | const length = fn.length; 3 | 4 | return function() { 5 | let newArgs = args.concat(...arguments); 6 | if (newArgs.length < length) { 7 | return curry.call(this, fn, ...newArgs); 8 | } else { 9 | return fn.apply(this, newArgs); 10 | } 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /realize/debounce.js: -------------------------------------------------------------------------------- 1 | function debounce(fn, waitTime) { 2 | let timeout; 3 | 4 | return function() { 5 | clearTimeout(timeout); 6 | const args = arguments; 7 | timeout = setTimeout(() => { 8 | fn.apply(this, [...args]); 9 | }, waitTime); 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /realize/new.js: -------------------------------------------------------------------------------- 1 | function myNew() { 2 | const obj = {}; 3 | const constructor = [].shift.call(arguments); 4 | obj.__proto__ = constructor.prototype; 5 | const reslut = constructor.apply(obj, arguments); 6 | return reslut && reslut instanceof Object ? reslut : obj; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /realize/promise.ts: -------------------------------------------------------------------------------- 1 | interface MyPromise { 2 | status: 'pendding' | 'resloved' | 'rejected' 3 | data: any 4 | onResolvedCallback: Array 5 | onRejectedCallback: Array 6 | 7 | 8 | then: (onFulfill?: any, onReject?: any) => void 9 | 10 | catch: (reason: any) => void 11 | 12 | resolve: (val: any) => Promise 13 | 14 | reject: (reason: any) => Promise 15 | 16 | all: (promises: Array) => Promise 17 | 18 | race: (promises: Array) => Promise 19 | } 20 | 21 | 22 | class Promise implements MyPromise { 23 | private status 24 | private data 25 | private onResolvedCallback 26 | private onRejectedCallback 27 | 28 | constructor(executor?: Function) { 29 | this.status = 'pendding' 30 | 31 | this.onResolvedCallback = [] 32 | this.onRejectedCallback = [] 33 | 34 | const resolve = (value) => { 35 | if (value instanceof Promise) { 36 | return value.then(resolve, reject) 37 | } 38 | 39 | setTimeout(() => { 40 | if (this.status === 'pendding') { 41 | this.status = 'resloved' 42 | this.data = value 43 | this.onResolvedCallback.forEach((fn) => fn(value)) 44 | } 45 | }) 46 | } 47 | 48 | const reject = (reason) => { 49 | setTimeout(() => { 50 | if (this.status === 'pendding') { 51 | this.status = 'rejected' 52 | this.data = reason 53 | this.onRejectedCallback.forEach((fn) => fn(reason)) 54 | } 55 | }) 56 | } 57 | 58 | try { 59 | executor(resolve, reject) 60 | } catch (e) { 61 | this.catch(e) 62 | } 63 | } 64 | 65 | public then(onFulfill, onReject) { 66 | const self = this 67 | let promise2 68 | onFulfill = typeof onFulfill === 'function' ? onFulfill : (v) => v 69 | onReject = typeof onReject === 'function' ? onReject : (v) => { 70 | throw v 71 | } 72 | 73 | if (self.status === 'resolved') { 74 | return promise2 = new Promise(function (resolve, reject) { 75 | try { 76 | var x = onFulfill(self.data) 77 | if (x instanceof Promise) { 78 | x.then(resolve, reject) 79 | } 80 | resolve(x) 81 | } catch (e) { 82 | reject(e) 83 | } 84 | }) 85 | } 86 | 87 | if (self.status === 'rejected') { 88 | return promise2 = new Promise(function (resolve, reject) { 89 | try { 90 | var x = onReject(self.data) 91 | if (x instanceof Promise) { 92 | x.then(resolve, reject) 93 | } 94 | } catch (e) { 95 | reject(e) 96 | } 97 | }) 98 | } 99 | 100 | if (self.status === 'pendding') { 101 | promise2 = new Promise((resolve, reject) => { 102 | self.onResolvedCallback.push((value) => { 103 | try { 104 | let x = onFulfill(value) 105 | resolvePromise(promise2, x, resolve, reject) 106 | } catch (e) { 107 | reject(e) 108 | } 109 | }) 110 | 111 | self.onRejectedCallback.push((value) => { 112 | try { 113 | let x = onReject(value) 114 | resolvePromise(promise2, x, resolve, reject) 115 | } catch (e) { 116 | reject(e) 117 | } 118 | }) 119 | }) 120 | } 121 | 122 | return promise2 123 | } 124 | 125 | public catch(reason) { 126 | return this.then(null, onRejected) 127 | } 128 | 129 | public resolve(val) { 130 | return new Promise((resolve, reject) => { 131 | resolve(val) 132 | }) 133 | } 134 | 135 | public reject(reason) { 136 | return new Promise((resolve, reject) => { 137 | reject(reason) 138 | }) 139 | } 140 | 141 | public all(promises) { 142 | let datas = [] 143 | let len = 0 144 | 145 | function processData(data, index, resolve) { 146 | len += 1 147 | datas[index] = data 148 | if (len === promises.length) { 149 | resolve(datas) 150 | } 151 | } 152 | 153 | return new Promise((resolve, reject) => { 154 | promises.forEach((promise, index) => { 155 | if (promise instanceof Promise) { 156 | promise.then((data) => processData(data, index, resolve)) 157 | } else { 158 | this.resolve(promise).then((data) => processData(data, index, resolve)) 159 | } 160 | }) 161 | }) 162 | } 163 | 164 | public race(promises) { 165 | return new Promise((resolve, reject) => { 166 | promises.forEach((promise, index) => { 167 | if (promise instanceof Promise) { 168 | promise.then(resolve, reject) 169 | } else { 170 | this.resolve(promise).then(resolve, reject) 171 | } 172 | }) 173 | }) 174 | } 175 | } 176 | 177 | function resolvePromise(promise2: Function, x: Function, resolve: Function, reject: Function): void { 178 | var then 179 | var thenCalledOrThrow = false 180 | 181 | if (promise2 === x) { 182 | return reject(new TypeError('Chaining cycle detected for promise!')) 183 | } 184 | 185 | if (x instanceof Promise) { 186 | if (x.status === 'pendding') { 187 | x.then(function (v) { 188 | resolvePromise(promise2, v, resolve, reject) 189 | }, reject) 190 | } else { 191 | x.then(resolve, reject) 192 | } 193 | return 194 | } 195 | 196 | if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) { 197 | try { 198 | then = x.then 199 | if (typeof then === 'function') { 200 | then.call(x, function rs(y) { 201 | if (thenCalledOrThrow) return 202 | thenCalledOrThrow = true 203 | return resolvePromise(promise2, y, resolve, reject) 204 | }, function rj(r) { 205 | if (thenCalledOrThrow) return 206 | thenCalledOrThrow = true 207 | return reject(r) 208 | }) 209 | } else { 210 | resolve(x) 211 | } 212 | } catch (e) { 213 | if (thenCalledOrThrow) return 214 | thenCalledOrThrow = true 215 | return reject(e) 216 | } 217 | } else { 218 | resolve(x) 219 | } 220 | } 221 | 222 | -------------------------------------------------------------------------------- /realize/throttle.js: -------------------------------------------------------------------------------- 1 | function throttle(fn, timehold) { 2 | let startTime = new Date().getTime(); 3 | const context = this; 4 | 5 | return function() { 6 | const currentTime = new Date().getTime(); 7 | if (currentTime - startTime >= timehold) { 8 | fn.apply(context, [...arguments]); 9 | 10 | startTime = currentTime; 11 | } 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | Title 10 | 11 | 12 | 13 | 14 |
15 | 16 |

17 |
18 | 19 | 20 | 21 | 22 | http://storage.360buyimg.com/douya/spring-cms/image001.png 23 | --------------------------------------------------------------------------------