├── .editorconfig ├── .github └── FUNDING.yml ├── .gitignore ├── COPYING ├── Gemfile ├── README-EN.md ├── README.md ├── _config.yml ├── _includes ├── about.html ├── categories.html ├── comment.html ├── contact.html ├── footer.html ├── header.html ├── projects.html ├── tags.html └── tools.html ├── _layouts ├── page.html └── post.html ├── _posts ├── 2018-03-27-Markdown-tutorial.md ├── 2018-03-28-markdown-total.md ├── 2018-03-30-c-leap-year.md ├── 2018-03-30-c-multiply-table.md ├── 2018-03-30-c-prime-number.md ├── 2018-04-01-github-pages-blog.md ├── 2018-04-04-negative-binary.md ├── 2018-04-06-bit-operation.md ├── 2018-04-06-recursion-factorial.md ├── 2018-04-10-c-self-plus.md ├── 2018-04-15-kali-linux-install.md ├── 2018-04-21-linux-sources-list.md ├── 2018-04-24-c-gluttonous-snake.md ├── 2018-04-25-c-rand-number.md ├── 2018-04-28-c-storage-type.md ├── 2018-05-02-css-selector.md ├── 2018-05-04-css-layout-model.md ├── 2018-05-22-css-content-center.md ├── 2018-05-22-web-browser-history.md ├── 2018-05-23-js-anonymous-function.md ├── 2018-05-24-js-timer-function.md ├── 2018-05-31-js-closure.md ├── 2018-05-31-js-eventlistener.md ├── 2018-06-01-jq-syntax.md ├── 2018-06-01-js-logic-compute.md ├── 2018-11-25-discuz-website.md ├── 2018-12-08-ssd.md ├── 2019-01-27-ascii-unicode.md ├── 2019-01-27-base64.md ├── 2019-01-27-css-draw-polygon.md ├── 2019-01-27-css-px.md ├── 2019-01-27-css-transform.md ├── 2019-01-27-css-transition-animation.md ├── 2019-01-27-css-webkit.md ├── 2019-01-27-js-iteration.md ├── 2019-01-27-linux-apt-lock.md ├── 2019-01-27-linux-umount.md ├── 2019-01-27-linux-xrandr.md ├── 2019-01-27-programming-paradigm.md ├── 2019-03-04-articles-search.md ├── 2019-05-01-js-call.md ├── 2019-05-01-js-ecmascript-history.md ├── 2019-05-01-js-oop.md ├── 2019-05-01-js-sort.md ├── 2019-05-11-js-permutation.md ├── 2019-06-20-js-event-loop.md ├── 2019-06-20-sudo-nopasswd.md ├── 2019-08-02-js-async-await.md ├── 2019-08-02-js-sparse-array.md ├── 2019-09-02-js-febonacci.md ├── 2019-09-02-js-hoisting.md ├── 2019-09-02-js-mutation-array.md ├── 2019-09-02-js-try.md ├── 2019-09-03-js-lcm.md ├── 2019-10-07-js-magic-expression.md ├── 2020-01-10-linux-kali-android.md ├── 2020-01-12-js-array-sort.md ├── 2020-01-14-website-add-category.md ├── 2020-03-09-js-binary-data.md ├── 2020-03-13-js-comment-format.md ├── 2020-03-21-programme-float-point.md ├── 2020-04-15-linux-chinese.md ├── 2020-05-20-system-login-blackscreen.md ├── 2020-05-23-tools-devtool-shortcut.md ├── 2020-05-24-linux-shell-shortcut.md ├── 2020-09-03-js-react-props.md ├── 2020-09-10-js-react-state-update.md ├── 2020-11-29-js-redux-summary.md ├── 2021-01-17-js-design-pattern.md ├── 2021-01-18-git-ignorecase.md ├── 2021-03-21-git-submodule.md ├── 2021-04-03-js-ts-type-compare.md ├── 2021-04-18-js-ts-generic-type.md ├── 2021-05-09-js-react-purecomponent.md ├── 2021-07-05-css-flex-chrome-safari-bug.md ├── 2021-09-04-exploit-take-down-swindle-website.md ├── 2021-12-06-exploit-penetrate-bocai-website.md └── 2022-07-17-tools-ssh-tunnel.md ├── about.md ├── assets ├── css │ ├── about.sass │ ├── article-category.sass │ ├── categories.sass │ ├── contact.sass │ ├── icons.sass │ ├── index.sass │ ├── materialize.min.css │ ├── page.sass │ ├── post.sass │ ├── projects.sass │ ├── syntax.scss │ ├── tags.sass │ └── tools.sass ├── fonts │ ├── SourceCodePro-Regular.ttf │ └── icon-font.woff2 ├── img │ ├── ad-huaweiyun-0.png │ ├── ad-huaweiyun-1.png │ ├── ad-huaweiyun.png │ ├── alipay.png │ ├── bg.png │ ├── favicon.ico │ ├── icons │ │ ├── access_time.svg │ │ ├── call_split.svg │ │ ├── chevron_left.svg │ │ ├── chevron_right.svg │ │ ├── clear.svg │ │ ├── close.svg │ │ ├── date_range.svg │ │ ├── description.svg │ │ ├── email.svg │ │ ├── home.svg │ │ ├── info.svg │ │ ├── label.svg │ │ ├── menu.svg │ │ ├── more_vert.svg │ │ ├── person.svg │ │ ├── rss_feed.svg │ │ ├── search.svg │ │ ├── sort.svg │ │ └── star.svg │ ├── knight.png │ ├── logo.png │ ├── my-weixin.png │ ├── user.png │ ├── wechat-slide.png │ ├── wechat.png │ └── wxpay.png └── js │ ├── min │ ├── about.min.js │ ├── gen-category.min.js │ ├── geopattern.min.js │ ├── main.min.js │ ├── materialize.min.js │ ├── particles.min.js │ ├── post.min.js │ ├── projects.min.js │ ├── search.min.js │ └── tools.min.js │ └── normal │ ├── about.js │ ├── gen-category.js │ ├── main.js │ ├── post.js │ ├── projects.js │ ├── search.js │ └── tools.js ├── baidu_verify_Wkb0Jzk8yx.html ├── categories.md ├── contact.md ├── feed.xml ├── index.html ├── message.md ├── minify.cmd ├── projects.md ├── tags.md └── tools.md /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = crlf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = false 13 | 14 | [*.sass] 15 | indent_size = 2 -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | # github: knightyun # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | # patreon: # Replace with a single Patreon username 5 | # open_collective: # Replace with a single Open Collective username 6 | # ko_fi: # Replace with a single Ko-fi username 7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | # liberapay: # Replace with a single Liberapay username 10 | # issuehunt: # Replace with a single IssueHunt username 11 | # otechie: # Replace with a single Otechie username 12 | custom: [ 13 | 'https://knightyun.github.io/assets/img/wxpay.png', 14 | 'https://knightyun.github.io/assets/img/alipay.png' 15 | ] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.gem 3 | .vscode 4 | .bundle 5 | .sass-cache 6 | .jekyll-metadata 7 | _site 8 | Gemfile.lock 9 | vendor -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # 这个文件用于管理 Jekyll 运行时需要安装的依赖; 2 | # 当你想使用某个依赖的另外一个版本时,那么就在下面的配置进行修改; 3 | # 然后保存该文件,再运行 bundle install 就可以更新相应版本了; 4 | # 启动 Jekyll 本地服务请使用下面的命令: 5 | # 6 | # bundle exec jekyll serve 7 | # 8 | # 下面的配置用于更改 Jekyll 的默认版本: 9 | # gem "jekyll", "~> 3.8.5" 10 | 11 | # 这是 Jekyll 网站的默认主题,你可以换成自己喜欢的其它主题: 12 | # gem "minima", "~> 2.0" 13 | 14 | # 另外,如果你使用 GitHub Pages 功能搭建网站的话, 15 | # 那么请将上面的代码注释掉,换成使用下面的代码: 16 | 17 | gem "github-pages", group: :jekyll_plugins 18 | 19 | # 需要更新相关依赖版本,请运行命令:bundle update github-pages 20 | 21 | # 如果需要使用插件的话,请改变下面的配置: 22 | # 23 | group :jekyll_plugins do 24 | # gem "jekyll-feed", "~> 0.6" 25 | gem "jekyll-admin" 26 | end 27 | 28 | # Windows 不支持空文件,需要使用下面的包: 29 | gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby] 30 | 31 | # 默认是官方的 ruby 源,可以选择中国的源进行加速: 32 | # source 'https://gems.ruby-china.com' 33 | source 'https://rubygems.org' 34 | 35 | # Windows 平台中如果频繁改变文件内容,使用下面的包可以提升性能: 36 | gem 'wdm', '>=0.1.0' if Gem.win_platform? 37 | 38 | # Fix ruby 3.0 webrick bug 39 | gem "webrick" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 | 简体中文 | English 4 |
5 |

knightyun.github.io

6 |

基于 jekyll 的响应式 Github Pages 个人博客网站

7 | 8 | [![license](https://img.shields.io/github/license/knightyun/knightyun.github.io)](https://github.com/knightyun/knightyun.github.io/blob/master/COPYING) 9 | [![Gitter](https://img.shields.io/gitter/room/knightyun/knightyun.github.i0)](https://gitter.im/knightyun-github-io/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 10 | [![Website](https://img.shields.io/website?down_color=lightgrey%09&down_message=offline&up_color=%09aqua&up_message=online&url=https%3A%2F%2Fknightyun.github.io)](https://knightyun.github.io) 11 | [![GitHub deployments](https://img.shields.io/github/deployments/knightyun/knightyun.github.io/github-pages)](https://github.com/knightyun/knightyun.github.io/deployments) 12 | ![GitHub top language](https://img.shields.io/github/languages/top/knightyun/knightyun.github.io) 13 | 14 | ![GitHub stars](https://img.shields.io/github/stars/knightyun/knightyun.github.io?style=flat) 15 | ![GitHub forks](https://img.shields.io/github/forks/knightyun/knightyun.github.io?style=flat) 16 | ![GitHub followers](https://img.shields.io/github/followers/knightyun?style=flat) 17 | [![Github issues](https://img.shields.io/badge/issues-welcome-success)](https://github.com/knightyun/knightyun.github.io/issues) 18 | [![Github pull request](https://img.shields.io/badge/pull%20request-welcome-success)](https://github.com/knightyun/knightyun.github.io/pulls) 19 | 20 | [![GitHub last commit](https://img.shields.io/github/last-commit/knightyun/knightyun.github.io)](https://github.com/knightyun/knightyun.github.io/commit/master) 21 | [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/knightyun/knightyun.github.io)](https://github.com/knightyun/knightyun.github.io/graphs/commit-activity) 22 | ![GitHub repo size](https://img.shields.io/github/repo-size/knightyun/knightyun.github.io) 23 |
24 | 25 | ## 特性 26 | 27 | - 适配移动端与桌面端展示效果 | [预览](https://knightyun.github.io) 28 | - 个性化自动展示 GitHub 项目 | [预览](https://knightyun.github.io/projects) 29 | - 文章按类别与标签归档展示 | [预览](https://knightyun.github.io/categories) 30 | - 支持搜索框,按关键词搜索全站文章 | [预览](https://knightyun.github.io) 31 | - 文章评论与留言板功能 | [预览](https://knightyun.github.io/message) 32 | - 生动的 “关于” 页面 | [预览](https://knightyun.github.io/about) 33 | 34 | ## 使用 35 | 36 | 详细搭建教程:[搭建 Github Pages 个人博客网站](https://knightyun.github.io/2018/04/01/github-pages-blog) 37 | 38 | jekyll 使用教程: 39 | 40 | ## 配置 41 | 42 | 配置文件是位于主目录的 `_config.yml`,关于配置的完整参数介绍和默认值等内容,请查阅官网文档: 43 | 44 | 以下是我的网站配置示例,以供参考: 45 | ```yml 46 | # 以下为自定义的全局变量,可以在 HTML 文件中引用, 47 | # 比如代码:

{{ site.title }}

48 | # 将会展示为设定的值,也可以自行添加其他自定义全局变量。 49 | title: 瑝琦的博客 # 网站的标题 50 | description: > # 网站的描述,可能会出现在搜索引擎展示结果中 51 | 基于 jekyll 的 Github Pages 个人博客网站,技术的学习、总结、分享与提升 52 | url: "https://knightyun.github.io" # 网站地址 53 | github_repo: knightyun/knightyun.github.io 54 | github_profile: "https://github.com/knightyun" # GitHub 个人主页 55 | user: "瑝琦" # 用于侧栏展示的名字 56 | user_email: "2386209384@qq.com" # 侧栏展示的联系方式 57 | paginate: 5 # 主页展示的博客文章数量 58 | 59 | # jekyll 相关配置 60 | markdown: kramdown 61 | plugins: 62 | - jekyll-feed 63 | - jekyll-paginate 64 | - jekyll-seo-tag 65 | - jekyll-sitemap 66 | exclude: 67 | - Gemfile 68 | - Gemfile.lock 69 | - README.md 70 | - COPYING 71 | - vendor 72 | sass: 73 | style: compressed 74 | future: true 75 | permalink: /:year/:month/:day/:title 76 | theme: jekyll-theme-slate 77 | ``` 78 | 79 | ## 配置开发环境 80 | 81 | 提交推送代码后,GitHub Pages页面(即博客网站主页)更新较慢,所以推荐搭建本地开发环境,以便调试。 82 | 83 | 详细教程请见:[安装 jekyll](https://knightyun.github.io/2018/04/01/github-pages-blog#%E5%AE%89%E8%A3%85jekyll-) 84 | 85 | 配置好依赖后在项目主目录运行: 86 | ```cmd 87 | bundle exec jekyll s 88 | ``` 89 | 90 | 然后会提示浏览器打开 `http://127.0.0.1:4000` 预览网站,正常情况预览效果与 GitHub Pages 展示的一样,这样就可以在本地开发调试好了再推送到 GitHub。 91 | 92 | ## 用到的第三方库 93 | 94 | - [Materialize.css](http://materializecss.com/):一个不错的样式组件库 95 | - [GeoPattern](http://btmills.github.io/geopattern/):格式化生成有趣的背景图 96 | - [particles.js](https://marcbruederlin.github.io/particles.js/):粒子连接效果 97 | - [Valine](https://valine.js.org/):博客评论插件 98 | 99 | ## 参考 100 | 101 | - https://github.com/ShawnTeoh/matjek 102 | 103 | ## License 104 | 105 | [GPL v3](https://github.com/knightyun/knightyun.github.io/blob/master/COPYING) -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Jekyll! 2 | # 3 | # This config file is meant for settings that affect your whole blog, values 4 | # which you are expected to set up once and rarely edit after that. If you find 5 | # yourself editing this file very often, consider using Jekyll's data files 6 | # feature for the data you need to update frequently. 7 | # 8 | # For technical reasons, this file is *NOT* reloaded automatically when you use 9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process. 10 | 11 | # 以下为自定义的全局变量,可以在 HTML 文件中引用, 12 | # 比如代码:

{{ site.title }}

13 | # 将会展示为设定的值,也可以自行添加其他自定义全局变量。 14 | title: 瑝琦的博客 # 网站的标题 15 | description: > # 网站的描述,可能会出现在搜索引擎展示结果中 16 | 基于 jekyll 的 Github Pages 个人博客网站,技术的学习、总结、分享与提升 17 | url: "https://knightyun.github.io" # 网站地址 18 | github_repo: "https://github.com/knightyun/knightyun.github.io" 19 | github_profile: "https://github.com/knightyun" # GitHub 个人主页 20 | user: "瑝琦" # 用于侧栏展示的名字 21 | user_email: "2386209384@qq.com" # 侧栏展示的联系方式 22 | paginate: 5 # 主页展示的博客文章数量 23 | nick_name: "瑝琦" # 昵称 24 | english_name: "Knight" 25 | # valine 评论插件配置 26 | valine: 27 | leancloud_appid: "4XY3DoTJmibNe3rHeAKOxqzl-gzGzoHsz" 28 | leancloud_appkey: "vjothQHALvgTQF9GrSgj577a" 29 | 30 | # jekyll 相关配置 31 | markdown: kramdown 32 | plugins: 33 | - jekyll-feed 34 | - jekyll-paginate 35 | - jekyll-seo-tag 36 | - jekyll-sitemap 37 | - jekyll-admin 38 | exclude: 39 | - Gemfile 40 | - Gemfile.lock 41 | - README.md 42 | - COPYING 43 | - vendor 44 | - minify.cmd 45 | sass: 46 | style: compressed 47 | lang: zh_CN 48 | future: true 49 | permalink: /:year/:month/:day/:title 50 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /_includes/about.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 |
7 |
8 | {{site.nick_name}}({{site.english_name}}) 9 |
10 |
11 |

一个的爱码士

12 |
13 |
14 |

15 | 心中本没有路,用双手敲写康庄大道。 16 |

17 |

18 | 知之甚少,学之甚多,生命不休,求索不止。 19 |

20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /_includes/categories.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {% for cat in site.categories %} 4 | {% capture test %}{{cat[0] | slice: 0}}{% endcapture %} 5 | {% capture testup %}{{cat[0] | slice: 0 | upcase}}{% endcapture %} 6 |
{{cat[0]}}
7 | {% endfor %} 8 |
9 |
10 |
11 | {% for cat in site.categories %} 12 | {% capture test %}{{cat[0] | slice: 0}}{% endcapture %} 13 | {% capture testup %}{{cat[0] | slice: 0 | upcase}}{% endcapture %} 14 |

{{cat[0]}}

15 | 25 | {% endfor %} 26 |
27 |
-------------------------------------------------------------------------------- /_includes/comment.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 | 6 | 17 | -------------------------------------------------------------------------------- /_includes/contact.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
微信:
4 |
5 | 6 |
7 |
8 |
9 | 10 |
11 |
QQ:
12 | 2386209384 13 |
14 |
15 | 16 |
17 |
邮箱:
18 | 21 |
22 |
23 | 24 |
25 |
留言:
26 | 留言板 27 |
28 |
29 | 30 |
    31 |
  • 32 |
    33 | 赞赏 34 | favorite 35 |
    36 | 37 |
    38 |
    39 | 微信支付 40 |
    41 |
    42 |
  • 43 |
44 |
45 | -------------------------------------------------------------------------------- /_includes/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 66 | 67 | {% for js in layout.js %} 68 | {% if js contains "//" %} 69 | {% if jekyll.environment == 'production' %} 70 | 71 | {% else %} 72 | 73 | {% endif %} 74 | {% else %} 75 | 76 | {% endif %} 77 | {% endfor %} 78 | 79 | {% for js in page.js %} 80 | {% if js contains "//" %} 81 | {% if jekyll.environment == 'production' %} 82 | 83 | {% else %} 84 | 85 | {% endif %} 86 | {% else %} 87 | 88 | {% endif %} 89 | {% endfor %} 90 | 91 | 92 | {% if jekyll.environment == 'production' %} 93 | 94 | 95 | 96 | 105 | 106 | 107 | 108 | 121 | 122 | 130 | 131 | 132 | 138 | {% endif %} 139 | 140 | 141 | -------------------------------------------------------------------------------- /_includes/projects.html: -------------------------------------------------------------------------------- 1 | {% if site.github.public_repositories %} 2 | {% assign sorted_repos = (site.github.public_repositories | sort: 'updated_at') | reverse %} 3 |
4 | 9 |
10 | 11 | {% for repo in sorted_repos %} 12 |
13 |
14 |
15 | more_vert 16 | {{repo.name}} 17 |
18 |
19 | {{repo.description}} 20 |
21 |
22 |
23 | Statisticsclose 24 | 25 | 26 | star 27 | {{repo.stargazers_count}} 28 | 29 | 30 | call_split 31 | {{repo.forks_count}} 32 | 33 | 34 | access_time 35 | 36 | 37 |
38 |
39 |
40 |
41 | {% endfor %} 42 | {% endif %} -------------------------------------------------------------------------------- /_includes/tags.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {% for tag in site.tags %} 4 | {% capture test %}{{tag[0] | slice: 0}}{% endcapture %} 5 | {% capture testup %}{{tag[0] | slice: 0 | upcase}}{% endcapture %} 6 |
{{tag[0]}}
7 | {% endfor %} 8 |
9 |
10 |
11 | {% for tag in site.tags %} 12 | {% capture test %}{{tag[0] | slice: 0}}{% endcapture %} 13 | {% capture testup %}{{tag[0] | slice: 0 | upcase}}{% endcapture %} 14 |

{{tag[0]}}

15 | 25 | {% endfor %} 26 |
27 |
-------------------------------------------------------------------------------- /_includes/tools.html: -------------------------------------------------------------------------------- 1 | {% if site.github.public_repositories %} 2 | {% assign sorted_repos = (site.github.public_repositories | sort: 'pushed_at') | reverse %} 3 | 4 | {% for repo in sorted_repos %} 5 | {% if repo.homepage != nil and repo.homepage != '' and repo.fork == false %} 6 |
7 |
8 | 19 |
20 | {{repo.description}} 21 |
22 |
23 |
24 | {% endif %} 25 | {% endfor %} 26 | 27 | {% endif %} -------------------------------------------------------------------------------- /_layouts/page.html: -------------------------------------------------------------------------------- 1 | --- 2 | css: [ 3 | "page.css" 4 | ] 5 | js: [ 6 | "materialize.min.js", 7 | "particles.min.js", 8 | "main.min.js", 9 | "search.min.js" 10 | ] 11 | --- 12 | 13 | {% include header.html %} 14 | 15 |
16 |
17 |

{{page.title}}

18 |
19 |
20 | {{ content }} 21 |
22 |
23 | 24 | {% include footer.html %} -------------------------------------------------------------------------------- /_layouts/post.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | css: [ 4 | "page.css", 5 | "post.css", 6 | "syntax.css", 7 | "article-category.css" 8 | ] 9 | js: [ 10 | "materialize.min.js", 11 | "post.min.js", 12 | "particles.min.js", 13 | "main.min.js", 14 | "search.min.js", 15 | "gen-category.min.js" 16 | ] 17 | --- 18 |
19 |
    20 |
  • 21 |
    22 | 23 | date_range 24 | {{page.date | date: "%d/%m/%Y %H:%M"}}
    25 |
    点击量:
    26 | info 28 |
    29 |
    30 |
    31 | 32 | sort 33 | {% for cat in page.categories %} 34 | {% capture test %}{{cat | slice: 0}}{% endcapture %} 35 | {% capture testup %}{{cat | slice: 0 | upcase}}{% endcapture %} 36 | 38 |
    {{cat}}
    39 |
    40 | {% endfor %} 41 |
    42 | 43 | label 44 | {% for tag in page.tags %} 45 | {% capture test %}{{tag | slice: 0}}{% endcapture %} 46 | {% capture testup %}{{tag | slice: 0 | upcase}}{% endcapture %} 47 | 48 |
    {{tag}}
    49 |
    50 | {% endfor %} 51 |
    52 |
    53 |
  • 54 |
55 |
56 |
57 |
58 |
59 | {{ content }} 60 |
61 |
62 |
63 | 64 | 65 |

评论:

66 | {% include comment.html %} 67 | 68 | 69 |
70 |

技术文章推送

71 |

手机、电脑实用软件分享

72 | 微信搜索公众号: 程序骑士 73 |
74 | wechat 75 | 微信公众号:程序骑士 76 |
77 |
78 | 79 | {% if jekyll.environment == 'production' %} 80 | 93 | {% endif %} 94 | -------------------------------------------------------------------------------- /_posts/2018-03-27-Markdown-tutorial.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown 简明教程 3 | layout: post 4 | categories: 编程 5 | tags: markdown 6 | excerpt: 简要 markdown 语法 7 | --- 8 | 9 | ## Markdown 及扩展 10 | 11 | > Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面。 —— [ 维基百科 ] 12 | 13 | 使用简单的符号标识不同的标题,将某些文字标记为**粗体**或者*斜体*,创建一个[链接](http://www.csdn.net)等,详细语法参考帮助?。 14 | 15 | 本编辑器支持 **Markdown Extra** ,  扩展了很多好用的功能。具体请参考[Github][2]. 16 | 17 | ### 表格 18 | 19 | **Markdown Extra** 表格语法: 20 | 21 | 项目 | 价格 22 | ---------|------ 23 | Computer | $1600 24 | Phone | $12 25 | Pipe | $1 26 | 27 | 写法: 28 | ```markdown 29 | 项目 | 价格 30 | ---------|------ 31 | Computer | $1600 32 | Phone | $12 33 | Pipe | $1 34 | ``` 35 | 36 | 可以使用冒号来定义对齐方式: 37 | 38 | | 项目 | 价格 | 数量 | 39 | |:--------- |--------:|:----:| 40 | | Computer | 1600 元 | 5 | 41 | | Phone | 12 元 | 12 | 42 | | Pipe | 1 元 | 234 | 43 | 44 | 写法: 45 | ```markdown 46 | | 项目 | 价格 | 数量 | 47 | |:--------- |--------:|:----:| 48 | | Computer | 1600 元 | 5 | 49 | | Phone | 12 元 | 12 | 50 | | Pipe | 1 元 | 234 | 51 | ``` 52 | 53 | ### 插入图片 54 | > 格式一: 55 | 56 | ``` markdown 57 | ![picture-name](http://xxx.com/xxx.png) 58 | ``` 59 | 60 | > 格式二:(方便设置图片尺寸) 61 | 62 | ``` html 63 | download-failed 64 | ``` 65 | 66 | ### 定义列表 67 | 68 | **Markdown Extra** 定义列表语法: 69 | - 项目1 70 | - 项目2 71 | - 定义 A 72 | - 定义 a 73 | - 定义 B 74 | 75 | 项目3 76 | : 定义 C 77 | 78 | : 定义 D 79 | 80 | > 定义 E 81 | 82 | 写法: 83 | ```markdown 84 | - 项目1 85 | - 项目2 86 | - 定义 A 87 | - 定义 a 88 | - 定义 B 89 | 90 | 项目3 91 | : 定义 C 92 | 93 | : 定义 D 94 | 95 | > 定义 E 96 | ``` 97 | 98 | ### 代码块 99 | 代码块语法遵循标准markdown代码,例如: 100 | > python: 101 | 102 | ```python 103 | @requires_authorization 104 | def somefunc(param1='', param2=0): 105 | '''A docstring''' 106 | if param1 > param2: # interesting 107 | print 'Greater' 108 | return (param2 - param1 + 1) or None 109 | class SomeClass: 110 | pass 111 | >>> message = '''interpreter 112 | ... prompt''' 113 | ``` 114 | 115 | > c语言: 116 | 117 | ```c 118 | #include 119 | int main() 120 | { 121 | printf("Hello world!"); 122 | } 123 | ``` 124 | 125 | ### 脚注 126 | 127 | 生成一个脚注[^footnote]. 128 | [^footnote]: 这里是 **脚注** 的 *内容*. 129 | 130 | 写法: 131 | ```markdown 132 | 生成一个脚注[^footnote]. 133 | [^footnote]: 这里是 **脚注** 的 *内容*. 134 | ``` 135 | 136 | ### 数学公式 137 | 138 | 使用 MathJax 渲染 *LaTex* 数学公式,详见 [math.stackexchange.com][1]. 139 | 140 | #### 行内公式 141 | 142 | 数学公式为:$ \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N $。 143 | 144 | 写法: 145 | ```markdown 146 | 数学公式为:$ \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N $。 147 | ``` 148 | 149 | #### 块级公式: 150 | 151 | $$ x = \dfrac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$ 152 | 153 | 写法: 154 | ```markdown 155 | $$ x = \dfrac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$ 156 | ``` 157 | 158 | 更多LaTex语法请参考 [这里][3]. 159 | 160 | ## 浏览器兼容 161 | 162 | 1. 目前,本编辑器对 **Chrome** 浏览器支持最为完整。建议大家使用较新版本的 Chrome。 163 | 3. **IE9** 以下不支持 164 | 4. **IE9,10,11** 存在以下问题 165 | 1. 不支持离线功能 166 | 1. IE9 不支持文件导入导出 167 | 1. IE10 不支持拖拽文件导入 168 | 169 | ## 常用 Markdown 编辑器推荐 170 | 171 | 1. **Markdownpad**: 详情请点击 [官网](http://markdownpad.com/)。 172 | (貌似专业版需要收取一定dollars$,需要序列号自行baidu。) 173 | 2. **Markpad**:详情前往 [官网](http://markpad.fluid.impa.br/)。 174 | (推荐使用,Microsoft Store也有,完全免费,支持及时效果浏览。) 175 | 3. **CSDN博客编辑器**:CSDN网站内置编辑器。(这篇文件就是这样写出来的-_-) 176 | 177 | 4. **Harropad**: [官网](http://pad.haroopress.com/user.html) 178 | 179 | 5. **Retext**: 简单强大的文本编辑器,可控制输出格式:pdf, html等,仅支持Linux(推荐).[下载](https://github.com/retext-project/retext) 180 | 181 | [1]: http://math.stackexchange.com/ 182 | [2]: https://github.com/jmcmanus/pagedown-extra "Pagedown Extra" 183 | [3]: http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference 184 | [4]: http://bramp.github.io/js-sequence-diagrams/ 185 | [5]: http://adrai.github.io/flowchart.js/ 186 | [6]: https://github.com/benweet/stackedit -------------------------------------------------------------------------------- /_posts/2018-03-30-c-leap-year.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: C 语言统计闰年 3 | layout: post 4 | categories: C语言 5 | tags: C语言 6 | excerpt: 源码及运行结果 7 | --- 8 | ## 源码如下: 9 | 10 | ```c 11 | #include 12 | int main() 13 | { 14 | // 统计1-2020的闰年 15 | printf("1-2020的闰年: \n\n"); 16 | int ye, c = 0; 17 | for (ye = 1; ye <= 2020; ye++) //此处也可更改为指定年份区间 18 | { 19 | if (((ye % 4 == 0) && (ye % 100 != 0)) || (ye % 400 == 0)) //闰年的定义:能被4整除但不能被100整除,或能被400整除的年份 20 | { 21 | printf("%d ", ye); 22 | c++; 23 | } 24 | } 25 | printf("\n\nTotal: %d\n", c); //用定义的变量c统计 26 | } 27 | ``` 28 | 29 | ## 运行结果: 30 | 31 | ```txt 32 | 1-2020的闰年: 33 | 34 | 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 104 35 | 108 112 116 120 124 128 132 136 140 144 148 152 156 160 164 168 172 176 36 | 180 184 188 192 196 204 208 212 216 220 224 228 232 236 240 244 248 252 37 | 256 260 264 268 272 276 280 284 288 292 296 304 308 312 316 320 324 328 38 | 332 336 340 344 348 352 356 360 364 368 372 376 380 384 388 392 396 400 39 | 404 408 412 416 420 424 428 432 436 440 444 448 452 456 460 464 468 472 40 | 476 480 484 488 492 496 504 508 512 516 520 524 528 532 536 540 544 548 41 | 552 556 560 564 568 572 576 580 584 588 592 596 604 608 612 616 620 624 42 | 628 632 636 640 644 648 652 656 660 664 668 672 676 680 684 688 692 696 43 | 704 708 712 716 720 724 728 732 736 740 744 748 752 756 760 764 768 772 44 | 776 780 784 788 792 796 800 804 808 812 816 820 824 828 832 836 840 844 45 | 848 852 856 860 864 868 872 876 880 884 888 892 896 904 908 912 916 920 46 | 924 928 932 936 940 944 948 952 956 960 964 968 972 976 980 984 988 992 47 | 996 1004 1008 1012 1016 1020 1024 1028 1032 1036 1040 1044 1048 1052 48 | 1056 1060 1064 1068 1072 1076 1080 1084 1088 1092 1096 1104 1108 1112 49 | 1116 1120 1124 1128 1132 1136 1140 1144 1148 1152 1156 1160 1164 1168 50 | 1172 1176 1180 1184 1188 1192 1196 1200 1204 1208 1212 1216 1220 1224 51 | 1228 1232 1236 1240 1244 1248 1252 1256 1260 1264 1268 1272 1276 1280 52 | 1284 1288 1292 1296 1304 1308 1312 1316 1320 1324 1328 1332 1336 1340 53 | 1344 1348 1352 1356 1360 1364 1368 1372 1376 1380 1384 1388 1392 1396 54 | 1404 1408 1412 1416 1420 1424 1428 1432 1436 1440 1444 1448 1452 1456 55 | 1460 1464 1468 1472 1476 1480 1484 1488 1492 1496 1504 1508 1512 1516 56 | 1520 1524 1528 1532 1536 1540 1544 1548 1552 1556 1560 1564 1568 1572 57 | 1576 1580 1584 1588 1592 1596 1600 1604 1608 1612 1616 1620 1624 1628 58 | 1632 1636 1640 1644 1648 1652 1656 1660 1664 1668 1672 1676 1680 1684 59 | 1688 1692 1696 1704 1708 1712 1716 1720 1724 1728 1732 1736 1740 1744 60 | 1748 1752 1756 1760 1764 1768 1772 1776 1780 1784 1788 1792 1796 1804 61 | 1808 1812 1816 1820 1824 1828 1832 1836 1840 1844 1848 1852 1856 1860 62 | 1864 1868 1872 1876 1880 1884 1888 1892 1896 1904 1908 1912 1916 1920 63 | 1924 1928 1932 1936 1940 1944 1948 1952 1956 1960 1964 1968 1972 1976 64 | 1980 1984 1988 1992 1996 2000 2004 2008 2012 2016 2020 65 | 66 | Total: 490 67 | ``` -------------------------------------------------------------------------------- /_posts/2018-03-30-c-multiply-table.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: C 语言打印九九乘法表 3 | layout: post 4 | categories: C语言 5 | tags: C语言 6 | excerpt: 源码及运行结果 7 | --- 8 | ## 源码如下: 9 | 10 | ```c 11 | #include 12 | int main() 13 | { 14 | //打印九九乘法表 15 | printf("九九乘法表:\n"); 16 | int x, y; //初始化打印的两个方向 17 | for (y = 1; y < 10; y++) //两层循环嵌套打印输出 18 | { 19 | for (x = 1; x <= y; x++) 20 | { 21 | printf("%d*%d=%2d ", y, x, x * y); //%2d表示固定输出两位 22 | } 23 | printf("\n"); //打印到行尾,换行 24 | } 25 | printf("This is the end.\n"); 26 | } 27 | ``` 28 | 29 | ## 输出结果: 30 | 31 | ```txt 32 | 九九乘法表: 33 | 1*1= 1 34 | 2*1= 2 2*2= 4 35 | 3*1= 3 3*2= 6 3*3= 9 36 | 4*1= 4 4*2= 8 4*3=12 4*4=16 37 | 5*1= 5 5*2=10 5*3=15 5*4=20 5*5=25 38 | 6*1= 6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 39 | 7*1= 7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 40 | 8*1= 8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 41 | 9*1= 9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 42 | This is the end. 43 | ``` 44 | 45 | ## 注意: 46 | 47 | 代码注释处说明的`%2d`是为了美观,强行使相乘的结果占两个字符位,否则打印结果如下: 48 | 49 | ```txt 50 | 九九乘法表: 51 | 1*1=1 52 | 2*1=2 2*2=4 53 | 3*1=3 3*2=6 3*3=9 54 | 4*1=4 4*2=8 4*3=12 4*4=16 55 | 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 56 | 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 57 | 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 58 | 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 59 | 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 60 | This is the end. 61 | ``` 62 | 63 | 没有上面美观吧-_- 64 | -------------------------------------------------------------------------------- /_posts/2018-03-30-c-prime-number.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: C 语言统计素数 3 | layout: post 4 | categories: C语言 5 | tags: C语言 6 | excerpt: 源码及运行结果 7 | --- 8 | ## 源码如下: 9 | 10 | ```c 11 | #include 12 | int main() 13 | { 14 | // 1-1000的素数 15 | printf("1-1000的素数: \n\n"); 16 | int i, j, co = 0; //设置co用于统计个数 17 | for (j = 1; j <= 1000; j++) //遍历1-1000 18 | { 19 | for (i = 2; i < j; i++) //素数条件:只能被1和自身整除 20 | { 21 | if (j % i == 0) //发现不是素数,则跳出本层循环 22 | { 23 | break; 24 | } 25 | } 26 | if (i == j) //遍历后,没有除1和自身以外的因数,i==j 表示遍历了 2--自身的所有数并且未发现因数 27 | { 28 | printf("%d ", j); 29 | co++; 30 | } 31 | } 32 | printf("\nTotal: %d\n\n", co); 33 | } 34 | ``` 35 | 36 | ## 运行结果: 37 | 38 | ```txt 39 | 1-1000的素数: 40 | 41 | 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 42 | 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 43 | 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 44 | 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 45 | 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 46 | 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 47 | 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 48 | 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 49 | 941 947 953 967 971 977 983 991 997 50 | 51 | total: 168 52 | ``` 53 | 54 | ## 注意 55 | 56 | 素数,又称质数,即整数在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数。将1-1000中每个数都对“2--自身”进行整除,`i==j` 说明是对“2--自身”都遍历了一遍并且未发现符合条件的数,而不是前面发现有多余因数的`break;` 57 | 58 | >#### 另一个优化的版本,供参考: 59 | 60 | ```c 61 | #include 62 | #include 63 | int main() 64 | { 65 | // 1-1000的素数 66 | printf("1-1000的素数: \n\n"); 67 | int i, j, co = 0; 68 | printf("2 "); 69 | for (j = 3; j <= 1000; j+=2) //不遍历偶数,除了2偶数都不是质数 70 | { 71 | for (i = 2; i <= sqrt(j); i++) //实际遍历到此数的平方根就够了,需要引入 头文件 72 | { 73 | if (j % i == 0) 74 | { 75 | break; 76 | } 77 | } 78 | if (i > sqrt(j)) //这里也要变一下 79 | { 80 | printf("%d ", j); 81 | co++; 82 | } 83 | } 84 | printf("\n\ntotal: %d\n\n", co+1); //注意这里要加上“2”这个数,2是质数也是偶数,之前没有遍历 85 | } 86 | ``` 87 | 这样就大大缩短了时间。 -------------------------------------------------------------------------------- /_posts/2018-04-04-negative-binary.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 十进制负数的二进制表示法 3 | layout: post 4 | categories: 编程 5 | excerpt: 十进制负数转换为二进制 6 | tags: 负数二进制 7 | --- 8 | 十进制转正整数转二进制应该都会,用C语言代码简单表示算法: 9 | ``` c 10 | #include 11 | int main() 12 | { 13 | int dec=65535; /*positive decimalism number to binary number*/ 14 | int bin[32]; 15 | int i=0, j; 16 | while (dec>1) 17 | { 18 | bin[i]=dec%2; 19 | dec/=2; 20 | i++; 21 | } 22 | bin[i]=dec; 23 | for (j=i; j>=0; j--) /*print binary number*/ 24 | { 25 | printf("%d",bin[j]); 26 | } 27 | printf("\n"); 28 | } 29 | ``` 30 | 当然也有另外一种简单转换方法: 31 | ``` c 32 | #include 33 | int main() 34 | { 35 | int dec=65535; 36 | char bin[32]; 37 | itoa(dec,bin,2); /*整型转换为字符串的函数,第一个参数是整型变量, 38 | 第二个是字符数组,用于存放字符串,第三个是进制,“2” 表示输出的字符串的进制格式, 39 | 可以这样记函数:“int to arr” */ 40 | printf("%s\n", bin); 41 | } 42 | ``` 43 | 但是,十进制负整数转换为二进制稍微复杂一些,分为三步: 44 | # 一、原码 45 | 例如一个十进制数 5,二进制原码表示为: 46 | 47 | `00000000 00000000 00000000 00000101` 48 | 49 | 大小为 4 字节,每一个 `0` 或 `1` 表示一个比特位(bit),所以八位为一字节,好像32位和64位系统都这样。一字节用十进制整数表示大小则是:2的8次方(256)。 50 | 表示为十六进制是这样:`ff ff ff ff`(f=2^4-1) 51 | # 二、反码 52 | 将二进制原码每一位取反,就是 `0` 变 `1` ,`1` 变 `0`。 53 | 上面 5 的反码表示为这样: 54 | 55 | `11111111 11111111 11111111 11111010` 56 | # 三、补码 57 | 将反码最低位加 `1` 叫做补码,那么 5 的补码表示为: 58 | 59 | `11111111 11111111 11111111 11111011` 60 | 61 | **注意反码末位是 `1` 时记得进位。** 62 | 63 | 所以十进制数 `-5` 的二进制表示为: 64 | 65 | `11111111 11111111 11111111 11111011` 66 | 67 | 所以 -1 在计算机中表示为全 `1`,就是: 68 | 69 | `11111111 11111111 11111111 11111111` 70 | 71 | 我64位计算机中是这样的: 72 | 73 | ![20180404111248861.jpg](https://i.loli.net/2018/04/15/5ad3575f46acf.jpg) -------------------------------------------------------------------------------- /_posts/2018-04-06-bit-operation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 位运算符与位运算 3 | layout: post 4 | excerpt: 编程中位运算的介绍与应用 5 | categories: 编程 6 | tags: 位运算 按位运算 7 | --- 8 | # 目录 9 | 10 | * [概述](#1) 11 | * [按位与](#2) 12 | * [按位或](#3) 13 | * [按位异或](#4) 14 | * [简单应用](#4.1) 15 | * [交换变量值](#4.1.1) 16 | * [简单加密](#4.1.2) 17 | * [按位取反](#5) 18 | * [移位运算](#6) 19 | * [左移位](#6.1) 20 | * [右移位](#6.2) 21 | * [复合赋值符](#7) 22 | 23 | # 一、概述 24 | 程序中的所有数在计算机内存中都是以二进制的形式储存的。除了常见的**算术运算符**:`+ - * / %`,还有**位运算**:`& | ^ ~ >> <<`,就是直接对整数在内存中的二进制位进行操作。接下来以C语言为例介绍,其它语言大同小异。 25 | 26 | # 二、按位与(&) 27 | 又叫 `and` 运算,用符号 `&` 表示,计算方式如下: 28 | 29 | `1 & 1 = 1` , `0 & 1 = 0` , ` 0 & 0 = 0` 30 | 31 | 布尔类型中,`1` 表示真,`0` 表示假,所以可以用高中数学那句话来记:**`同真为真,一假为假`**。 32 | 33 | 举个例子:`3 & 5 = 1` ,运算过程如下: 34 |
 35 |    0 1 1   ---> 3
 36 |  & 1 0 1   ---> 5
 37 |   --------
 38 |    0 0 1   ---> 1
 39 | 
40 | 41 | # 三、按位或 (|) 42 | 又叫 `or` 运算,用符号 `|` 表示,运算方式: 43 | 44 | `1 | 1 = 1` , `1 | 0 = 1` , `0 | 0 = 0` 45 | 46 | 记为:**`一真为真,同假为假`** 47 | 48 | 举例:`3 | 5 = 7` , 运算过程: 49 |
 50 |    0 1 1   ---> 3
 51 |  | 1 0 1   ---> 5
 52 |  --------
 53 |    1 1 1   ---> 7
 54 | 
55 | 56 | # 四、按位异或(^) 57 | 58 | 又叫 `xor` 运算,用符号 `^` 表示,注意这里不是数学表达里面的**次方**的意思,运算方式: 59 | 60 | `1 ^ 1 = 0` , ` 1 ^ 0 = 1` , `0 ^ 0 = 0` 61 | 62 | 这种运算也较为特殊,记为:**`同为假,异为真`** 63 | 举例:`3 ^ 5 = 6` , 运算过程: 64 |
 65 |    0 1 1    ---> 3
 66 |  ^ 1 0 1    ---> 5
 67 |  ---------
 68 |    1 1 0    ---> 6
 69 | 
70 | 71 | ## 简单应用 72 | 73 | ### 1、交换变量值 74 | 75 | 异或运算有如下特性: 76 | 77 | `a ^ b ^a = b` , `a ^ b ^ b =a` 78 | 79 | 因此可以用于程序中的变量值交换,C语言中,我们可能经常这样交换变量值: 80 | ``` c 81 | #include 82 | int main() 83 | { 84 | int a = 3, b = 5; 85 | int temp; /*定义一个临时变量用于交换方便*/ 86 | temp = a; 87 | a = b; 88 | b = temp; 89 | printf("a = %d, b = %d", a, b); /*输出结果为:a = 5, b = 3 实现了变量值的交换*/ 90 | } 91 | ``` 92 | 但是以后我们可以这样实现: 93 | ``` c 94 | #include 95 | int main() 96 | { 97 | int a = 3, b = 5; 98 | a ^= b; /*等同于:a = a ^ b 之后会讲*/ 99 | b = a ^ b; /*这时 a ^ b 等于 原来 a 的值*/ 100 | a ^= b; /*a = a ^ b*/ 101 | printf("a = %d, b = %d", a, b); 102 | } 103 | ``` 104 | >**a, b 为负数时同样适用,但位运算只适用于整型,浮点数不可用** 105 | 106 | ### 2、简单加密 107 | 108 | 例如,你想传输一条信息给Ta,信息为:`5201314` ,密码为:`1998` ,使用如下代码加密: 109 | 110 | 5201314 ^ 1998 111 | 112 | 结果为 `5200492`,想要查看原信息,使用密码查看: 113 | 114 | 5200492 ^ 1998 115 | 这样就生成了原数字:`5201314`. 116 | 117 | # 五、按位取反(~) 118 | 又叫 `not` 运算,即将二进制位中 `0` 和 `1` 全部取反,运算方式为: 119 | 120 | `~ 1 = 0` , `~ 0 = 1` 121 | 122 | 记为:**`0 变 1,1 变 0`** 123 | 124 | 举例:`~5 = -6`, 运算过程: 125 |
126 |  ~ 00000000 00000000 00000000 00000101   ---> 5
127 |  ---------------------------------------
128 |    11111111 11111111 11111111 11111010   ---> -6
129 | 
130 | >**注意变量如果定义是无符号短整型 `unsigned short` , `~5` 将不再是 `-6` ,而是 `65530`**。 131 | >**还有一个规律是正整数取反后结果是原数加一后取相反数,负数一样**。 132 | >**还要注意不要和逻辑运算符 `!` 搞混,`! 1 = 0` , `! 1234 = 0` , `! 0 = 1`**,即只有 `真(1)` 与`假(0)` 两种。 133 | 134 | # 六、移位运算 135 | 顾名思义,移位即将数据的二进制数进行向左或向右平移一定的位数,然后得到新的数据,移位分为左移位和右移位。 136 | ## 1、左移位(<<) 137 | 将数据的转换为二进制,所有位向左平移,高位(左端)舍弃,低位(右端)空位补 `0`,格式为: 138 | 139 | `需要移位的数据 << 需要移动的位数` 140 | 141 | 举例:`5 << 2 =20` ,运算过程: 142 | 143 |
144 |   00000000 00000000 00000000 00000101   ---> 5
145 |  -------------------------------------
146 |   00000000 00000000 00000000 00010100   ---> 20
147 | 
148 | >**右移位的数学意义是,原数左移 n 位,相当于原数乘以 2 的 n 次方** 149 | 150 | ## 2、右移位 151 | 将数据的二进制所有位向右移位,低位舍弃,高位补 `0`(负数补 `1`),格式: 152 | 153 | `需要移位的数据 >> 需要移动的位数` 154 | 155 | 举例:`5 >> 2 = 1`,运算过程: 156 |
157 |   00000000 00000000 00000000 00000101   ---> 5
158 |  -------------------------------------
159 |   00000000 00000000 00000000 00000001   --->  1
160 | 
161 | 负数情况:`-6 >> 2 = -2`,运算过程: 162 |
163 |   11111111 11111111 11111111 11111010    ---> -6
164 |  -------------------------------------
165 |   11111111 11111111 11111111 11111110    ---> -2
166 | 
167 | >**右移位的数学意义是,相当于原数除以 2 的 n 次方** 168 | 169 | # 七、复合赋值符 170 | 171 | 算术运算中有复合赋值符:`+= -+ *= /= %=`,位运算也有对应的复合赋值:`&= |= ^= >>= <<= `(注意没有 `~=` ),运算一样: 172 | 173 | `a &= b` 等价于 `a = a & b` 174 | 175 | 以此类推 176 | 177 | ----------------------------------------------------------------------------- 178 | # 返回[顶部](#home) -------------------------------------------------------------------------------- /_posts/2018-04-06-recursion-factorial.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 递归函数之阶乘的实现 3 | layout: post 4 | tags: 递归函数 阶乘 5 | categories: 编程 6 | excerpt: 用递归函数实现阶乘函数算法 7 | --- 8 | # 定义 9 | 在编程中函数有一个神奇又难理解的功能,就是递归。递归就是在一个过程中要调用上一步或上几步的结果,使用递归过程的函数就叫递归函数。简单说就是函数自身调用自身(听着有点反自然,像自己举起自己)。 10 | 11 | # 递归实例 12 | 13 | 除了数学的复杂运算中,生活中也有不少递归的实例: 14 | 15 | ## 德罗斯特效应 16 | 德罗斯特效应(Droste effect)是递归的一种视觉形式,即一张图片中的某部分与整张图片相同,如下: 17 | ![20180406205325252.jpg](https://i.loli.net/2018/04/15/5ad3565ad7935.jpg) 18 | 19 | ------------------- 20 | ![20180406205355939.jpg](https://i.loli.net/2018/04/15/5ad3565b03bca.jpg) 21 | 22 | -------------------- 23 | ![20180406205418499.jpg](https://i.loli.net/2018/04/15/5ad3565b0245f.jpg) 24 | 25 | ------------------------ 26 | >别晕、别晕 -_- 27 | 28 | 或者在自己身前和身后都放一面镜子,深刻体会一会儿 ▄︻┻┳══━一 29 | 30 | # 递归实现 31 | 32 | 接下来就用C语言递归函数来实现阶乘功能,源码如下: 33 | ``` c 34 | #include 35 | int factorial(int n) /*外部定义阶乘函数*/ 36 | { 37 | int m; 38 | if (n < 0) /*注意要给函数设置一个递归结束条件*/ 39 | { 40 | printf("输入错误!"); 41 | return 0; 42 | } 43 | else if (n == 1) 44 | { 45 | m = 1; 46 | } 47 | else 48 | { 49 | m = n * factorial(n-1); /*调用函数factorial()自身*/ 50 | } 51 | return m; 52 | } 53 | int main() 54 | { 55 | printf("%d", factorial(5)); 56 | 57 | } 58 | ``` 59 | 这是程序大概的运算过程: 60 | ![20180406220517224.jpg](https://i.loli.net/2018/04/15/5ad3565b00bba.jpg) 61 | 62 | ----------------------------- 63 | >**这里要注意给函数设置一个递归结束条件,可以是 if 判断句,不然函数就无限调用自身下去了,你之前看着镜子中的镜子中的……自己都晕,程序自然是崩溃了** -------------------------------------------------------------------------------- /_posts/2018-04-10-c-self-plus.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: C 语言自增自减运算辨析 3 | layout: post 4 | categories: C语言 5 | tags: C语言 自增运算 自减运算 6 | excerpt: C语言自增与自减运算辨析 7 | --- 8 | c语言中,自增(++)和自减(--)运算是很有c语言“感觉”的一种运算符,但是在实际编写中,尤其对初学者或者很久没接触它的,会对它的原理和运算结果产生混淆,接下来做详细辨析。 9 | 10 | # 自增运算(++) 11 | 12 | 语法为:`a++`,其结果与:`a = a + 1` 一样,也和:`a += 1` 一样,作用很明显,方便阅读,减小代码量。例如下面的例子,就能看出明显的效果了: 13 | ``` c 14 | ((3+a)*sqrt(3)/(a%2))=((3+a)*sqrt(3)/(a%2))+1; 15 | 16 | /*简化后*/ 17 | ((3+a)*sqrt(3)/(a%2))++; 18 | ``` 19 | 20 | ## 辨析 21 | 22 | 自增也可以表示为 `++a`, **它们都能把a 的值加 1**,但是两个**表达式的值**却不同,用一个例子说明: 23 | ``` c 24 | #include 25 | int main() 26 | { 27 | int a = 1, b = 1, a2, b2; 28 | a2 = a++; 29 | b2 = ++b; 30 | printf("a = %d, b = %d, a2 = %d, b2 = %d", a, b, a2, b2); 31 | } 32 | ``` 33 | 输出结果为: 34 | ``` 35 | a = 2, b = 2, a2 = 1, b2 = 2 36 | ``` 37 | 其实,`a++` 的值为 `a` 本身,`++a` 的值为 `a+1` 后的值。 38 | 39 | >**也可以按教科书那种记:** 40 | >>**`b = a++` 是先赋值后运算,即先 `b=a`,然后 `a++`。** 41 | >>**`b = ++a` 是先运算后赋值,即先 `++a`,然后 `++a`。** 42 | 43 | # 自减运算 44 | 45 | 自减运算原理和辨析与上面自增运算相似,`a--` 等于 `a = a -1` ,表达式 `a--` 的值为 `a` ,表达式 `--a` 的值为 `a-1`。 -------------------------------------------------------------------------------- /_posts/2018-04-21-linux-sources-list.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kali Linux 之软件安装、卸载、更新和修改更新源 3 | layout: post 4 | categories: Exploit 5 | tags: Linux安装软件 Linux更新源 6 | excerpt: Linux 系统软件安装、卸载、更新与修改更新源 7 | --- 8 | 使用Linux系统,与Windows系统一样,也需要及时进行软件与系统的更新。 9 | 10 | ## 软件 11 | 12 | 这里以 [Kali Linux][kali] 系统为例,介绍常用的软件安装、卸载与更新命令: 13 | 14 | ## 软件安装 15 | 16 | 安装前先搜索一下更新源中是否有该软件,这里使用 `apt` 命令,貌似比另外一个类似的命令 `apt-get` 友好一些。 17 | 18 | 例如安装 `leafpad` 这个软件: 19 | 20 | apt search leafpad 21 | 22 | 然后安装这个软件: 23 | 24 | apt install leafpad 25 | 26 | 然后确定安装就行了。 27 | 28 | > 有时会出现一些 `failed` 可以按照提示使用命令 `apt install --fix-missing` 修复。 29 | 30 | ## 软件卸载 31 | 32 | 简单卸载软件: 33 | 34 | apt remove leafpad 35 | 36 | 卸载软件并移除配置文件: 37 | 38 | apt-get purge leafpad 39 | 40 | 卸载自动安装并且未使用的软件 41 | 42 | apt autoremove 43 | 44 | ## 软件更新 45 | 46 | 先更新一下源: 47 | 48 | apt update 49 | 50 | > 这个操作并没有开始更新软件,类似于将远程源中的最新版本信息更新到本地 51 | 52 | 接下来才开始更新软件: 53 | 54 | apt upgrade 55 | 56 | 更新系统: 57 | 58 | apt full-upgrade 59 | 60 | 或者: 61 | 62 | apt-get dist-upgrade 63 | 64 | 清理安装包: 65 | 66 | apt-get clean 67 | apt-get autoclean 68 | 69 | ## 更新源 70 | 71 | Linux 更新源文件位于 `/etc/apt/sources.list` ,系统就是从这个文件中读取一些网址参数下载安装软件,默认的是 kali 官方源,我们可以修改为国内一些较快的源,例如阿里、中科大、网易等,加快下载速度。 72 | 73 | 找到并编辑上述 `sources.list` 源文件,替换为以下内容: 74 | ```sh 75 | #aliyun 阿里云 76 | deb http://mirrors.aliyun.com/kali kali-rolling main non-free contrib 77 | deb-src http://mirrors.aliyun.com/kali kali-rolling main non-free contrib 78 | 79 | # ustc 中科大 80 | deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib 81 | deb-src http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib 82 | #deb http://mirrors.ustc.edu.cn/kali-security kali-current/updates main contrib non-free 83 | #deb-src http://mirrors.ustc.edu.cn/kali-security kali-current/updates main contrib non-free 84 | 85 | # kali 官方源 86 | deb http://http.kali.org/kali kali-rolling main non-free contrib 87 | deb-src http://http.kali.org/kali kali-rolling main non-free contrib 88 | 89 | # 默认的,可以注释掉不用管 90 | #deb http://security.kali.org/kali-security kali-rolling/updates main contrib non-free 91 | #deb-src http://security.kali.org/kali-security kali-rolling/updates main contrib non-free 92 | ``` 93 | 94 | 以上是目前加快的,也可以百度一下增加其它源 95 | 96 | -------------- 97 | [kali]: https://blog.csdn.net/knigh_yun/article/details/79949512 -------------------------------------------------------------------------------- /_posts/2018-04-25-c-rand-number.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: C 语言之随机数函数(rand())的使用方法 3 | layout: post 4 | categories: C语言 5 | tags: C语言随机数 伪随机数 rand() srand() 6 | excerpt: C 语言关于随机数函数的用法和原理 7 | --- 8 | 在程序设计中,难免会使用到随机值函数,其原理与语法大多类似,接下来以C语言为例介绍其随机值函数 `rand()` 用法。 9 | 10 | # 原理 11 | 引用[百度百科][rand],首先,需要包含头文件: 12 | 13 | #include 14 | rand()函数是按指定的顺序来产生整数,因此每次执行上面的语句都打印相同的两个值,所以说C语言的随机并不是真正意义上的随机,有时候也叫[伪随机数][wei],使用 `rand()` 生成随机数之前需要用随机发生器的初始化函数 `srand(unsigned seed)`(也位于 `stdlib.h` 中) 进行伪随机数序列初始化,`seed` 又叫[随机种子][seed],通俗讲就是,如果每次提供的 `seed` 是一样的话,最后每一轮生成的几个随机值也都是一样的,因此叫伪随机数,所以需要每次提供不同的 `seed` 达到完全的随机,我们通常用时间函数 `time(NULL)` 作为 `seed` ,因为时间值每秒都不同,这个函数需要包含以下头文件: 15 | 16 | #include 17 | 18 | 理论太泛,下面用例子分析理解。 19 | 20 | # 举例分析 21 | 先来理解以下伪随机数,编译以下代码: 22 | ``` c 23 | #include 24 | #include 25 | #include 26 | int main() 27 | { 28 | srand(1); 29 | int i; 30 | for (i = 0; i < 10; i++) 31 | printf("%d, ", rand()%11); 32 | } 33 | ``` 34 | 运行结果 35 | 36 | 8, 9, 9, 1, 7, 5, 5, 10, 1, 0, 37 | 38 | 然后无论运行多少次,结果都依然是以上随机数,不会改变,因为每次设置的种子 `seed` 都是 `1` 。 39 | 40 | 但是假如把 `seed` 换成 `time(NULL)`,每次就不一样了,如下: 41 | ``` c 42 | #include 43 | #include 44 | #include 45 | int main() 46 | { 47 | srand(time(NULL)); 48 | int i; 49 | for (i = 0; i < 10; i++) 50 | printf("%d, ", rand()%11); 51 | } 52 | ``` 53 | 结果是就变了,并且每次都不一样: 54 | 55 | 6, 3, 4, 5, 5, 9, 8, 10, 10, 4, 56 | 6, 4, 2, 4, 3, 2, 5, 1, 2, 9, 57 | 58 | >**这里的 `time(NULL)` 的结果是一个类似于 `1524655706` 的数字,并且每秒都在递增 1,也就达成了 srand() 的 seed 不断变化的目的,不断生成新的随机数。** 59 | 60 | # 拓展 61 | 这里注意一下例子中函数 `rand()` 的用法,函数括号内不需要加参数,如果直接调用 `rand()` 的话会生成下面这样的数: 62 | 63 | 17163, 2663, 24810, 4875, 26975, 14119, 22193, 11233, 26009, 20105, 64 | 所以我们想要生成指定范围的随机数的话就需要使用到**求余**运算符 `%`,这里有个规律:例如我们需要 0--10的随机数时,就写成 `rand()%11`,0--100就写成 `rand()%101`,就是运算符后的数字需要比需求范围极值大 1,当然这也是取余运算的原理。 65 | 66 | ---------------------- 67 | [rand]: https://baike.baidu.com/item/rand%28%29 68 | [wei]: https://baike.baidu.com/item/%E4%BC%AA%E9%9A%8F%E6%9C%BA%E6%95%B0 69 | [seed]: https://baike.baidu.com/item/%E9%9A%8F%E6%9C%BA%E7%A7%8D%E5%AD%90 -------------------------------------------------------------------------------- /_posts/2018-04-28-c-storage-type.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: C 语言之变量存储类型与链接属性 3 | layout: post 4 | categories: C语言 5 | excerpt: C语言的变量存储类型与链接属性的区别分析 6 | tags: 存储类型 链接属性 静态变量static extern 寄存器 7 | --- 8 | C语言中一个重要的东西就是弄清申明变量的类型、作用域、存储类型、链接属性等,例如是整型还是浮点型,存储于普通内存还是堆栈或者寄存器,作用于全局还是局部,能否被其他文件 引用等。 9 | 10 | # 链接属性 11 | 12 | 申明变量或函数时需要**标识符**,标识符的链接属性一共有三种:`external(外部)`, `internal(内部)`, `none(无)`,external和internal常用,**none**表示无链接属性,该标识符的多个申明被当成独立不同的实体。 13 | 14 | 顾名思义,**external**表示能被其它源文件访问的变量或函数,**internal**则不能被其它源文件访问,并且**缺省**情况下**代码块(block)外部**的变量为**external**属性,也就是外部变量,**代码块内部**的变量为**internal**属性,即局部变量. 15 | 16 | 如果需要改变链接属性需要使用 `extern` 和 `static` 关键字,`extern` 是转化为**external**属性,`static` 是转化为**internal**属性。 17 | 举例说明: 18 | 19 | ``` c 20 | #include 21 | int a = 1; /* 这里是代码块外部,external 属性,缺省为"extern" */ 22 | extern int aa = 11; /* 与上面效果一样 */ 23 | static int aaa = 111; /* 这里申明的是 internal 属性,不能被其它源文件访问 */ 24 | void example() /* 这里申明的 example() 函数也是external属性,能被其它源文件访问 */ 25 | { 26 | int b = 2; /* 这里是代码块内部,internal 属性 */ 27 | extern int bb = 22; /* 这里的意思是访问其它源文件的全局变量 */ 28 | } 29 | ``` 30 | >**注意上面指出的代码块内部和外部,定义的函数的花括号之外叫做代码块外部,之内叫做代码块内部。** 31 | >**代码块外部缺省为`extern`,并且代码块外部使用`extern`表示被其它源文件访问,代码块内部使用`extern`表示访问其它文件的外部变量。** 32 | 33 | # 存储类型 34 | 35 | 存储类型指申明的变量将被存储到什么地方去,并且与其存储周期有关,就是这个变量何时被创建,何时被销毁,保持多久。 36 | 37 | 存储类型有三种: 38 | 静态变量(`static`) ---> 存储于普通内存。 39 | 自动变量(`auto`) ---> 存储于堆栈。 40 | 寄存器变量(`register`) ---> 存储于寄存器。 41 | 42 | ###### 静态变量 43 | 任何代码块之外定义的变量,总是处于静态内存中,无需使用 `static` 关键字,在程序运行**之前**创建,程序整个执行期间**始终存在**。 44 | 45 | ###### 自动变量 46 | 代码块内部申明的变量,并且**缺省**情况下都是(`auto`)类型,所以很少使用,存储于堆栈中,程序执行到申明变量处被创建,离开后被销毁,每次在堆栈中占据的内存位置都**可能不同**。 47 | 48 | ###### 寄存器变量 49 | 用于申明**自动变量**,即在**代码块内部**使用,使这类变量存储于寄存器中,**寄存器中的变量比内存中的变量访问效率更高**。 50 | 但是,如果有**太多**变量申明为 `register` ,只会选取前几个存储于寄存器中,其它处理为普通自动变量。 51 | 52 | 通常把**使用频率最高**的变量申明为寄存器变量,或者指针申明为寄存器变量,以提高效率。例如可以把函数的形参申明为寄存器变量(有可能它节省的时间空间开销抵不上复制这几个值的开销)。 53 | 54 | ###### 综合举例 55 | 56 | ``` c 57 | #include 58 | int a = 1; /* 静态变量(static),这里不能使用 register */ 59 | int main() 60 | { 61 | int b = 2; /* 自动变量,省略 auto */ 62 | register int c = 3; /* 寄存器变量(register) */ 63 | int aaa(register int d) /* 申明函数形参为 register */ 64 | static int e = 4; /* 申明静态变量,和变量 b 一个属性 */ 65 | } 66 | ``` 67 | 68 | ###### 初始化 69 | 静态变量在不指定初始值的时候,初始化为 `0`; 70 | 自动变量是否初始化赋值,并无效率的改变(每次执行都要重新初始化),这也是它的优点:可以用任何“表达式”作为初始值。例如: 71 | 72 | int add(int a) 73 | { 74 | int b = a + 1; /* 将表达式 a + 1 的值初始化给 b */ 75 | return b; 76 | } 77 | 78 | # 注意 79 | * `static` 申明函数或代码块之外的变量时,只修改**链接属性** ``external` 为 `internal`,**存储类型**和**作用域**不变。 80 | * `static` 申明代码块内部变量时,将自动变量修改为**静态变量**,但是**链接属性**和**作用域**不变。 81 | 82 | ###### 综合举例 83 | 84 | ``` c 85 | #include 86 | int a = 1; /* 链接属性为 external,缺省 extern */ 87 | static int b = 2; /* 修改连接属性为静态变量,不能被其它源文件访问,依然为全局变量,存储于静态内存中 */ 88 | int main() 89 | { 90 | int c = 3; /* 自动变量,存储到堆栈 */ 91 | static int d = 4; /* 静态变量,存储到普通内存,依然不能被其它源文件访问 */ 92 | } 93 | ``` -------------------------------------------------------------------------------- /_posts/2018-05-02-css-selector.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CSS 选择器详细介绍 3 | layout: post 4 | categories: CSS 5 | tags: css选择器 内联嵌入外部式 ID类选择器区别 伪元素 6 | excerpt: css选择器详细介绍与举例 7 | --- 8 | -------------------- 9 | 文章出自个人博客,转载请申明 10 | 11 | ------------------ 12 | # 目录 13 | * [基础](#1) 14 | * [选择器](#2) 15 | * [元素选择器](#2.1) 16 | * [类选择器](#2.2) 17 | * [ID选择器](#2.3) 18 | * [ID选择器与类选择器的区别](#2.3.1) 19 | * [子选择器](#2.4) 20 | * [后代选择器](#2.5) 21 | * [通用选择器](#2.6) 22 | * [属性选择器](#2.7) 23 | * [简单属性选择器](#2.7.1) 24 | * [属性和值选择器](#2.7.2) 25 | * [伪元素选择器](#2.8) 26 | * [:active](#2.8.1) 27 | * [:hover](#2.8.2) 28 | * [:focus](#2.8.3) 29 | * [::selection](#2.8.4) 30 | * [:first-child](#2.8.5) 31 | * [:nth-child()](#2.8.6) 32 | * [组选择器](#2.9) 33 | * [相邻同级选择器](#2.10) 34 | 35 | ---------------------------- 36 | # 基础 37 | CSS(层叠样式表Cascading Style Sheets),用于修饰HTML网页内容,根据使用位置不同可分为三种样式:**内联式,嵌入式,外部式。** 38 | 39 | * **内联式:**标签 `<>`内部使用,例如: 40 | 41 | >`

`。 42 | 43 | * **嵌入式:**写在 `` 之中,并放在 `` 内,例如: 44 | 45 | ``` html 46 | 47 | 48 | 54 | 55 | ``` 56 | 57 | * **外部式:**写在外部 `.css` 文件中,使用如下方式引用: 58 | 59 | >`` 60 | > `href` 写 `.css` 文件路径,可以是绝对路径或相对路径,相对路径类似于:`../../css/index.css`,绝对路径类似于:`/css/index.css`。 61 | 62 | # 选择器(Selector) 63 | 64 | 三种样式中,**嵌入式**和**外部式**需要使用到**选择器**,也是组成 css 样式的主体例如上例中的 `p { }`,主要分为: 65 | 元素选择器、类选择器、ID选择器、子选择器、后代选择器、通用选择器、属性选择器、伪元素选择器、组选择器、相邻同级选择器。 66 | 67 | ## 元素选择器(Type selector) 68 | 也叫类型选择器,可以理解为**标签选择器**,最基本的选择器,就是使用常见的HTML元素,例如:`body { }`, `h { }`, `p { }`, `div { }`, `span { }`, `a { }` 等。 69 | 70 | ## 类选择器(Class selector) 71 | **前提**需要在标签内使用**类**标记某处文档,类似:`class = "myClass"`,然后它的选择器的格式就为:`.myClass { }`,就是在类名前面加个小数点。 72 | 73 | ## ID选择器(ID selecctor) 74 | 和类选择器类似,**前提**需要在标签内使用**ID**标记某处文档,类似:`id = "myId"`,格式为:`#myId { }`,就是在 ID 前加个符号 `#`。 75 | 76 | >**ID选择器与类选择器的区别:** 77 | >类选择器可以使用多次,ID选择器只能使用一次,例如: 78 | >`

This is a test content,

` 79 | >`

hello world !

`,但是ID不能这样。 80 | >并且能同时使用多个类分别标记不同样式,例如:`

`,ID也不能这样。 81 | 82 | ## 子选择器(Child selector) 83 | 用于指定标签元素的**子元素**,使用符号 `>` 隔开父元素与子元素,例如: 84 | HTML: 85 | 86 | 87 | Hello World !!! 88 | This is a test content 89 | 90 | 91 | CSS: 92 | 93 | p1>p2 { 94 | color: green; 95 | font-size: 20px; 96 | } 97 | 98 | 这里就指定了父元素 `p1` 的子元素 `p2` 的样式,但是**只作用于子元素,不作用于父元素**。 99 | 100 | ## 后代选择器(Descendant selector) 101 | 用于指定标签元素的**后代元素**,使用空格符号隔开,例如: 102 | html: 103 | 104 | 105 | Hello world !!! 106 | 107 | This is a
test content 108 | 109 | 110 | 111 | css: 112 | 113 | p1 a { 114 | color: green; 115 | font-size: 20px; 116 | } 117 | 118 | 这里指定了元素 `p1` 的后代元素 `a` 的样式,注意这里不是**子代元素** `p2`,就是作用于**所有指明的后代元素**。 119 | 120 | >**子代选择器与后代选择器的区别:** 121 | >顾名思义的理解,后代就是包含子代在内的所有下代的元素,可以跨越子代直接作用于孙代;而子代只包含父级的**第一代子代**元素。 122 | >子代选择器使用符号 `>` 隔开,后代选择器使用`空格` 隔开。 123 | 124 | ## 通用选择器 125 | 顾名思义,使用通配符 `*` 设置 html 中**所有标签**的样式,例如: 126 | 127 | ``` css 128 | * { 129 | color: red; 130 | font-size: 20px; 131 | } 132 | ``` 133 | 134 | 这样就设置了HTML中所有的标签的样式了。 135 | 136 | ## 属性选择器(Attribute selector) 137 | 对**具有指定的属性**(attribute)设置样式,使用方括号符号 `[ ]`。 138 | 139 | ### 简单属性选择器 140 | 不用管属性值,例如: 141 | 142 | ``` css 143 | [href] {color: red} 144 | a [href] {color: red} 145 | a [href] [title] {color: red} 146 | ``` 147 | 148 | >以上格式都能实现相同效果,即具有该属性的 `a` 标签。 149 | 150 | ### 属性和值选择器 151 | 具有指定属性与其**指定值**的标签,格式为: 152 | 153 | a [title = "link"] {color: red} 154 | 155 | ## 伪元素选择器 156 | HTML中存在一类与元素控制内容相同的**抽象元素**,但是并不实际存在于HTML文档,给标签的**某种状态**设置样式,例如单击某内容或鼠标滑过某内容,然后设置改变的样式。伪元素种类较多,只列举几个常用例子。 157 | 158 | ### :active 159 | 为**激活**的元素设置样式,就是用户单击该标签时的样式,例如: 160 | 161 | a:active {color: red} 162 | 163 | 则用户点击这个链接文本时颜色变为红色。 164 | 165 | ### :hover 166 | 悬停状态伪元素,为用户鼠标所**停靠**的标签设置样式,例如: 167 | 168 | p:hover {color: red} 169 | 170 | 则鼠标停留在该段落时,段落内容变为红色。 171 | 172 | ### :focus 173 | 用于具有**焦点**的元素,常用就是输入框,用户点击输入框准备输入时则该输入框就具有了焦点,例如: 174 | 175 | input:focus {background-color: green} 176 | 则点击输入框时背景颜色变为绿色。 177 | 178 | ### ::selection 179 | 为选中的元素设置样式,例如: 180 | 181 | ::selection {color: red} 182 | 183 | 为文档中鼠标选定的内容设置为红色字体。注意可以追加应用范围:`p::selection` 表示段落中选中的字体才应用该样式,不追加直接使用 `::selection` 表示应用于所有内容。 184 | **火狐浏览器**支持需要使用 `-moz-selection`。 185 | 186 | ### :first-child 187 | 为元素的第一子代应用样式,例如: 188 | 189 | p:first-child {color: red} 190 | 191 | 这个比较好理解。 192 | 193 | ### :nth-child() 194 | 为元素的**父元素**的第 n 个子代设置样式,只是括号内需要输入数字表示第几代,例如: 195 | 196 | p:nth-child(2) {color: red} 197 | 198 | 假如p标签父元素是body,就表示为body的第二个子元素设置样式。 199 | 200 | ## 组选择器 201 | 为多个元素设置相同样式时,可以使用**逗号**分隔元素,达到同时设置的效果。例如: 202 | 203 | p1,p1 {color: red} 204 | 205 | 表示为p1和p2 **同时**设置**相同**的样式。 206 | 207 | ## 相邻同级选择器 208 | 选择与指定元素同级的相邻的第一个某元素,设置样式,例如: 209 | 210 | div+p {color: red} 211 | 212 | 表示为 p 设置样式,并且这个 p 与 div 同级,并且是与 div **相邻的第一个** p,div **内部**的 p 并不包含在内。 213 | 214 | ------------------------ 215 | # 返回[顶部](#home) -------------------------------------------------------------------------------- /_posts/2018-05-04-css-layout-model.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CSS 布局模型详细介绍 3 | layout: post 4 | categories: CSS 5 | tags: css布局模型 绝对定位 相对定位 固定定位 position 6 | excerpt: CSS 布局类型详细介绍与举例说明 7 | --- 8 | HTML中元素有三种布局模型:流动模型、浮动模型、层模型。 9 | 10 | # 流动模型(flow) 11 | HTML网页默认布局就是流动模型,布局如下: 12 | 13 | **块级元素(block)**自上而下垂直分布,因为块级元素默认宽度为浏览器窗口的**100%**,或者理解为每个块级元素默认**占一行**。常见块级元素有 `div`, `p`, `h` 等; 14 | 15 | **内联元素(inline)**从左到右水平分布,即不像块级元素那样每个独占一行。常见内联元素有 `a`, `span`, `em` 等。 16 | 17 | 18 | # 浮动模型(float) 19 | 上面提到的块级元素是每个独占一行显示,但是定义css浮动模型后就能使两个块级元素**并排一行**显示。 20 | 例如HTML代码: 21 | 22 | ``` html 23 |
24 |

Hello

25 |
26 |
27 |

World !

28 |
29 | ``` 30 | 31 | 显示结果是这样: 32 | 33 | Hello 34 | World ! 35 | 36 | 但是设置浮动css后: 37 | 38 | ``` css 39 | div { 40 | float: left; 41 | } 42 | ``` 43 | 44 | 效果就是这样: 45 | 46 | HelloWorld ! 47 | 48 | 也可以设置元素一左一右显示: 49 | 50 | ``` css 51 | #div1 { 52 | float: left; 53 | } 54 | 55 | #div2 { 56 | float: right; 57 | } 58 | ``` 59 | 60 | # 层模型(layer)(position) 61 | 类似于PS中的**图层**编辑,HTML中也存在层模型布局,对元素进行**定位**。 62 | 层模型有三种:**绝对定位**(absolute)、**相对定位**(relative)、**固定定位**(fixed)。 63 | 64 | ## 绝对定位 65 | 理解就是字面上的意思,简言之就是**相对于上级设置了 position 属性的元素**进行定位,如果没有这类上级就是相对于 `body` 标签,也是**浏览器窗口**。需要设置css:`position: absolute;`,然后就可以使用 `top`, `right`, `bottom`, `left` 这类属性进行定位。例如: 66 | 67 | ``` css 68 | div { 69 | position: absolute; 70 | top: 100px; 71 | left: 150px; 72 | } 73 | ``` 74 | 75 | 这样就使板块**向下**移动100像素,**向右**移动150像素。 76 | 77 | ## 相对定位 78 | 这里的**相对**较难理解,与数理中的“相对”不太一样,这里是**“相对于自己原来应在的位置”**,需要设置css:`position: relative;`,重要的是不用关心**上级是否设置了position属性**,这样就很方便。例如: 79 | 80 | ``` css 81 | div { 82 | position: relative; 83 | top: 100px; 84 | right: 100px; 85 | } 86 | ``` 87 | 88 | 板块就相对于自己没设置样式前的位置,同时向左向下移动100px。 89 | 90 | ## 固定定位 91 | 这个就好理解了,所谓**固定**就是指固定于整个浏览器网页窗口不动,即使滚动网页内容也不改变位置,需要设置css:`position: fixed`,也可以设置 `top`, `right`等调整固定的位置。还记得浏览器某些网页右下角的小广告吗,是不是固定在那怎么浏览网页都不动 -_- . -------------------------------------------------------------------------------- /_posts/2018-05-22-css-content-center.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CSS 样式之内容居中方法 3 | layout: post 4 | categories: CSS 5 | tags: css水平居中 css垂直居中 6 | excerpt: CSS 样式设置使 HTML 内容水平居中和垂直居中的方法 7 | --- 8 | # 水平居中 9 | 10 | HTML中要实现某一内容水平居中显示,要通过设置css样式来实现,主要分为**行内元素**和**块状元素**两种情况,**块状元素**又可分为**块状定宽**与**块状不定宽**两种情况,接下来依次介绍分析。 11 | 12 | ## 行内元素 13 | 14 | 像 a、span、i 这类元素叫做行内元素,**文本**和**图片**也是行内元素。行内元素水平居中方法简单,只需要给行内元素的**父元素**设置 `text-align: center;` css样式就内实现内容水平居中,例如: 15 | html: 16 | 17 | ``` html 18 |
居中内容
19 | ``` 20 | 21 | css: 22 | 23 | ``` css 24 | .txt { 25 | text-align: center; 26 | } 27 | ``` 28 | 29 | 文本内容的**父元素**就是 `div` ,这样就内实现水平居中,效果如下: 30 | 31 |
居中内容
32 | 33 | ## 块状定宽元素 34 | 35 | 常见块状元素有 div, p, h 等,定宽即为其设置固定宽度值 `width`,这时我们可以为元素设置 `margin-left` 和 `margin-right` 来实现水平居中,也可以简写为 `margin: 0 auto;`,例如: 36 | html: 37 | 38 | ``` html 39 |
居中内容
40 | ``` 41 | 42 | css: 43 | 44 | ``` css 45 | .txt { 46 | width: 100px; 47 | margin: 10px auto; 48 | } 49 | ``` 50 | 51 | 实现效果如下: 52 | 53 |
居中内容
54 | 55 | ## 块状不定宽 56 | 57 | 有时候我们不能限制块状元素的宽度,就是块状不定宽元素,主要有三种方法,接下来一次介绍。 58 | 59 | ##### 1、加入 table 标签 60 | 61 | 利用 table 标签的**长度自适应性**,长度根据内容自动调整,然后通过设置 `margin: auto;` 实现水平居中,例如: 62 | html: 63 | 64 | ``` html 65 | 66 | 67 | 68 | 71 | 72 | 73 |
69 |
居中内容
70 |
74 | ``` 75 | 76 | css: 77 | 78 | ``` css 79 | .txt { 80 | margin: auto; 81 | } 82 | ``` 83 | 84 | 效果如下: 85 | 86 |
居中内容
87 | 88 | ##### 2、设置为行内元素 89 | 90 | 就是通过设置 `display: inline;` 将块状元素设置为**行内元素**,然后就是像行内元素一样设置 `text-align: center;` 来是内容水平居中,例如: 91 | html: 92 | 93 | ``` html 94 |
居中内容
95 | ``` 96 | 97 | css: 98 | 99 | ``` css 100 | .txt { 101 | display: inline; 102 | text-align: center; 103 | } 104 | ``` 105 | 106 | 效果为: 107 | 108 |
居中内容
109 | 110 | **注:** 111 | 112 | >**使用这种方法虽然可以不用像table增加无语义标签,但是改变了display,所以会少了一些功能,例如不能设置宽度。** 113 | 114 | ##### 3、设置浮动和相对定位 115 | 116 | 这种方法设置就相对复杂,同时设置**浮动**和**相对定位**来实现元素的水平居中。 117 | 首先设置**父元素**: 118 | 119 | ``` css 120 | float: left; 121 | position: relative; 122 | left: 50%; 123 | ``` 124 | 125 | 然后设置**子元素**: 126 | 127 | ``` css 128 | position: relative; 129 | left: -50%; 130 | ``` 131 | 132 | 通过代码应该好理解,就是通过**50%**那个关键位置来实现水平居中效果,因为**50%**是界面的中央位置,将父元素右移,直到左边框移到中线位置,在将子元素向左移,这样子元素不就居中了吗。 133 | 134 | 这里要**注意**的是分别设置**父元素**的 `50%` 和**子元素**的 `-50%`。 135 | 实现效果如下: 136 | 137 |
居中内容
138 | 139 | # 垂直居中 140 | 141 | 说完水平居中接着说垂直居中,这里主要又分为两种情况:**父元素高度确定的单行文本** 和**父元素高度确定的多行文本**。 142 | 143 | ## 单行文本 144 | 145 | 对于**父元素**高度确定的单行文本,可以通过设置**父元素**的 `height` 和 `line-height` 高度一致来实现。 146 | 147 | 这里可以这样理解,`height` 是元素的高度,例如文本字体的高度,`line-height` 是行高,例如文本的行间距,一行文本中,行间距被**分为两部分**,分别位于这行文本的**顶部**和**底部**(因为行间距是两行之间的距离),所以设置 `height` 和 `line-height` **一样大**的话,`line-height` 就被均分为两部分,分别位于元素顶部和底部,这样中间设置为 `height` 的元素不就实现**垂直居中**了吗 ^_^ . 148 | 149 | 例如: 150 | html: 151 | 152 | ``` html 153 |
居中内容
154 | ``` 155 | 156 | css: 157 | 158 | ``` css 159 | .txt { 160 | height: 200px; 161 | line-height: 200px; 162 | } 163 | ``` 164 | 165 | 效果如下: 166 | 167 |
168 | 
169 | 
170 | 
171 | 居中内容
172 | 
173 | 
174 | 
175 | 
176 | 177 | >**这里需要注意的是关键词“单行文本”,如果使用这种方法但是一行文本超过宽度限制的话,某些内容就会脱离元素块,子元素有多行的话,这几行就会并排居中,并保持设置的行高。** 178 | 179 | ## 多行文本 180 | 181 | 对于父元素高度确定的**文本**和**图片**等内容设置垂直居中,主要有两种方法。 182 | 183 | ##### 1、使用 table 标签 184 | 185 | 对元素使用**table**标签,包括 tbody,tr,td,然后对父元素设置 `vertical-align: middle;` 样式,就能使 `inline-block` 类型的子元素垂直居中显示。 186 | 187 | 因为 td 标签**默认**设置了 `vertical-align: middle`,所以也可以不用单独设置 `vertical-align`。 188 | 例如: 189 | html: 190 | 191 | ``` html 192 | 193 | 194 | 195 | 200 | 201 | 202 |
196 |

居中内容

197 |

居中内容

198 |

居中内容

199 |
203 | ``` 204 | 205 | css: 206 | 207 | ``` css 208 | .txt { 209 | height: 300px; 210 | background-color: #ccc; 211 | } 212 | ``` 213 | 214 | >**这里的父元素就是 td,父元素的高度必须确定,就要为其设置 height。** 215 | 216 | **注意**这里的 p 元素是 **inline** 类型的,所以设置 `vertical-align: middle` 的话会出现错误,若果是图片元素 img 的话,就可以设置 `vertical-align: middle`,但是由于 td 标签默认,所以都可以不写。 217 | 218 | 效果如下: 219 | 220 |
221 | 
222 | 
223 | 
224 | 居中内容
225 | 
226 | 
227 | 
228 | 
229 | 230 | ##### 2、设置 table-cell 231 | 232 | 第二种方法是把要垂直居中显示的元素的父元素设置为**table-cell (表格单元)**类型:`display: table-cell;`,然后设置 `vertical-align: middle`就能实现元素垂直居中。 233 | 234 | 但是这个方法存在兼容性问题,**chrome, firefox, IE8以上**才支持这个操作。 235 | 236 | 例如: 237 | html: 238 | 239 | ``` html 240 |
241 |

居中内容

242 |

居中内容

243 |

居中内容

244 |
245 | ``` 246 | 247 | css: 248 | 249 | ``` css 250 | .txt { 251 | height: 300px; 252 | background-color: #ccc; 253 | display: table-cell; 254 | vertical-align: middle; 255 | } 256 | ``` 257 | 258 | >**同样,要为父元素 div 设置高度 height** 259 | 260 | 效果如下: 261 | 262 |
263 | 
264 | 
265 | 
266 | 居中内容
267 | 
268 | 
269 | 
270 | 
271 | 272 | 这种方法除了兼容性问题外,同时也改变了 **display**类型,会在某些方面带来不便。 -------------------------------------------------------------------------------- /_posts/2018-05-22-web-browser-history.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: web 浏览器进化简史 3 | layout: post 4 | categories: 网站 5 | tags: web浏览器 浏览器发展史 6 | excerpt: web 浏览器的发展简史,常用浏览器的介绍 7 | --- 8 | ## 发展史与时间线 9 | 10 | * 1989年,科学家***Tim-Berners-Lee***发明了**World Wide Web**(万维网)。 11 | ![www.png](https://i.loli.net/2018/05/22/5b04323d35dcc.png) 12 | 13 | * 1990年,他开发了世界上第一款网页浏览器,为避免与万维网混淆,改名为**NEXUS**,但不支持图片。 14 | ![nexus.png](https://i.loli.net/2018/05/22/5b04323d6cf2f.png) 15 | 16 | * 1993年,伊利诺大学的NCSA组织创造了第一款可显示图片的浏览器,**Mosaic**(马赛克) 17 | ![mosaic.gif](https://i.loli.net/2018/05/22/5b04323d04dfc.gif) 18 | 19 | * 1994年10月在麻省理工学院计算机科学实验室成立**万维网联盟**。建立者正是万维网的发明者**蒂姆·伯纳斯·李**。万维网联盟(**World Wide Web Consortium**,简称**W3C**)。 20 | ![w3c.jpg](https://i.loli.net/2018/05/22/5b04323c3986d.jpg) 21 | 22 | * 1994年,**Mozilla**出现了。不过,鉴于当时 Mosaic 的权势。为了避嫌,最终改名成了**Netscape Navigator**(网景公司开发的网络浏览器)。凭借着html框架显示等新特性,很快成为了**新的霸主**。 23 | ![nn.jpg](https://i.loli.net/2018/05/22/5b04323c69a6d.jpg) 24 | 25 | * 1995年微软发布了跟系统“捆绑”的浏览器**Internet Explorer(IE)**,凭借着操作系统的占有率,**IE**就把**Netscape**挤下了霸主宝座。 26 | ![ie.jpg](https://i.loli.net/2018/05/22/5b04323cc82c2.jpg) 27 | 28 | * 和 **IE** 差不多时间诞生,还有一直不温不火的 **Opera**。 29 | ![opera.jpg](https://i.loli.net/2018/05/22/5b04326e039df.jpg) 30 | 31 | * **NetScape**并未放弃,围绕着浏览器引擎衍生出了人们熟知 **Firefox**。 32 | ![firefox.jpg](https://i.loli.net/2018/05/22/5b04326e06bfd.jpg) 33 | 34 | * 2003年,苹果推出的 **Safari**。 35 | ![safari.jpg](https://i.loli.net/2018/05/22/5b04326e023b8.jpg) 36 | 37 | * 2008年 **Google** 携 **Chrome** 参战,让 **IE** 逐渐失利。 38 | ![chrome.jpg](https://i.loli.net/2018/05/22/5b04326e31caf.jpg) 39 | 40 | * 2015年,微软为了改变局面,推出了 **Edge**。 41 | ![edge.jpg](https://i.loli.net/2018/05/22/5b04326e00c7f.jpg) 42 | 43 | * 但 **Chrome** 以及类似内核的浏览器依旧是主流。 44 | ![chrome-inner.jpg](https://i.loli.net/2018/05/22/5b04326e052f1.jpg) -------------------------------------------------------------------------------- /_posts/2018-05-23-js-anonymous-function.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 中语句与函数的执行辨析 3 | layout: post 4 | categories: JavaScript 5 | tags: javascript函数 匿名函数 javascript语句 6 | exccerpt: Javascript 中函数与匿名函数及语句的使用辨析 7 | --- 8 | Javascript代码中,语句和函数以及匿名函数的执行存在一些区别,所以在编写过程中也存在一些“坑“。 9 | 10 | # script 中的语句 11 | 12 | html文档中的javascript语句是写在 `` 中的,每条语句末尾需要添加分号 `;`,表示此条语句执行结束。例如下面的代码: 13 | 14 | ``` html 15 | 19 | ``` 20 | 21 | 文档加载到这块代码区域时,就会立刻**执行**这两条语句,即弹出提示框为x的值,但是如果把语句换成函数定义,代码如下: 22 | 23 | ``` html 24 | 32 | ``` 33 | 34 | 这时第一行语句会被**执行**,第二至五行是**函数定义**,并不会执行这个函数,直到最后一行语句才会真正**执行**这个定义过的函数。 35 | 36 | 如果需要立刻执行函数的话,就需要使用**匿名函数**了。所谓匿名函数,顾名思义,即不会给这个执行的函数定义“函数名”,而且是一个立即执行的语句。格式如下: 37 | 38 | ``` html 39 | 45 | ``` 46 | 47 | **注意**代码中的三个**括号**的位置,以及最后跟的那个**分号**,表示这是一个立即执行的语句。 48 | 49 | 当然匿名函数也能**传递参数**,例如: 50 | 51 | ``` html 52 | 57 | ``` 58 | 59 | 效果和上面一样。 60 | 61 | 但有时又需要不立即执行的函数,例如: 62 | 63 | ``` html 64 | 70 | ``` 71 | 72 | 效果与下面代码一样: 73 | 74 | ``` html 75 | 79 | ``` 80 | 81 | 这是Javascript中的延时函数,表示2秒后弹出提示。`setTimeout()` 自身就是一个**函数**,里面的 `“alert(x)”` 是这个函数的一个**参数**,即一个**加引号的语句**。便于理解,可以写成这样: 82 | 83 | setTimeout("alert();", 2000); 84 | 85 | 这样写并不会出错。 86 | 87 | 所以这个函数 `setTimeout()` 的参数是一个**不用立即执行**的匿名函数 `function(){}`,也可以是一个语句块,从而进行**参数传递**。 88 | 89 | 通俗讲,这里加引号的语句块相当于不加引号的匿名函数。 90 | 91 | # 标签属性中的语句 92 | 93 | 在 html 标签中也能使用语句,通常用于设置元素的属性。 94 | 95 | 先对比区分以下代码: 96 | 97 | ```html 98 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | ``` 119 | 120 | 猜一下哪个按钮点击无效…… 121 | 122 | 答案是最后的**“Button6”**和**"Button7"**,然后就能发现规律了,**属性**所设置的**值**必须是能**立即执行**的语句块函数匿名函数,最后那两种情况是行不通的。 -------------------------------------------------------------------------------- /_posts/2018-05-24-js-timer-function.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 计时器函数用法 3 | layout: post 4 | categories: JavaScript 5 | excerpt: Javascript 计时函数的详细介绍 6 | tags: Javascript计时器 setTimeout setInterval 7 | --- 8 | Javascript中和大多数语言一样,存在计时函数,使某语句或函数不用立即执行,可以延时设定的时间值之后再执行。 9 | 10 | # setTimeout() 11 | 12 | 这个函数表示括号中的代码,延时指定时间后再执行,格式为 `setTimeout("function()", time)`,其中 `time` 的单位是**毫秒**。 13 | 14 | 例如: 15 | 16 | ```javascript 17 | function fx() 18 | { 19 | alert(); 20 | } 21 | setTimeout("fx()", 2000); 22 | ``` 23 | 24 | 也可以写成: 25 | 26 | ``` js 27 | setTimoeout(function(){ 28 | alert(); 29 | }, 2000); 30 | ``` 31 | 32 | 结果就是页面加载完 2 秒后弹出提示框。 33 | 34 | # clearTimeout() 35 | 36 | clearTimeout() 方法用于结束 setTimeout() 方法的执行,括号中**参数**为 setTimeout() 返回的 **ID 值**。 37 | 38 | 举例说明: 39 | 40 | ``` js 41 | var int1 = setTimeout(function(){alert();}, 5000); 42 | clearTimeout(int1); 43 | ``` 44 | 45 | 这样就能**终止**代码执行,不会弹出提示框。 46 | 47 | # setInterval() 48 | 49 | 这个函数表示**每隔**指定时间间隔执行一次括号中的代码,格式为:`setInterval("function()", time)`, `time` 单位依然为毫秒。 50 | 51 | 例如: 52 | 53 | ``` js 54 | function fx() 55 | { 56 | document.write("0"); 57 | } 58 | setInterval("fx()", 2000); 59 | ``` 60 | 61 | 这里就不要用 `alert()` 做实验了,后果你懂的 -_- . 62 | 63 | 同样也能写成: 64 | 65 | ``` js 66 | setInterval(function(){ 67 | document.write("0"); 68 | }, 1000); 69 | ``` 70 | 71 | 效果就是不断输出字符“0”。 72 | 73 | # clearInterval() 74 | 75 | 用法与 clearTimeout() 一样,终止 setInterval() 的执行,括号中填 setInterval() 的返回值。 76 | 77 | 例如: 78 | 79 | ``` js 80 | var int2 = setInterval(function()[ 81 | document.write("0"); 82 | }, 1000); 83 | clearInterval(int2); 84 | ``` 85 | 86 | 这样就能终止输出。 87 | 88 | ## 注意 89 | 90 | 有个小问题,用 setTimeout() 举例,假如代码像下面这样写: 91 | 92 | ``` js 93 | function fx() 94 | { 95 | alert(); 96 | } 97 | setTimeout(fx(), 3000); 98 | ``` 99 | 100 | 相比上面,就是函数第一个参数少了双引号,猜一下后果会怎样…… 101 | 102 | 后果当然是页面加载后立刻弹出提示框,并不会延时 3 秒。下面的写法也是类似的效果: 103 | 104 | ``` js 105 | setTimeout((function(){ 106 | alert(); 107 | })(), 3000); 108 | ``` 109 | 110 | 原因都一样,无论是语句块 `fx()` 还是匿名函数 `(function(){})()`,都是会**立刻执行**的语句,而加双引号的 `"fx()"` 和 `function(){}` 就是当成一个**参数**传递给了函数 setTimeout(),然后这个**参数**语句直到 setTimeou() 真正执行时才生效,也就是延时3秒后执行。 111 | 112 | 函数 setInterval() 的这个性质与 setTimeout() **类似**。 113 | 114 | # 拓展 115 | 116 | ## 回调函数参数 117 | 118 | setTimeout 常见的便是使用两个参数,回调函数和时间,但是它还可以接受更多的参数,作为回调函数调用时传入的参数(可以有多个,按顺序填入即可); 119 | 120 | 举个例子: 121 | ```js 122 | setTimeout(function(a, b){ 123 | console.log(a + b); 124 | }, 3000, 1, 2); 125 | // 3 秒后输出: 126 | // 3 127 | ``` 128 | 129 | ## 返回值 130 | 131 | setTimeout, setInterval 的返回值都是一个数字,具体值取决于当前环境的分配,每次调用后这个数字会加一,`clearTimeout()`, `clearInterval()` 方法传入的参数便是这个数字,只不过平时都是以变量代替; 132 | ```js 133 | let a = setTimeout(function(){}, 1000); 134 | let b = setTimeout(function(){}, 1000); 135 | let c = setTimeout(function(){}, 1000); 136 | 137 | console.log(a, b, c); 138 | // 1 (也可能是其他数字) 139 | // 2 140 | // 3 141 | clearTimeout(a); // 相当于 clearTiemout(1); 142 | clearTimeout(b); // clearTimeout(2) 143 | clearTimeout(c); // clearTimeout(3) 144 | ``` 145 | 146 | ## 时间精准度 147 | 148 | setTimeout 会等到当前任务执行完,即使延迟时间已经到了,所以这也是常说 JavaScript 计时器不一定准确的原因所在,存在所用时间大于指定时间的情况; 149 | 150 | ```js 151 | console.log('start'); 152 | setTimeout('console.log("time")', 2000); 153 | 154 | // 该函数执行 5s 左右 155 | function delay() { 156 | for (i = 0; i < 1000; i++) { 157 | for (j = 0; j < 1000; j++) { 158 | for (k = 0; k < 1000; k++) { 159 | ; 160 | } 161 | } 162 | } 163 | } 164 | delay(); 165 | console.log('end1'); 166 | console.log('end2'); 167 | // start 168 | // end1 169 | // end2 170 | // time 171 | ``` 172 | 173 | ## setInterval 的执行间隔 174 | 175 | 该函数的作用是每隔一定时间执行一遍代码,但是代码的执行时间,被**包括**在间隔时间内,如果执行时间超过了间隔时间,那么下一次执行会立即执行; 176 | ```js 177 | function delay() { 178 | let m = 3000; 179 | let t = new Date().getTime(); 180 | while (new Date().getTime() - t <= m) { 181 | ; // 使该函数 执行时间为 3s 182 | } 183 | console.log(new Date().getSeconds()); 184 | } 185 | 186 | console.log(new Date().getSeconds()); 187 | setInterval(delay, 2000); 188 | ``` 189 | 190 | 最后的输出结果将是输出间隔变为 3s,而不是设定的 2s,因为 `delay()` 函数的执行时间超过了 `setInterval()` 的间隔时间,即间隔时间过了也要等到函数执行完毕,然后下一遍执行就紧接着来,不再有间隔时间,所以就使得最后的结果显示为每隔 3s 输出,其实就是整个 `delay` 函数的执行时间,间隔时间可以理解为被**挤**得没有了; -------------------------------------------------------------------------------- /_posts/2018-05-31-js-closure.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 闭包详解 3 | layout: post 4 | categories: JavaScript 5 | tags: js闭包 js作用域 6 | excerpt: JavaScript 闭包原理详解与举例 7 | --- 8 | # 变量作用域 9 | 10 | 首先来了解一下Javascript中变量的作用域,除了常见的普通变量外,**对象**和**函数**也是一种变量。变量分为局部变量和全局变量。 11 | 12 | ## 局部变量 13 | 14 | 局部变量就是指在**函数内部**定义的变量,作用域是函数内部网,此变量通常只能在函数内部访问,和外界是区分开的,所以变量名即使和外部的**重复**,也是两个独立的变量,不会相互影响。局部变量在函数执行是创建,执行完后**销毁**。 15 | 16 | ## 全局变量 17 | 18 | 全局变量就是函数外部定义的变量,作用域是网页中的所有脚本和函数,它们都能够访问,全局变量是页面加载时创建,页面关闭后销毁。 19 | 20 | 综合举例: 21 | 22 | ``` js 23 | var a = 0; 24 | function fun1() { 25 | var a = 1; 26 | b = 2; 27 | } 28 | ``` 29 | 30 | 这里的 `var a = 0;` 就是全局变量,`var a = 1;` 是局部变量,虽然名字重复,但这里是两个独立变量,但是还是不建议出现重复,提高代码可读性;`b = 2;` 也是**全局变量**,因为规定函数内部申明的变量,如果不加 `var`,即会被认为是全局变量,尤其这点需要小心。 31 | 32 | # 闭包 33 | 34 | 先通俗的总结一下,闭包就是一个可以访问其他函数内部变量的**函数**,即一个定义在函数内部的函数,也叫**内嵌函数**。 35 | 36 | 其次,是闭包的作用,因为通常情况函数内部变量是无法在外部访问的,即全局变量也局部变量的区别,而闭包,就实现了能在外部访问某函数内部变量的功能,让这些变量值始终保存在**内存**中。 37 | 38 | 然后,来讲一下如何实现闭包。有以下代码: 39 | 40 | ``` js 41 | function fun1() { 42 | var a = 1; //定义一个局部变量 43 | function fun2() { //这里的 fun2() 就是闭包 44 | alert(a); //fun2() 是 fun1()的子函数,所以能访问之前定义的局部变量,这个是关键 45 | } 46 | return fun2; //然后通过这里,把之前得到的局部变量成功返回到外部去 47 | } 48 | fun1(); //正常执行函数 49 | var result = fun1(); //将内部变量传递出去,传给变量 result 50 | result(); //执行这个函数实现对局部变量的访问 51 | ``` 52 | 53 | 当然形式不止这一种,万变不离其宗,最后实现的功能是一样的,例如下面的方法也是可行的: 54 | 55 | ``` js 56 | function fun1() { 57 | var a = 1; 58 | return function(){ 59 | alert(a); 60 | }; 61 | } 62 | fun1(); 63 | var result = fun1(); 64 | result(); 65 | ``` 66 | 67 | # 注意 68 | 69 | 也许在很多文章中都能看到这句话“避免滥用闭包”,的确,由于闭包会使一些变量一直保存在内存中,所以如果大量使用的话就会消耗大量内存,影响网页性能。 70 | 71 | 同时,由于闭包的特性,还会在外部改变函数的内部变量值,有时候这是很危险的,举个例子: 72 | 73 | ``` js 74 | function fun1() { 75 | var a = 1; 76 | function fun2() { 77 | a++; 78 | console.log(a); 79 | } 80 | 81 | console.log(a); 82 | return fun2; 83 | } 84 | 85 | var change = fun1(); // 这里 fun1 函数被正常执行,输出 1 86 | change(); // 在外部执行这个函数后,函数内部变量 a 的值就被改变了,输出 2 87 | change(); // 输出 3,以此类推 88 | ``` -------------------------------------------------------------------------------- /_posts/2018-05-31-js-eventlistener.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: addEventListener 方法与 on 事件的区别 3 | layout: post 4 | categories: JavaScript 5 | tags: addeventlistener onclick 事件监听 冒泡捕获 6 | excerpt: Javascript 中事件监听 addEventListener 与 on 事件的区别与举例分析 7 | --- 8 | # on事件 9 | 10 | Javascript中可以对一些页面的事件设定触发值,例如常用的点击 `onclick`,鼠标移动 `onmousemove`,或者移动端屏幕点击 `ontouchstart`,其它类似的还有 `onmousedown`, `onmouseup`, `onchange`, `onfocus`, `onmouseenter`, `ontouchmove`, `ontouchend` 等等,可以对其设定值来实现事件触发后执行的操作,例如: 11 | 12 | ``` html 13 |

Click me

14 | ``` 15 | 16 | 点击后就会弹出提示框,也可以这样写: 17 | 18 | ``` html 19 |

Click me

20 | ``` 21 | 22 | 这样也能实现同样效果,只是它的值变成了一个匿名函数。 23 | 24 | # addEventListener()方法 25 | 26 | 这个方法设定一个事件监听器,当某一事件发生通过设定的参数执行操作。语法是: 27 | 28 | `addEventListener(event, function, useCapture)` 29 | 30 | * 参数 `event` 是必须的,表示监听的事件,例如 `click`, `touchstart` 等,就是之前**不加前缀** `on` 的事件。 31 | * 参数 `function` 也是必须的,表示事件触发后调用的函数,可以是外部定义函数,也可以是匿名函数。 32 | * 参数 `useCapture` 是选填的,填`true`或者`false`,用于描述事件是**冒泡**还是**捕获,`true`表示捕获,默认的`false`表示冒泡。 33 | 34 | ## 移除事件监听 35 | 36 | 如果要移除 addEventListener() 添加的事件监听,就要使用**removeEventListener()**,语法是: 37 | 38 | `removeEventListener(event, function)` 39 | 40 | 参数与addEventListener()一致。 41 | 42 | ## 兼容性 43 | 44 | **IE 8**及更早的版本,和**Opera 7.0**及更早的版本,不支持 addEventListener() 和 removeEventListener() 方法,他们使用的是一下方法代替: 45 | 46 | 添加事件: 47 | `attachEvent(event, function)` 48 | 49 | 移除事件: 50 | `detachEvent(event, function)` 51 | 52 | 可以用以下方法解决兼容性问题: 53 | 54 | ``` html 55 |
Click me
56 | 68 | ``` 69 | 70 | ## 冒泡与捕获 71 | 72 | 这个参数设置的是元素事件的**触发顺序**,即页面中某元素设置了事件监听,其内部元素也设置有事件监听,**冒泡**是先触发最内部元素的事件,再依次触发外一层元素的事件,**捕获**刚好相反,由外到内依次触发。 73 | 74 | 综合举例: 75 | 76 | ``` html 77 |
78 |
79 | 冒泡 80 |
81 |
82 |
83 |
84 | 捕获 85 |
86 |
87 | 88 | 106 | ``` 107 | 108 | 点击“冒泡”模块,先提示子元素后提示父元素;点击“捕获”模块,由于同时设置为 `true`,先提示父元素后提示子元素。 109 | 110 | # 区别 111 | 112 | 为某元素设定事件触发函数时,可能会觉得addEventListener和on事件的功能差不多,但是,addEventListener除了可以设置元素**触发顺序**外,还能**多次绑定事件**,因为 on 事件多次绑定的话会出现**覆盖**。 113 | 114 | 举例说明: 115 | 116 | ``` html 117 |
118 | Click me 119 |
120 | 121 | 130 | ``` 131 | 132 | 结果会依次提示“message1”,“message2“。 133 | 134 | 但是js这么写的话: 135 | 136 | ``` js 137 | div1.onclick = function(){ 138 | alert("message1"); 139 | }; 140 | div1.onclick = function(){ 141 | alert("message2"); 142 | } 143 | ``` 144 | 145 | 这里就只会提示最后一个“message2”,因为onclick作为对象div1的一个属性,第二次对其进行赋值就会**覆盖**之前的函数值,这样on事件在某些场合就不适用了。 -------------------------------------------------------------------------------- /_posts/2018-06-01-jq-syntax.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: jQuery 初识之安装与语法简介 3 | layout: post 4 | categories: JavaScript 5 | tags: jquery语法 jQueryCDN 6 | excerpt: jQuery简介,安装和语法介绍 7 | --- 8 | # 概念 9 | 10 | jQuery是一个JavaScript**函数库**,是一个比较流行的**js框架**,功能就是简化 js 代码的书写,因为一些功能用原生javascript书写代码量是很大的。可以理解为**javascript query**,毕竟Query也是它的一个功能。 11 | 12 | # 安装 13 | 14 | 要使用jQuery库,可以从网上下载得到jQuery的 `.js` 文件,也可以使用**CDN (Content Delivery Content 内容分发网络)**加载jQuery。 15 | 16 | ## 下载 17 | 18 | 需要去jQuery官网:[jquery.com](http://jquery.com/) 下载需要的jQuery库,一般有两个版本,`production` 表示已被压缩精简的版本,用于放到实际网站中,`development` 表示测试开发版,用于编写和开发,是**可读**的代码。 19 | 20 | 例如目前最新的版本是 `jquery-3.3.1.js`,压缩版后缀是 `.min.js`,开发版文件有一万多行,就是正常格式的JavaScript源代码,包含一些注释,文件大小为 `266k`;压缩版就是去掉里面不必要的**空格**,**回车**与**注释**,所以最后文件实际内容只有**一行!**,文件大小为 `85k`,压缩了近**三倍**,这也是网页都使用压缩版,提升网页性能的原因。 21 | 22 | 下载好后放到网页文件夹中,然后使用 ` 26 | ``` 27 | 28 | 路径中填写 `.js` 文件的实际存放位置。 29 | 30 | ## CDN 31 | 32 | 使用CDN(内容分发网络)就可以不用下载jQuery文件,优点是可以使用这个机制尽量避开网络中一些影响数据传输的路线,提高访问速度和稳定性。原理就是使用在各处配置的**节点服务器**,让用户就近获取所需内容。 33 | 34 | 常见CDN有很多,例如百度、新浪、谷歌、微软等,如果是国内站点的话,建议使用国内CDN,国外站点可以使用谷歌或微软,提高速度。 35 | 36 | 以百度CDN为例,安装方法如下: 37 | 38 | ``` html 39 | 40 | ``` 41 | 42 | 微软CDN: 43 | 44 | ``` html 45 | 46 | ``` 47 | 48 | 微软jQuery历史版本可以从这里查看[https://docs.microsoft.com/en-us/aspnet/ajax/cdn/overview#jQuery_Releases_on_the_CDN_0](https://docs.microsoft.com/en-us/aspnet/ajax/cdn/overview#jQuery_Releases_on_the_CDN_0)。 49 | 50 | 更多内容可以访问**百度静态资源公共库**[(http://cdn.code.baidu.com/)](http://cdn.code.baidu.com/),其他CDN可以自行百度搜索。 51 | 52 | # 语法 53 | 54 | jQuery的基础语法是通过**选取(query)**文档中的元素,对其进行**操作(action)**,语法是: 55 | 56 | `$(selector).action()` 57 | 58 | ## 选择器 59 | 60 | `selector` 是选择器,类似于**CSS选择器**,常见的有: 61 | 62 | * 元素选择器,如: `$("p")` 63 | * ID选择器,如:`$("#myId")` 64 | * 类选择器,如:`$(".myClass")` 65 | * 属性选择器,如:`$("[href]")` 66 | 67 | ## 操作 68 | 69 | `action()` 是对所选元素执行的操作,例如: 70 | 71 | * 隐藏元素:`.hide()` 72 | * 单击事件:`.click(myFunction())` 73 | * 双击:`.dblclick()` 74 | * 悬停:`.hover()` 75 | 76 | 其他语法与JavaScript类似,代码写在 ` 82 | ``` 83 | 84 | 有时需要等文档加载完毕后执行代码,很像JavaScript中的 `window.onload`: 85 | 86 | ``` js 87 | window.onload = function(){ 88 | alert(); 89 | } 90 | ``` 91 | 92 | jQuery中就要这么写: 93 | 94 | ``` js 95 | $(document).ready(function(){ 96 | $("p").hide(); 97 | }); 98 | ``` 99 | 100 | 简化写法: 101 | 102 | ``` js 103 | $(function(){ 104 | $("p").hide(); 105 | }); 106 | ``` 107 | 108 | 结果都是在整个文档加载完后执行语句。 109 | 110 | ## 方法链接 111 | 112 | 相对于JavaScript,jQuery又一种特殊的操作方法叫做**方法链接(chaining)**,即在一条语句上,对一个元素执行多个操作,语法是: 113 | `$(selector).action1().action2().action3()` 114 | 115 | 例如: 116 | 117 | ``` js 118 | $("p").html("Hello").click(function(){ 119 | alert("Hello world"); 120 | }); 121 | ``` 122 | 123 | 结果就是改变元素文本内容后绑定点击事件的调用函数,操作可以绑定多个,并且是**依次执行**,方法类似,其他操作以此类推。 124 | -------------------------------------------------------------------------------- /_posts/2018-06-01-js-logic-compute.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 逻辑运算符 “&&” 和 “||” 短路原则的应用 3 | layout: post 4 | categories: JavaScript 5 | tags: javascript逻辑运算 短路原则 6 | excerpt: JavaScript 中逻辑运算符的介绍,短路原则的介绍与应用 7 | --- 8 | # 逻辑运算符 9 | 10 | 在Javascript中,有逻辑运算符 `与 &&`, `或 ||`, `非 !`,常在条件句或循环中进行逻辑判断。 11 | 12 | 例如: 13 | 14 | ``` js 15 | var a = 1, b = 1, c = 2; 16 | if (a = b && (b = c || a != c)) 17 | { 18 | alert("true"); 19 | } else 20 | { 21 | alert("false"); 22 | } 23 | ``` 24 | 25 | 括号中表达式值为**真**,最后提示“true”。 26 | 27 | # 短路原则 28 | 29 | 在逻辑运算中,这是一个通用的原则,这是由于表达式从左到右执行的特性,为了减少运算量而给运算器规定的操作。主要针对 `&&` 和 `||` 两种运算。 30 | 31 | * `&&` 的判断是**同真为真,一假为假**,则运算如果左边的表达式值为 `false`,那么就不会再执行右边的表达式了,如果左表达式为 `true`,就会继续执行右表达式; 32 | 33 | * `||` 的判断是**一真为真,同假为假**,则运算如果坐表达式值为 `true`,那么就不用执行右边的表达式了,如果左表达式为 `false`,就会继续执行右表达式; 34 | 35 | 举例说明: 36 | 37 | ``` js 38 | (1 == 1) && alert("msg1"); 39 | (1 != 1) && alert("msg2"); 40 | (1 == 1) || alert("msg3"); 41 | (1 != 1) || alert("msg4"); 42 | ``` 43 | 44 | 结果是提示**“msg1”**和**“msg4”**。原理如上述。 45 | 46 | 因此,如果有以下表达式: 47 | 48 | ``` js 49 | var a = 9; 50 | if (a > 0) 51 | { 52 | alert("true"); 53 | } else 54 | { 55 | alert("false"); 56 | } 57 | ``` 58 | 59 | 也许你会使用**三目运算**简化成这样: 60 | 61 | ``` js 62 | var a = 9; 63 | (a > 0) ? alert("true") : alert("false"); 64 | ``` 65 | 66 | 其实也可以这样写: 67 | 68 | ``` js 69 | var a = 9; 70 | (a > 0) && alert("true"); 71 | (a > 0) || alert("false"); 72 | ``` 73 | 74 | # Javascript中的应用 75 | 76 | 在javascript中,只有`对象(Object)`和布尔值`true`为真,其它例如 `undefined`, `NaN`, `false` 等,值为 `false`。为被定义的对象或未赋值变量也是 `false`,因为其值都是 `undefined`,这里就可以应用于检查某变量是否**已定义**。 77 | 78 | 举例说明: 79 | 80 | ``` js 81 | var a = 1; 82 | var o = new Object(); 83 | var b; 84 | a && alert("defined"); //已定义a,提示“defined” 85 | o && alert("defined"); //已定义对象o,提示“defined” 86 | Object && alert("defined"); //Object是一个已知的全局对象,提示“defined” 87 | b || alert("not defined"); //b未赋值,提示“not defined” 88 | p || alert("not defined"); //未定义p,提示“not defined” 89 | ``` 90 | 91 | 除了这个也能衍生出其它相同原理的应用,类似于判断赋值 `var a = (b > 0) && '9'` 或判断定义变量 `var abc = abc || ""` 等。 92 | 93 | js中使用这种方法可以减少代码量,提示性能,但同时也降低了代码**可读性**,比如个人觉得还是看以下代码比较舒适: 94 | 95 | ``` js 96 | var a = 1; 97 | if (a > 1) 98 | { 99 | alert("true"); 100 | } 101 | ``` 102 | 103 | 方法的选择就要视情况而权衡了。 -------------------------------------------------------------------------------- /_posts/2018-11-25-discuz-website.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 搭建个人论坛网站图文教程 3 | layout: post 4 | categories: 网站 5 | tags: 建站 论坛 discuz 6 | excerpt: 关于 discuz 论坛网站的详细图文搭建教程 7 | --- 8 | # 关于建站 9 | 前面的文章介绍过如何使用Github Pages提供的仓库服务搭建Jekyll个人博客,链接在这 [https://knightyun.github.io/2018/04/01/github-pages-blog](https://knightyun.github.io/2018/04/01/github-pages-blog),现在来了解一下如何一步步搭建自己的论坛网站。 10 | 11 | 搭建个人论坛网站,也相当于建站的一种,通常的套路便是**域名+主机空间+网页源码程序**,网页文件上传到虚拟空间,一般这些空间都安装有网站所需环境,如PHP和数据库等,然后把域名和主机空间绑定,这样就能在浏览器中输入域名(网址)访问所建网页,不然理论上只能通过虚拟主机的IP访问,但是通常有**IP访问限制**不允许你这么做。 12 | 13 | 域名和主机空间可以在各大网站市场购买,通常是按年或按月付费,如阿里云和华为云。这里说一个需要**注意**的东西,产品列表中的**虚拟空间、虚拟主机**这类产品,指的是云服务器分配出的一部分磁盘空间,也叫网站空间,即只能通过服务商提供的控制面板进行访问控制,上传或者下载网页文件;而**云服务器、云主机**这类名称指的是有独立操作系统的服务器,可理解为一台可远程桌面控制访问的-云电脑。当然他们也能通过价格区分,一般情况,域名几十块每年,空间几百每年,主机几千每年,更高级的企业级服务就更贵了-_-。 14 | 15 | # 关于论坛 16 | 能力强大的大佬可以自己编写网页和程序文件上传到主机空间,普通选手一般选择使用一些开源的网站源码,网上能找到很多,懂一些网页基础的也可以后期修改一些内部样式效果。 17 | 18 | 这里我们使用**Discuz**提供的论坛建设服务,相当于让你下载一份网站源码压缩包,解压后上传到自己的网页空间,然后安装他们的程序。先看一下其[官网](http://www.comsenz.com/)的简介: 19 | 20 | ![Image Title](https://i.loli.net/2018/11/25/5bfa5a2311d32.png) 21 | 22 | 他们提供的服务还是不错的,这个源码也是免费下载的,当然也有其他付费服务可以自行了解,下面是他们提供服务的企业,看样子还是很厉害的: 23 | 24 | ![Image Title](https://i.loli.net/2018/11/25/5bfa5b4142af4.png) 25 | 26 | # 开始安装 27 | 首先到其官网[下载页面](http://www.comsenz.com/downloads/install/discuzx#down_open),然后选择下载的版本,我们这里选择简体UTF-8,点击下载等待完成: 28 | 29 | ![Image Title](https://i.loli.net/2018/11/25/5bfa5f33e7571.png) 30 | 31 | 也可以到其[官方论坛](http://www.discuz.net/forum.php)了解,版本更新就在这里发布,我们去其官方gitee,点击[下载页面](https://gitee.com/ComsenzDiscuz/DiscuzX)下载: 32 | 33 | ![Image Title](https://i.loli.net/2018/11/25/5bfa872216ff4.png) 34 | 35 | 如图所示下载zip压缩文件即可。由于作者使用最上面那个下载页面的压缩文件测试不成功,因此使用这个下载页面的压缩包。 36 | 37 | 解压后进入**upload**文件夹,其他都是一些说明性文档,可以自行了解一下: 38 | 39 | ![Image Title](https://i.loli.net/2018/11/25/5bfa609973982.png) 40 | 41 | 然后把upload目录下的所有文件复制到自己购买的空间的网页根目录下,一般是wwwroot这类名字,可以在里面新建一个文件夹例如**discuz**,然后拷贝到这个文件目录里面,这样就不妨碍以后用虚拟空间制作其他网页。 42 | 43 | ![Image Title](https://i.loli.net/2018/11/25/5bfa630914816.png) 44 | 45 | 其主要文件大概就这些,我这里用自己的虚拟机建设的网站做演示,大家就上传到自己虚拟空间目录下,然后在自己电脑浏览器输入绑定的域名进行访问,关于如何绑定域名,很简单并且网上教程很多,自行了解。我自己电脑作为服务器因此网址如图所示,如果域名为`test.com`,并且上面提到的所有文件保存在`discuz·里面,那么访问网址就输入`test.com/discuz/`,然后进入安装页面: 46 | 47 | ![Image Title](https://i.loli.net/2018/11/25/5bfa838094975.png) 48 | 49 | 然后点同意,下一步,进入如下页面,选择**全新安装**: 50 | 51 | ![Image Title](https://i.loli.net/2018/11/25/5bfa8b39abfe0.png) 52 | 53 | 设置数据库,数据库名,用户名,密码,一般买虚拟空间有送一个数据库,没有的话就单独买一个数据库服务器,把地址改一下就行了,邮箱填常用的,用于发送错误报告: 54 | 55 | ![Image Title](https://i.loli.net/2018/11/25/5bfa8c222e37b.png) 56 | 57 | 等待页面安装完成,就能点击访问了: 58 | 59 | ![Image Title](https://i.loli.net/2018/11/25/5bfa8e647689c.png) 60 | 61 | 那些推荐应用可以暂时不管,以后还能安装,直接点击右下方访问,看看效果: 62 | 63 | ![Image Title](https://i.loli.net/2018/11/25/5bfa9f083d437.png) 64 | 65 | 右上方是用户注册和登录的地方,管理员就用刚才安装页面设置那个账号和密码,就是**admin**那个。点击右上方**模块管理,管理中心**就可以进入后台管理一个内容和功能了,会再次验证密码,还是刚才那个。 66 | 67 | ![Image Title](https://i.loli.net/2018/11/25/5bfaa02b2a22d.png) 68 | 69 | 整个系统比较庞大,功能模块也相当多,有时间多多摸索一下就能熟练管理了。 -------------------------------------------------------------------------------- /_posts/2018-12-08-ssd.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 电脑固态硬盘接口辨析 3 | layout: post 4 | categories: 系统 5 | tags: 固态硬盘 SSD SATA M.2 6 | excerpt: 介绍电脑不同接口的固态硬盘的区别 7 | --- 8 | 固态硬盘相比传统机械硬盘读写速度快许多,固态硬盘目前分为M.2接口与SATA接口。 9 | 10 | # SATA接口 11 | 12 | SATA(Serial ATA,Serial Advanced Technology Attachment,串行高级技术附件),一种硬盘接口规范。 13 | 14 | SATA3是目前大多数笔记本使用的接口规范版本,尺寸比msata大一些,有个硬壳盒包装; 15 | 16 | 如下图,就是笔记本上取下的固态: 17 | 18 | ![sata_one](https://i.loli.net/2018/12/08/5c0b60b71fa9c.jpg) 19 | ![sata_two](https://i.loli.net/2018/12/08/5c0b60ae9c878.jpg) 20 | 21 | PCI-E(PCI Express)新一代总线接口,取代PCI总线接口,称为第三代I/O总线技术,提高了带宽,PCI Express的接口根据总线位宽不同而有所差异,包括x1、x4、x8以及x16(x2)模式将用于内部接口而非插槽模式。 22 | 23 | **PCI-E传输速度大于SATA。** 24 | 25 | # M.2接口 26 | 27 | M.2是intel推出替代mSATA(mini-SATA,小尺寸SATA规范接口,多应用于笔记本固态硬盘接口)的新接口规范,尺寸更小,传输性能更高,为满足超级本用户而推出; 28 | 29 | M.2接口有两种类型:Socket 2(ngff)和Socket 3(nvme),Socket2支持SATA、PCI-E X2接口,PCI-E ×2接口标准,最大的读取速度可以达到700MB/s,写入达到550MB/s。Socket 3可支持PCI-E ×4接口,理论带宽达4GB/s。 30 | 31 | NVME(Non-Volatile Memory express,非易失性内存主机控制器接口规范),充分利用PCIE通道的低延时和并行性,降低AHCI的高延时和提高SATA的性能; 32 | 33 | - NVME缺口靠右边,使用一缺固态; 34 | 35 | ![m.2_1](https://i.loli.net/2018/12/08/5c0b60b31adf5.jpg) 36 | ![m.2_0](https://i.loli.net/2018/12/08/5c0b60b4589e0.jpg) 37 | 38 | - NGFF缺口靠左边,使用两缺m.2固态; 39 | 40 | ![c3fb1290842eb6f7.jpg](https://i.loli.net/2018/12/08/5c0bbc1207a8b.jpg) 41 | 42 | 购买更换时需要注意主板插槽上缺口靠哪边,一般安装是固态条元器件面朝上。 43 | 44 | 并且,不要把它和内存条搞混,区别在于接口位置。 -------------------------------------------------------------------------------- /_posts/2019-01-27-ascii-unicode.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: UTF-8, ASCII, Unicode 的介绍与区分 3 | layout: post 4 | categories: 编程 5 | tags: utf-8 ascii unicode 6 | excerpt: 关于 UTF-8,ASCII,Unicode 的介绍与区分 7 | --- 8 | # 背景 9 | 10 | 人类能通过肉眼识别文字和字符,并能通过知识了解他们的含义,但是计算机内部不论存储还是控制,都是通过二进制码实现,因为二进制的 `0`, `1` 刚好对应基础电路中的**开**和**关**,然后组合进行复杂的系统控制; 11 | 12 | 将人类识别的字符转换成计算机识别的二进制数据的过程,叫做**编码**,顾名思义,编程二进制数字码,如 `0101101100011001`这样的;相反,就叫做**解码**,把二进制码解释为字符; 13 | 14 | # ASCII 15 | 16 | 首先ASCII全称(American Standard Code for Information Interchange,美国信息交换标准代码),是一个**字符集**,顾名思义,很多字符的集合; 17 | 18 | 像前面提到的,人类与计算机语言不通,一个识别字符,一个识别二进制,所以**ASCII**就充当了这样一个**翻译官**,其内容是编码与字符的映射,即一个字符只对应一个固定的编码,例如字符 `A` 的编码为 `65`,字符 `a` 的编码为 `122`;当然这个编码是**十进制**的,计算机内部把十进制转换成二进制就能供底层使用了; 19 | 20 | 另外需要知道的是,一字节(1 Byte)等于八比特位(8 bit),8 bit就是这样的:`01010101`,八位二进制的所有不同表示一共 **2^8 = 256** 个,而且一般都是从 **0** 开始数,所以表示的十进制数的范围就是 **0 - 255**,这也是ASCII编码映射字符数的范围,包含大小写字母和一些其他常用的符号; 21 | 22 | # Unicode 23 | 24 | 看完上面肯定就会疑惑ASCII总共才表示256个字符,怎么处理当今世界巨大的信息量的,由于这个字符集最初是老外发明的,表示所有字母和一些字符对他们当时来说可能很足够了,但是先进计算机遍布全球大部分地方,汉语、韩语、日语、阿拉伯语等语言数不过来,所以ASCII明显不够用了;虽然中国之前也制定了是和中文的编码字符集叫 **GB2313** 等系列; 25 | 26 | 因此,便顺应时代需要产生了一种更庞大的字符集叫 **Unicode**,有时也叫**万国码**,顾名思义,几乎表示了世界上所有语言的字符,可以理解为 `Unique code`,独一无二的的编码; 27 | 28 | 目前Unicode的编码范围达到了**21位**,即 `0x0000 - 0x10ffff` 的范围,二进制为 `1 0000 1111 1111 1111 1111`,刚好21位;十进制表示为 `1114111`,就是一百万多个字符,已经相当多了; 29 | 30 | 如果要使用UNIcode,以在 **HTML** 中为例,假如知道一个字符的Unicode码是 `0x0394`,那么就在标签中添加代码: 31 | ```html 32 | Δ 33 | ``` 34 | 35 | 放在标签中就是: 36 | ```html 37 |
这个Unicode码对应的字符是:Δ
38 | ``` 39 | 40 | 结果是这样: 41 | 42 | >
这个Unicode码对应的字符是:Δ
43 | 44 | 其实那个Unicode编码就是对应的大小希腊字母德尔塔,数学或物理中经常用到的字符; 45 | 46 | 也可以用 JavaScript 来遍历一部分Unicode与字符的对应关系: 47 | ```js 48 | for (i = 0x0000; i <= 0x00ff; i++) { 49 | document.write(i + ': &#x' + i + ';
'); 50 | } 51 | ``` 52 | 53 | 页面就会出现前256个字符及其Unicode码; 54 | 55 | # UTF-8, UTF-16, UTF-32 56 | 57 | 首先UTF全称(Unicode Transformation Format),所以它是一种针对前面提到的Unicode的**编码格式**,常见的格式就是 **UTF-8**,还有 `UTF-16`, `UTF-32`; 58 | 59 | UTF-8 其中的 `8` 表示的是 `8 bit`,即Unicode中每8位表示一个字符,UTF-16 和 UTF-32 类似,因为Unicode最多才21位,32位大于21位,所以 UTF-32 的格式就可以表示所有字符对应的Unicode码了,但是呢,32位也就是**4字节**,让每个字符都占用4字节太费空间了,所以出现了**UTF-8**和**UTF-16**; 60 | 61 | UTF-8 定义 `0 - 7 bit` 的 Unicode 用一字节表示,这里就与**ASCII**一样了,`8 - 11 bit` 用两字节表示,`12 - 16 bit` 用三字节表示,`17 - 21 bit` 用四字节表示; 62 | 63 | UTF-8 编码规则如下: 64 | 69 | | Unicode | bit | UTF-8 | byte | 70 | |:---------------:|:------:|:----------|:--------:| 71 | | 0x0000 - 0x007f | 0 - 7 | 0XXX XXXX | 1 | 72 | | 0x0080 - 0x07ff | 8 - 11 | 110X XXXX 10XX XXXX | 2 | 73 | | 0x0800 - 0xffff | 12 - 16 | 1110 XXXX 10XX XXXX 10XX XXXX | 3 | 74 | |0x1 0000 - 0x1f ffff|17 - 21|1111 0XXX 10XX XXXX 10XX XXXX 10XX XXXX|4| 75 | 76 | 规律是: 77 | - 每个字节中不足8位的,高位(左边)先用0补上,比如 `0XXXX XXXX`; 78 | - 超过两字节表示的UTF-8,第一个字节高位添加两个 `1` 和一个 `0`,后面的字节高位添加 `10`; 79 | - 三、四字节同理,几个字节高位就添几个 `1` 再加上一个 `0`,其余字节高位添 `10`; 80 | 81 | 可以看出 UTF-8 这种针对不同位数使用不同字节数编码的方式有效的利用了空间,避免了一些浪费,当然,事物都有利弊,空间降下去,时间也就升上去了; -------------------------------------------------------------------------------- /_posts/2019-01-27-css-px.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CSS 单位与尺寸参数 3 | layout: post 4 | categories: CSS 5 | tags: css单位 px dpi dpr 逻辑像素 6 | excerpt: 对 CSS 中涉及的一些单位与参数的介绍 7 | --- 8 | # css单位 9 | 10 | ## px 11 | 常用的单位,即像素pixel缩写,但通常被当做绝对单位,但严格说并不是,因为官方考虑到观看不同设备显示屏时,使网页设计出的某一图形的显示大小在人眼中的观看效果差不多,而定义的一个相对值,即人以一臂之遥观看96DPI的显示屏的角度,大概就是利用透视的近大远小原理,照顾不同设备的最终观看效果。 12 | 13 | 比如某网页图形设置为一固定的px值,在手机浏览器上显示是用直尺测大概1cm,但是同样在不缩放情况下,电脑显示屏测量可能就是1.5cm左右,如果是打印机打印出来的话也许就是2cm左右了。 14 | 15 | ## em 16 | 常用的相对单位,前面的数字是比例,即相对于**父元素**的字体尺寸的比例,比如父元素字体16px,子元素设置1em,也可以理解为100%,那么子元素也是16px,同样,2em就是200%,32px,也可以是小数0.2em,1.5em等等。 17 | 18 | ## rem 19 | 类似于em,但rem是相对于**根元素html**,例如用css标签选择器给html标签设置字体尺寸font-size大小为20px,那么文档中的每个1rem就代表20px,1.5em代表30px,以此类推。 20 | 21 | ## in,cm,mm 22 | 这些虽然是生活中的物体测量单位,但网页的1cm尺寸的元素显示到显示器上,用直尺测量通常不是标准1cm,因为css已经默认设置1in=96px,前面也讲过px会因显示屏而不同,因此最终尺寸也不是绝对的,其他也差不多,所以这类尺寸很少用。 23 | 24 | 尺寸比较: 25 | 26 | ![size](https://i.loli.net/2019/01/26/5c4c2fdf10206.png) 27 | 28 | # 显示原理 29 | 30 | ## dpi, ppi 31 | dpi(dot per inch),即每英寸多少点,是针对打印机的一个概念,点可以理解为墨点; 32 | 33 | ppi(pixel per inch),即每英寸多少像素,是针对显示器的概念,开发中一般关心显示器问题,所以一般认为`dpi`和`ppi`是同一个概念; 34 | 35 | ## dpr 36 | dpr(device pixel ratio),即物理像素与独立像素的比例; 37 | 38 | - 物理像素 39 | 40 | **物理像素**也叫**设备像素**,屏幕显示图像都是由很多个像素点组成,屏幕出厂时本身带的点阵数就是它的物理像素; 41 | 42 | - 独立像素 43 | 44 | 而**独立像素**,又叫**逻辑像素**,或者**css像素**,顾名思义,逻辑嘛,当然是独立于物理的概念,大小没有固定实际值,也是前面提到的css里面的`1px`; 45 | 46 | 逻辑像素可以通过js代码获取,`screen.width`获取逻辑像素宽度,`screen.height`是高度;至于`dpr`,可以通过`devicePixelRatio`这个全局属性获取,现在的新一些的安卓智能手机一般这个比例是**3**,电脑的一般是**1**,iphone、iPad一般是**2**; 47 | 48 | **注意**,dpr为**1**,说明一个css像素块由`1x1`个物理像素块来显示,也就是一个物理像素,如果为**2**,则是一个css像素由`2x2`个物理像素来显示,也就是**4**个像素块,以此类推;这里也就能明白了,dpr的存在就是为了是小尺寸设备屏幕显示出高画质图形,细节更高就更清晰了; 49 | 50 | 现在来说设备像素的获取,并没有直接的获取方法,所以可以通过**dpr乘以逻辑像素的方法获取**; 51 | 52 | 综合举例: 53 | ```js 54 | var logicWidth = screen.width; 55 | var logicHeight = screen.height; 56 | var dpr = devicePixelRatio; 57 | var deviceWidth = logicWidth * dpr; 58 | var deviceHeight = logicHeight * dpr; 59 | // 输出逻辑像素 60 | console.log('逻辑像素:' + logicWidth + 'x' + logicHeight); 61 | // 输出设备像素 62 | console.log('物理像素:' + deviceWidth + 'x' + deviceHeight); 63 | ``` -------------------------------------------------------------------------------- /_posts/2019-01-27-css-transition-animation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CSS3 过渡与动画 3 | layout: post 4 | categories: CSS 5 | tags: css3过渡 css3动画 transition animation 6 | excerpt: CSS3 中的过渡与动画效果的介绍 7 | --- 8 | CSS3中出现很多新的特性,下面就讲一下其中比较好玩的**3D操作**,**过渡**和**动画**效果; 9 | 10 | # 过渡(transition) 11 | 过渡就是使瞬间的样式变化,按照一定方式变得缓慢平缓; 12 | 13 | 例如鼠标划过超链接时颜色的变化,点击按钮后的颜色变化等,默认转化都是瞬间完成,可能你已经习惯了这种变换,但有时候平缓一些看着还是比较舒适的; 14 | 15 | 要实现样式的过渡变化,那么首先就学要有**样式变换**,例如鼠标划过,单击按钮,点击图片等操作,来实现颜色,尺寸,位置等样式的变化; 16 | 17 | 下面是鼠标划过段落使文本变红的操作,应用所有 `transition`属性: 18 | ```css 19 | p:hover { 20 | color: red; 21 | } 22 | p { 23 | transition-property: color; 24 | transition-duration: 2s; 25 | transition-timing-function: linear; 26 | transition-delay: 0; 27 | } 28 | ``` 29 | 30 | ![image](https://i.loli.net/2019/01/26/5c4c3488ab322.gif) 31 | 32 | 一共四个值,功能基本都是字面翻译的意思: 33 | - **transition-property** 34 | 35 | 执行过渡的属性,例子设置为颜色color的变化,也可以是width, font-size等,不设置的话默认是`all`,即所有属性; 36 | 37 | - **transition-duration** 38 | 39 | 过渡的时间,单位是秒,如1s, 2.3s,不设置的话默认 `0s`,即无过渡效果; 40 | 41 | - **transition-timing-function** 42 | 43 | 设置过渡时的变化方式,默认是 `ease`,即速度由慢到快再到慢,常用的还有 `linear`,线性变化速度均匀,还有其他几个方式,过渡时间短的话看不出什么区别; 44 | 45 | - **transition-delay** 46 | 47 | 延迟时间,即多少秒后执行过渡效果,默认 `0s`,不延迟; 48 | 49 | 当然这么多单词可能记不住,一般使用快捷写法: 50 | ```css 51 | p { 52 | transition: color 2s linear 0; 53 | } 54 | /*最少要指定过渡时间*/ 55 | p { 56 | transition: 2s; 57 | } 58 | ``` 59 | 60 | 也可以设置每个样式分别过渡,例如: 61 | ```css 62 | p { 63 | transition: color 2s linear, 64 | font-size .5s, 65 | background: 1s; 66 | } 67 | ``` 68 | 69 | 每个样式过渡之间用**逗号**隔开就行了; 70 | 71 | 最后,由于是新特性,为了兼容性需要加上浏览器厂商前缀: 72 | ```css 73 | p { 74 | transition: 2s; 75 | -webkit-transition: 2s; 76 | -moz-transition: 2s; 77 | -ms-transition: 2s; 78 | -o-transition: 2s; 79 | } 80 | ``` 81 | 82 | # 动画(animation) 83 | CSS3的动画是个很不错的技术,基本能取代一些动图,javascript,flash等; 84 | 85 | 而动画里最重要的概念就是**关键帧**,也许你用PS做gif动图的时候看见过这个概念,所谓动画就是一帧一帧图片连续切换实现的效果,关键帧就是里面主要的一些帧; 86 | 87 | 实现CSS动画也需要设置关键帧 `@keyframes`: 88 | ```css 89 | @keyframes my-animation { 90 | 0% { 91 | color: red; 92 | } 93 | 50% { 94 | color: green; 95 | } 96 | 100% { 97 | color: blue; 98 | } 99 | } 100 | ``` 101 | 102 | 格式如上,@keyframes后面跟的是自定义的**动画名称**,后面会用到。里面的**0%,50%,100%**便是设置的三个关键帧及其对应样式,如果只需要设置首尾两个关键帧,可以这样写: 103 | ```css 104 | @keyframes my-animation { 105 | from { 106 | color: green; 107 | } 108 | to { 109 | color: blue; 110 | } 111 | } 112 | ``` 113 | 114 | 效果: 115 | 116 | ![image](https://i.loli.net/2019/01/26/5c4c4eae8329a.gif) 117 | 118 | 当然样式除了color还能设置多项样式; 119 | 120 | 定义好关键帧后就直接在需要应用动画的元素标签内使用就行了,格式及所有属性如下: 121 | ``` 122 | p { 123 | animation-name: my-animation; 124 | animation-duration: 3s; 125 | animation-timing-function: ease; 126 | animation-delay: 0; 127 | animation-iteration-count: 3; 128 | animation-direction: normal; 129 | animation-play-state: running; 130 | } 131 | ``` 132 | 133 | 发现了吧,很多属性和**transition**里面一样,简单介绍下: 134 | 135 | - **animation-name** 136 | 137 | 就是之前跟在@keyframea后面的自定义名称,之前设置的是 `my-animation`; 138 | 139 | - **animation-duration** 140 | - **animation-timing-function** 141 | - **animation-delay** 142 | 143 | 和前面一样,默认分别为 `0, ease, 0`; 144 | 145 | - **animation-iteration-count** 146 | 147 | 动画播放的次数,默认 `1`,但一般设置为 `infinite`,即无限循环; 148 | 149 | - **animation-direction** 150 | 151 | 动画播放的方向,`normal`为默认,正向播放,`reverse`为反向播放,`alternate`为正向后反向,`alternate-reverse`为反向后正向; 152 | 153 | - **animation-play-state** 154 | 155 | 播放状态,默认 `running`,运行,`paused`为暂停,可以在javascript中使用对动画进行控制; 156 | 157 | 当然,这个属性比之前的transition还多,也有简便写法: 158 | ```css 159 | p { 160 | animation: my-animation 3s linear infinite alternate; 161 | } 162 | ``` 163 | 164 | 其中 `animation-name` 和 `animation-duration`为必须设置的属性; 165 | 166 | 同样,记得考虑浏览器兼容: 167 | ```css 168 | @-webkit-keyframes mycanimation { 169 | from { 170 | color: green; 171 | } 172 | to { 173 | color: blue; 174 | } 175 | } 176 | p { 177 | -webkit-animation: my-animation 3s linear infinite; 178 | } 179 | /* -moz-, -ms-, -o- 格式类似 */ 180 | ``` -------------------------------------------------------------------------------- /_posts/2019-01-27-css-webkit.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: css 属性前浏览器厂商前缀 3 | layout: post 4 | categories: CSS 5 | tags: 浏览器兼容 css前缀 6 | excerpt: CSS 属性中浏览器厂商前缀的介绍 7 | --- 8 | CSS3中一些新功能也是目前导致各大浏览器不兼容的一个原因,这些新功能的出现,浏览器厂商们变便开始尝试融合、试验,所以就在这些功能前加上自己的特定前缀来执行自己的特定解决方法,为了让这些功能能在完全确认下来前使用; 9 | 10 | 下面就是我们经常用到的前缀及其兼容浏览器: 11 | 12 | ## -webkit- 13 | Apple Webkit团队,兼容Android, Safari, Chrome, BlackBerry等; 14 | 15 | ## -moz- 16 | Mozilla,兼容Firefox等; 17 | 18 | ## -ms- 19 | Microsoft基金会,兼容IE; 20 | 21 | ## -o- 22 | 兼容Opera, Opera Mini, Opera Mobile; 23 | 24 | 因此对于一些较新的css3特性,需要添加以上前缀兼容每个浏览器,例如实现线性渐变,标准写法是 `linear-gradient()`,但是一下浏览器还未完全确定这一特性,就在前面添加一个前缀来进行试验执行,如 `-webkit-linear-gradient`; 25 | 26 | 下面是开发中常用的兼容写法: 27 | ```css 28 | body { 29 | background: linear-gradient(0, green, blue); 30 | background: -webkit-linear-gradient(0, green, blue); 31 | background: -moz-linear-gradient(0, green, blue); 32 | background: -o-linear-gradient(0, green, blue); 33 | background: -ms-linear-gradient(0, green, blue); 34 | } 35 | ``` -------------------------------------------------------------------------------- /_posts/2019-01-27-js-iteration.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 深度迭代遍历未知对象 3 | layout: post 4 | categories: JavaScript 5 | tags: 迭代遍历 深度遍历 未知对象 6 | excerpt: 介绍 js 中对未知对象的遍历方法 7 | --- 8 | 面向对象编程的语言,都存在对对象的一些操作,其中就包括遍历未知对象的属性值。 9 | 10 | # 通常情况 11 | 12 | 常见的遍历对象的方法: 13 | ```js 14 | var o = { 15 | name: 'cloud', 16 | age: 20 17 | } 18 | for (i in o) { 19 | console.log(i + ': ' + o[i]); 20 | } 21 | // name: cloud 22 | // age: 20 23 | ``` 24 | 25 | # 特殊情况 26 | 27 | 但是对象中又含有子对象,对象的属性又是另一个对象,或者更深层嵌套,上面方法就不适用了; 28 | 29 | 下面使用**递归**实现这个功能: 30 | ```js 31 | var o = { 32 | name: { 33 | firstName: 'cloud', 34 | lastName: 'huang' 35 | }, 36 | age: 20 37 | } 38 | function myFn(obj) { 39 | for (i in obj) { 40 | console.log(i + ': ' + obj[i]); 41 | // 这里使用递归,属性类型为对象则进一步遍历 42 | if (typeof(obj[i]) == 'object') { 43 | myFn(obj[i]); 44 | } 45 | } 46 | } 47 | myFn(o); 48 | // 输出: 49 | // name: [object Object] 50 | // firstName: cloud 51 | // lastName: huang 52 | // age: 20 53 | ``` 54 | 55 | 这样的话不论对象有多复杂的结构都能全部遍历到位; 56 | 57 | # 困境 58 | 59 | 但同时,这也是个问题,一些对象层次非常深甚至是死循环的情况就尴尬了,类似于子对象属性与父对象属性一样,尝试用上诉函数遍历一下浏览器的`window` 对象就能体会了,你会后悔的; 60 | 61 | 所以为避免这种尴尬情况,设置一个**迭代深度值**吧,指定遍历到第几代: 62 | ```js 63 | var depth = 0; // depth为迭代深度值 64 | function myFn(obj) { 65 | for (i in obj) { 66 | console.log(i + ': ' + obj[i]); 67 | depth++; 68 | if (depth < 10 69 | && typeof(obj[i]) == 'object') { 70 | myFn(obj[i]); 71 | } 72 | } 73 | } 74 | ``` 75 | 76 | 或者使用一种类似**懒加载**的形式: 77 | ```js 78 | function myFn(obj) { 79 | for (i in obj) { 80 | console.log(i + ': ' + obj[i]); 81 | if (typeof(obj[i]) == 'object') { 82 | // 判断用户是否要继续迭代 83 | if (confirmFn('是否深入遍历?')) { 84 | myFn(obj[i]); 85 | } 86 | } 87 | } 88 | } 89 | ``` -------------------------------------------------------------------------------- /_posts/2019-01-27-linux-apt-lock.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Linux 中 apt install 的 lock 问题 3 | layout: post 4 | categories: Linux 5 | tags: apt-install-lock 6 | excerpt: apt install 过程遇到 lock 问题的解决方法 7 | --- 8 | 9 | Linux系统中有时执行 apt install 时,可能会显示以下问题: 10 | ```sh 11 | E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用) 12 | E: 无法锁定管理目录(/var/lib/dpkg/),是否有其他进程正占用它? 13 | ``` 14 | 15 | 根据提示分别找到对应的两个lock文件,移除即可; 16 | 17 | 解决方法: 18 | ```sh 19 | sudo rm /var/cache/apt/archives/lock 20 | sudo rm /var/lib/dpkg/lock 21 | ``` 22 | 23 | 再次运行就成功了。 -------------------------------------------------------------------------------- /_posts/2019-01-27-linux-umount.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Linux 强行取消挂载 3 | layout: post 4 | categories: Linux 5 | tags: linux挂载 6 | excerpt: linux 中遇到目录无法强行取消挂载情况的解决方法 7 | --- 8 | 9 | Linux系统有时需要取消挂载一些设备或者目录, 10 | 11 | 例如: 12 | ```sh 13 | # /dev/sdb挂载到了 /mnt/usb 14 | umount /mnt/usb 15 | ``` 16 | 17 | 但是多半会提示: 18 | ```sh 19 | umount: /mnt/usb: target is busy 20 | ``` 21 | 22 | 如果已 **备份** 了数据需要强行卸载,并且尝试 `umount -f /mnt/usb` 还是失败的情况 23 | 24 | 可以使用命令: 25 | ```sh 26 | fuser -cu /mnt/usb #查看挂载文件进程 27 | fuser -mv /dev/sdb #或者查看挂载点进程 28 | fuser -ck /mnt/usb #结束进程 29 | fuser -mk /dev/sdb #使用挂载点结束进程 30 | ``` 31 | 32 | 或者使用 **懒卸载** 方式,命令执行后系统会自动关闭相关进程后再卸载: 33 | ```sh 34 | umount -l /mnt/usb 35 | ``` -------------------------------------------------------------------------------- /_posts/2019-01-27-linux-xrandr.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kali Linux 自定义分辨率 3 | layout: post 4 | categories: Exploit 5 | tags: Linux分辨率 cvt xrandr 6 | excerpt: Linux 系统中自定义分辨率的方法 7 | --- 8 | Kali中无分辨率1920 x 1080,自定义的步骤: 9 | 10 | # 方法一 11 | 12 | 控制台输入: 13 | ```sh 14 | cvt 1920 1080 15 | ``` 16 | 17 | 会得到以下内容: 18 | ``` 19 | # 1920x1080 59.96 Hz (CVT 2.07M9) hsync: 67.16 kHz; pclk: 173.00 MHz 20 | Modeline "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync 21 | ``` 22 | 23 | 复制后面的内容,然后在新控制台输入: 24 | ``` 25 | sudo xrandr --newmode "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync 26 | ``` 27 | 28 | 然后再输入: 29 | ```sh 30 | sudo xrandr --addmode Virtual1 "1920x1080_60.00" 31 | ``` 32 | 33 | 最后系统设置选择分辨率或者: 34 | ```sh 35 | sudo xrandr --output Virtual1 --mode "1920x1080_60.00" 36 | ``` 37 | 38 | 但是此方法**重启会失效**,因此可以使用方法二; 39 | 40 | # 方法二 41 | 42 | 在 `/etc/profile` 文件末尾假如以下代码: 43 | ```sh 44 | xrandr --newmode "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync 45 | xrandr --addmode Virtual1 "1920x1080_60.00" 46 | ``` 47 | 48 | 重启完成。 -------------------------------------------------------------------------------- /_posts/2019-01-27-programming-paradigm.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 编程范式之命令式与函数式 3 | layout: post 4 | categories: 编程 5 | tags: 编程范式 函数式编程 命令式编程 6 | excerpt: 编程中的范式的介绍与区分 7 | --- 8 | 很多语言是**聚范式/多重范式**编程,即支持多在编程范式,如面向对象(Java),面向过程(C语言),泛函(函数式),元程序设计等;以下例子都用 **JavaScript** 举例; 9 | 10 | # 命令式编程(Imperative) 11 | 如命令一般指导程序一步步完成功能,如 for 循环: 12 | ```js 13 | function myFn(n) { 14 | for (i = 0; i < 3; i++) { 15 | n++; 16 | } 17 | console.log(n); 18 | } 19 | myFn(0); // 3 20 | ``` 21 | 22 | # 函数式编程/声明式(Functional/Declarative) 23 | 24 | **函数式编程特点:** 25 | - 函数式编程是声明式的; 26 | - 提倡纯函数理念,变量私有,不同于面向对象编程的成员共享; 27 | - 无副作用,不影响其他外部变量; 28 | - 有些类似初中数学纯函数f(x)的定义,提供输入值,返回新的输出值,每次提供相同输入值总能返回相同输出值,使线程安全可靠; 29 | 30 | ```js 31 | Array.map(); // 纯函数,输出唯一 32 | Math.random(); // 非纯函数,输出不唯一 33 | ``` 34 | 35 | - 函数的大量使用,变量中存储函数,动态创建函数,返回值为函数,函数作为参数传递,等等; 36 | 37 | ```js 38 | // 字符串通过函数储存在变量中 39 | var myStr = function(){return 'Hello World'}; 40 | console.log(myStr); // Hello World 41 | 42 | // 对象属性值储存为函数 43 | var myObj = { 44 | name: 'Cloud', 45 | getName: function(){ 46 | return this.name; 47 | } 48 | } 49 | console.log(myObj.getName()); // Cloud 50 | 51 | // 动态创建函数,用时调用,用完销毁 52 | console.log('Hello ' + (function(){ 53 | return 'World'; 54 | })()); // Hello World 55 | 56 | // 函数作为参数进行传递 57 | function paraFn() { 58 | return 'Hello'; 59 | } 60 | function myFn(a, b) { 61 | return a + b; 62 | } 63 | console.log(myFn(paraFn(), 'World')); // Hello World 64 | 65 | // 函数作为返回值 66 | function myFn2() { 67 | var a = 'Hello '; 68 | return function(){ 69 | return a + 'World'; 70 | } 71 | } 72 | console.log(myFn2()()); // Hello World 73 | ``` 74 | 75 | **总结:**例如for循环一个数组,命令式便是写出具体循环的方式,声明式便是只写声明函数,只要循环结果,具体方式交给程序执行; 76 | 77 | 例如: 78 | ```js 79 | // 命令式 80 | var a = [1, 2, 3]; 81 | var b = []; 82 | for (i = 0; i < 3; i++) { 83 | b.push(a[i] * a[i]); 84 | } 85 | console.log(b); // [1, 4, 9] 86 | 87 | // 声明式 88 | var a = [1, 2, 3]; 89 | var b = a.map(function(i){ 90 | return i * i; 91 | }); 92 | console.log(b); // [1, 4, 9] 93 | ``` 94 | 95 | 同样的结果,**代码量和理解难易**上,声明式都明显优于命令式对吧; 96 | 97 | **声明式编程:** 98 | 99 | 特点: 100 | - 说明想要实现的功能,让机器完成步骤以及如何实现; 101 | 102 | - 免去一些不必要的命令步骤,让思维集中在功能开发上,而不是冗长的复杂过程实现; 103 | 104 | 递归实现阶乘便是一个典型的函数式: 105 | ```js 106 | function factorial(n) { 107 | if (n == 0) return 1; 108 | return n * factorial(n-1); 109 | } 110 | console.log(factorial(3)); // 3 x 2 x 1 = 6 111 | ``` 112 | 113 | **.map() .reduce()**等 也是申明式编程函数; 114 | 115 | # 函数合成 116 | 一个值变成另一个值,中间经过多个函数,将多个函数合并为一个函数来实现; 117 | 118 | 举个例子: 119 | ``` 120 | // 高中数学常见的过程 121 | g(x) = 2x; 122 | h(x) = x + 3; 123 | f(x) = 2x + 3; 124 | // 则可变换为以下形式,即我们所学的复合函数 125 | f(x) = h(g(x)); 126 | ``` 127 | 128 | 上面的**f(x)**便是一个合成函数,实现了变量**x**到**2x + 3**的转变; 129 | 130 | js的实现: 131 | ```js 132 | function gFn(x) { 133 | return x *2; 134 | } 135 | function hFn(x) { 136 | return x + 3; 137 | } 138 | console.log(hFn(gFn(1))); // 5 139 | 140 | // 使用函数合成 141 | function fFn(x) { 142 | return hFn(gFn(x)); 143 | } 144 | console.log(fFn(1)); // 5 145 | ``` 146 | 147 | # 函数柯理化(Currying) 148 | 以逻辑学家***Haskell Curry***命名,即使接收多个参数的函数变成接受单个参数的函数的过程。单参数会使函数合成更简单; 149 | 150 | 例如: 151 | ```js 152 | // 原函数 153 | function plusFn(x, y, z) { 154 | return x + y + z; 155 | } 156 | console.log(plusFn(1, 2, 3)); // 6 157 | 158 | // 柯理化后 159 | function plusFn(x) { 160 | return function(y) { 161 | return function(z) { 162 | return x + y + z; 163 | } 164 | } 165 | } 166 | console.log(plusFn(1)(2)(3)); // 6 167 | ``` -------------------------------------------------------------------------------- /_posts/2019-05-01-js-call.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 之 call,bind,apply 方法及 this 的用法辨析 3 | layout: post 4 | categories: JavaScript 5 | tags: bind call apply this 6 | excerpt: JavaScript 中方法call, apply, bind 的区别 7 | --- 8 | # 概述 9 | 10 | JavaScript函数中的三个方法`.call()`, `.apply()`, `.bind()`,总体来说主要功能就是改变函数中 `this` 关键字的指向,因为 `this` 默认指向**当前环境的对象**; 11 | 12 | 例如: 13 | ```js 14 | var obj = { 15 | name: 'Knight', 16 | getName: function() { 17 | // this 指向 obj 对象 18 | console.log(this.name); 19 | } 20 | } 21 | obj.getName(); // 'Knight' 22 | ``` 23 | 24 | # call() 25 | 26 | `.call()` 可以用于改变 `this` 值的指向,例如: 27 | ```js 28 | this.name = 'Knight'; // 此处 this 指向全局对象 window; 29 | var obj = { 30 | name: 'Cloud' 31 | } 32 | function fn() { 33 | console.log(this.name); 34 | } 35 | 36 | fn(); // 'Knight' 37 | fn.call(obj); // 'Cloud' 38 | // 此处指向了 obj 对象,所以 name 变了 39 | ``` 40 | 41 | 也可以传递函数参数,平常调用函数的形式可能是这样: 42 | ```js 43 | function fn(a, b) { 44 | console.log(a + b); 45 | } 46 | 47 | fn(2 + 3); // 5 48 | ``` 49 | 50 | 现在也可以这样调用: 51 | ```js 52 | function fn(a, b) { 53 | console.log(a + n); 54 | } 55 | 56 | fn.call(null, 2, 3); // 5 57 | // 因为函数里没有用到 this, 58 | // 所以可以设置为 null 59 | ``` 60 | 61 | # apply() 62 | 63 | `.apply()` 与 `.call()` 类似,第一个参数也是用于改变 `this` 指向,区别就是 `apply()` 接受的函数参数是一个**数组**,例如: 64 | ```js 65 | function fn(a, b) { 66 | console.log('Mu name is ' + 67 | this.name + (a + b) + 68 | ' years old.'); 69 | } 70 | var obj = { 71 | name: 'Knight' 72 | } 73 | var arr = [2, 3]; 74 | 75 | fn.apply(obj, arr); 76 | // My name is Knight, 5 years old. 77 | 78 | // 使用 call() 的情况: 79 | fn.call(obj, 2, 3); 80 | // My name is Knight, 5 years old. 81 | ``` 82 | 83 | # bind() 84 | 85 | `.bind()` 也与 `.call()` 类似,改变 this 指向,传递函数参数,区别在于 `.bind()` 方法结果是创建一个新的 **绑定函数**,而之前的 `.call()` 和 `.apply()` 结果都是 **立即执行函数**,举例来理解: 86 | ```js 87 | var obj = { 88 | name: 'Knight' 89 | } 90 | function fn(a, b) { 91 | console.log('My name is ' + 92 | this.name + (a + b) + 93 | ' years old.'); 94 | } 95 | 96 | var fnn = fn.bind(obj, 2, 3); 97 | // fn.bind() 是一个函数,不会立即执行 98 | fnn(); 99 | // My name is Knight, 5 years old. 100 | 101 | fn.bind(obj, 2, 3)(); 102 | // 这种写法就是立即执行函数了, 103 | // 结果与上面一样; 104 | ``` 105 | 106 | # this 的困境 107 | 108 | 考虑以下情况: 109 | ```js 110 | function fn1() { 111 | function fn2() { 112 | console.log('fn2: ' + 113 | this); 114 | } 115 | fn2(); 116 | console.log('fn1: ' + this); 117 | } 118 | 119 | fn1.call('here'); // 'fn1: here' 120 | ``` 121 | 122 | 结果不会输出 `fn2: here`,因为函数定义 `fn2` 里的 `this` 是一个新的指向,并且未定义,与外部函数 `fn1` 中的 `this` 不同; 123 | 124 | 所以我们通常会进行一下处理: 125 | ```js 126 | function fn1() { 127 | function fn2() { 128 | console.log('fn2: ' + 129 | this); 130 | } 131 | 132 | // 对 this 进行转存 133 | var that = this; 134 | fn2.call(that); 135 | 136 | console.log('fn1: ' + 137 | this); 138 | } 139 | 140 | fn1.call('here'); 141 | /* 142 | fn2: here 143 | fn1: here 144 | */ 145 | ``` 146 | 147 | 当然,ES6中的**箭头函数**解决了上述问题: 148 | ```js 149 | function fn1() { 150 | var fn2 = () => { 151 | console.log('fn2: ' + this); 152 | } 153 | fn2(); 154 | fn2.call('there'); 155 | console.log('fn1: ' + this); 156 | } 157 | 158 | fn1.call('here'); 159 | /* 160 | fn2: here 161 | fn2: here 162 | fn1: here 163 | */ 164 | ``` 165 | 166 | 由于 `.call()` 方法对箭头函数不起作用,所以上面的第二行输出与第一行相同; -------------------------------------------------------------------------------- /_posts/2019-05-01-js-ecmascript-history.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ECMAScript 发展简史 3 | layout: post 4 | categories: JavaScript 5 | tags: es6 ECMAScript 6 | excerpt: ECMAScript 发展简史总结 7 | --- 8 | 9 | > ECMAScript,简称 ES,是 JavaScript 的标准版,经历了不同版本的变化; 10 | 11 | - 最初由于网速慢,网页验证表单需要通过服务器完成,因此Netscape(网景)公司决定开发这样一种用于处理验证的客户端语言; 12 | 13 | - 1995年,发布 LiveScript,由于当时 Java 很火,就顺便改名为 JavaScript 蹭热度,与 Netscape Navigator 2 一同发布,成为 JavaScript 1.0; 14 | 15 | - 1996年,JavaScript 1.1 与 Netscape Navigator 3 发布,同时微软也在 IE3 中加入 JScript(避免命名授权问题); 16 | 17 | - 1997年,ECMAScript 成为 JavaScript 的标准版本,标准命名为 ECMA-262,第一版为 ES1.0; 18 | 19 | - 1998年,ES2.0 发布; 20 | 21 | - 1999年,ES3.0 发布,标志其成为一门真正编程语言,成为JavaScript语法基础,即我们所学的 JavaScript; 22 | 23 | - 2000年,ES4.0 发布,新标准几乎是区别于ES3的新语言,所以由于激进未通过,激烈争论了几年。。。 24 | 25 | - 2008年,ES3.1 发布,作为 ES4.0 的替代方案,中止了 ES4.0的发布; 26 | 27 | - 2009年,ES3.1 作为第五版(ES5.0)正式发布; 28 | 29 | - 2011年,ES5.1 发布,成为国际标准; 30 | 31 | - 2015年,ES6 正式成为国际标准,又称 ES2015,也是指 ES5.1 后的下一代JavaScript标准; 32 | 33 | **总结:JavaScript = ECMAScript(核心) + DOM + BOM;** -------------------------------------------------------------------------------- /_posts/2019-05-01-js-sort.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 之常见算法排序 3 | layout: post 4 | categories: JavaScript 5 | tags: 算法排序 6 | excerpt: JavaScript 实现冒泡、选择、插入、快速、归并排序 7 | --- 8 | # 冒泡排序 9 | 10 | 冒泡排序即数组从头到尾,依次比较相邻两数的大小,不符合顺序则交换位置,一直循环直到排序完成。如果是升序排序,那么每一轮的一系列比较和交换之后,最大那个数一定会被排到最后(不信可以动手验证一下),可以理解为**冒泡**到最后,这样每一轮的最大那个数都冒到最后,所以每一轮需要比较的总数都在减少,直到剩一个数为止,序列就有序了,降序也是同样的道理; 11 | ```js 12 | // 输入值 _arr 为需要排序的数组,返回一个有序新数组 13 | function bubbleSort(_arr) { 14 | var arr = _arr.concat(); 15 | var len = arr.length; 16 | for (var i = len - 1; i > 0; i--) { 17 | for (var j = 0; j < i; j++) { 18 | if (arr[j] > arr[j + 1]) { 19 | let tmp = arr[j]; 20 | arr[j] = arr[j + 1]; 21 | arr[j + 1] = tmp; 22 | } 23 | } 24 | } 25 | return arr; 26 | } 27 | ``` 28 | 29 | # 选择排序 30 | 31 | 选择排序即从数组第一个数到倒数第二个数,分别与后面的数中的选出的最值(升序就是最小值)进行比较,满足条件(升序就是大于最小值)就交换位置,然后完成排序。这里可以理解为先**选择**出最小值,然后与前面的数进行比较和交换,就不用像冒泡那样挨个比较和交换了;另外,这里为了交换方便,记录的最值其实是该值在数组中的**索引**,而不是实际值; 32 | ```js 33 | function selectSort(_arr) { 34 | var arr = _arr.concat(); 35 | var len = arr.length; 36 | for (var i = 0; i < len - 1; i++) { 37 | var minIdx = i; 38 | for (var j = i + 1; j < len; j++) { 39 | if (arr[j] < arr[minIdx]) minIdx = j; 40 | } 41 | // 如果当前值已经是最小值,就可以不用交换, 42 | // 避免浪费时间 43 | if (minIdx !== i) { 44 | var tmp = arr[i]; 45 | arr[i] = arr[minIdx]; 46 | arr[minIdx] = tmp; 47 | } 48 | } 49 | return arr; 50 | } 51 | ``` 52 | 53 | # 插入排序 54 | 55 | 插入排序即从第二个到最后一个数,分别与排在前面的有序序列(第一轮该序列只有一个数,肯定是有序的,之后每一轮结束这个有序序列都会增加)中的每个数进行比较,然后**插入**合适的位置使其有序,直到最后一个数插入时完成排序; 56 | ```js 57 | function insertSort(_arr) { 58 | var arr = _arr.concat(); 59 | var len = arr.length; 60 | for (let i = 1; i < len; i++) { 61 | // 先将插入值(当前值)备份,方便后续插入操作 62 | let tmp = arr[i]; 63 | // 插入值在有序序列中从右向左比较 64 | for (let j = i; j > 0; j--) { 65 | // 下面就是“插入”操作的实现: 66 | // 如果插入值小于比较值(j-1),则将前面的数向后挪一位, 67 | // 这样就可以把被插入的空间留出来了,并且在不断向前移动 68 | if (tmp < arr[j - 1]) { 69 | arr[j] = arr[j - 1]; 70 | // 如果插入值大于或等于比较值,则把插入值放到这个比较值的后面 71 | // 也就是之前留出来的插入空间 72 | } else { 73 | arr[j] = tmp; 74 | break; 75 | } 76 | } 77 | } 78 | return arr; 79 | } 80 | ``` 81 | 82 | # 快速排序 83 | 84 | 快速排序在数组中任选一个数(下面选第一个数)作中间值,然后将余下的数分别与其比较,比中间值小则放到左边,否则放右边,然后再进行递归,将放在左边和右边的数组分别作为新数组进行同样的排序操作,直到数组不能再分,最后将所有排序结果合并;这里**快速**可以理解为整个操作过程相比于其他方法简单快捷,找好任一个中间值后便将剩下的数挨个放入其左或右,而不用管左右数组是否有序,直到递归完成就整体有序了,至于排序是否快速就要看情况了; 85 | ```js 86 | // 方法一: 87 | function quickSort(arr) { 88 | let len = arr.length; 89 | if (len < 2) { 90 | return arr; 91 | } else { 92 | let mid = arr[0], // 基准(中间值) 93 | left = [], // 放到基准左边的数 94 | right = []; // 放到基准右边的数 95 | for (let i = 1; i < len; i++) { 96 | if (arr[i] < mid) { 97 | left.push(arr[i]); 98 | } else { 99 | right.push(arr[i]); 100 | } 101 | } 102 | // 递归分割下去,不能分割时合并左中右数组返回 103 | return quickSort(left). 104 | concat(mid). 105 | concat(quickSort(right)); 106 | } 107 | } 108 | 109 | // 方法二: 110 | function quickSort(arr) { 111 | let len = arr.length; 112 | if (len < 2) { 113 | return arr; 114 | } else { 115 | let midIdx = 0; // 基准值的索引 116 | // 这里执行的就是把值放入基准左边还是右边的操作 117 | for (let i = 1; i < len; i++) { 118 | // 由于基准是第一个数,并且是从左向右遍历, 119 | // 所以后面的遍历值如果小于基准就先删除再 unshift 到最前面, 120 | // 这样就实现了“放到左边”, 121 | // 如果大于或等于基准就不用管,也就“放到右边”了; 122 | if (arr[i] < arr[midIdx]) { 123 | arr.unshift(arr.splice(i, 1)[0]); 124 | midIdx++; 125 | } 126 | } 127 | 128 | return quickSort(arr.slice(0, midIdx)). 129 | concat(arr[midIdx]). 130 | concat(quickSort(arr.slice(midIdx + 1))); 131 | } 132 | } 133 | 134 | // 经测试方法一比方法二快一些,数组越大相差倍数数量级也越大。 135 | // 显而易见方法一在空间上消耗不少,所以在时间上占优势; 136 | ``` 137 | 138 | # 归并排序 139 | 140 | 归并排序**递归**地将数组分割为两个部分(左数组与右数组),直到不能再分,然后再定义一个合并函数,负责**递归**地将两部分合并为一个有序数组作为返回值;合并函数其实会是合并两个有序的数组,合并方法便是分别将两数组第一个数取出(删除)放入返回数组中,至于两个数先放哪一个,可以通过比较大小来确定;所以这里的**归并**可以理解为递**归**地合**并**为一个有序序列; 141 | ```js 142 | function mergeSort(arr) { 143 | if (arr.length < 2) { 144 | // 不能再分时返回数组,执行之后的合并操作 145 | return arr; 146 | } else { 147 | // 将数组分割成两部分 148 | let mid = Math.ceil(arr.length / 2); 149 | let left = arr.slice(0, mid); 150 | let right = arr.slice(mid); 151 | // 递归地合并每次分割的左右数组 152 | return merge(mergeSort(left), mergeSort(right)); 153 | } 154 | } 155 | // 把左右数组合并为一个有序数组的函数 156 | function merge(left, right) { 157 | let result = []; 158 | let len = left.length + right.length; 159 | for (let i = 0; i < len; i++) { 160 | // 分割后左数组为空的情况 161 | if (!left[0]) { 162 | result.push(right.shift()); 163 | // 右数组为空 164 | } else if (!right[0]) { 165 | result.push(left.shift()); 166 | // 左右数组都不为空 167 | } else { 168 | // 较小的元素优先放入 169 | if (left[0] < right[0]) { 170 | result.push(left.shift()); 171 | } else { 172 | result.push(right.shift()); 173 | } 174 | } 175 | // 不存在左右数组都为空的情况,因为总循环次数为 len 176 | // 所以左右数组都空之前已经停止循环了 177 | } 178 | return result; 179 | } 180 | ``` -------------------------------------------------------------------------------- /_posts/2019-05-11-js-permutation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 实现元素全排列 3 | layout: post 4 | categories: JavaScript 5 | tags: 全排列 6 | excerpt: JavaScript 实现不同元素的全排列情况 7 | --- 8 | # 排列 (Permutation / Arrangement) 9 | 10 | ## 概念 11 | n 个不同元素中任意选取 m (m <= n) 个元素进行排列,所有排列情况的个数叫做 **排列数**,其值等于: 12 | ``` 13 | A = n! / (n - m)! 14 | ``` 15 | 16 | `!` 表示数学中的阶乘运算符,可以通过以下函数实现: 17 | ```js 18 | function factorial(n) { 19 | if (n === 0 || n === 1) { 20 | return 1; 21 | 22 | } else if (n < 0) { 23 | return null; 24 | 25 | } else { 26 | return n * factorial(n - 1); 27 | } 28 | } 29 | 30 | console.log(factorial(4)); // 24 31 | ``` 32 | 33 | 当 n = m 时,称为 **全排列**,其值等于: 34 | ``` 35 | A = n! 36 | ``` 37 | 38 | 全排列相当于将**所有元素**进行排序,得到所有不同顺序情况的个数; 39 | 40 | ## 分析 41 | 42 | 利用阶乘函数,通过上述数学公式只能得到所有情况的个数值,不容易得到具体的每种情况,要获取每种情况的输出值的话需要另寻他法; 43 | 44 | 用数组举例分析: 45 | ``` 46 | 全排列: 47 | 48 | [1, 2, 3] => [ 49 | [1, 2, 3], 50 | [1, 3, 2], 51 | [2, 1, 3], 52 | [2, 3, 1], 53 | [3, 1, 2], 54 | [3, 2, 1] 55 | ] 56 | 57 | 共 6 种情况 58 | 59 | 树状图表示: 60 | 61 | 1 2 3 62 | / \ / \ / \ 63 | 2 3 1 3 1 2 64 | | | | | | | 65 | 3 2 3 1 2 1 => 6 66 | 67 | 3 个元素中选取 2 个时:(n = 3, m = 2) 68 | 69 | [1, 2, 3] => [ 70 | [1, 2], 71 | [1, 3], 72 | [2, 1], 73 | [2, 3], 74 | [3, 1], 75 | [3, 2] 76 | ] 77 | 78 | 共 6 种情况 79 | 80 | 树状图表示: 81 | 82 | 1 2 3 83 | / \ / \ / \ 84 | 2 3 1 3 1 2 => 6 85 | 86 | ``` 87 | 88 | ## 实现 89 | 90 | ```js 91 | let arr = [1, 2, 3]; 92 | 93 | /* 94 | 参数 a 为输入数组, 95 | 元素个数 n 为 a 的长度, 96 | 选取个数为 m; 97 | */ 98 | function permutation(a, m) { 99 | 100 | // 保存最终输出结果 101 | let result = []; 102 | 103 | // 定义 m 值默认等于 n,即全排列 104 | let n = a.length; 105 | m = m || n; 106 | 107 | // 定义递归函数保存结果到数组中 108 | // _a 为输入数组, 109 | // tmpResult 为保存单个情况结果的数组 110 | function recur(_a, tmpResult = []) { 111 | if (tmpResult.length === m) { 112 | 113 | // 结果达到 m 个时保存结果, 114 | // 停止递归并进入下一次遍历 115 | result.push(tmpResult); 116 | 117 | } else { 118 | for (let i = 0; i < _a.length; i++) { 119 | 120 | // 复制一份输入数组,防止引用值被改变 121 | let tmpA = _a.concat(); 122 | 123 | // 复制一份保存结果的数组,防止每次遍历相互影响 124 | let _tmpResult = tmpResult.concat(); 125 | 126 | // 保存当前遍历值 127 | _tmpResult.push(tmpA[i]); 128 | 129 | // 删除当前遍历值,传递参数进入下一层递归 130 | tmpA.splice(i, 1); 131 | recur(tmpA, _tmpResult); 132 | } 133 | } 134 | } 135 | 136 | // 开始执行递归,然后返回最后结果 137 | recur(a); 138 | return result; 139 | } 140 | 141 | console.log(permutation(arr)); 142 | // 3 个数全排列: 143 | /* 144 | [ 145 | [1, 2, 3], 146 | [1, 3, 2], 147 | [2, 1, 3], 148 | [2, 3, 1], 149 | [3, 1, 2], 150 | [3, 2, 1] 151 | ] 152 | */ 153 | 154 | console.log(permutation(arr, 2)); 155 | // 3 个数中选取 2 个数排列: 156 | /* 157 | [ 158 | [1, 2], 159 | [1, 3], 160 | [2, 1], 161 | [2, 3], 162 | [3, 1], 163 | [3, 2] 164 | ] 165 | */ 166 | ``` 167 | 168 | 最终实现函数就是 `permutation(a, m)`,其中参数 `a` 为输入数组,包含需要排列的所有元素,参数 `m` 为选取需要排列的个数,默认等于输入数组的长度,即默认全排列,注意 `m` 不能大于元素个数; 169 | 170 | ## 拓展 171 | 172 | 以上函数输出值为一个二维数组,如果需要便于观察,输出一个一维数组,可以定义一个合并函数: 173 | ```js 174 | function merge(arr) { 175 | return arr.map(x => x.join('')); 176 | } 177 | 178 | let result = merge(permutation([1, 2, 3])); 179 | console.log(result); 180 | // [123, 132, 213, 231, 312, 321] 181 | ``` -------------------------------------------------------------------------------- /_posts/2019-06-20-sudo-nopasswd.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Linux 中 sudo 免密码 3 | layout: post 4 | categories: Linux 5 | tags: sudoers sudo 6 | excerpt: Linux 中执行 sudo 不用输入密码的方法 7 | --- 8 | 平时在 Linux 中执行一些命令时,可能会遇到 `Permission denied` 这样的提示,即该用户没有权限; 9 | 10 | 所以一般会想到在命令最前面加上 `sudo` 后再执行,然后有可能会提示输入当前用户的密码; 11 | 12 | 再接下来,如果命令没有正常执行,一般又会提示:`user is not in the sudoers file. This incident will be reported.`,即当前用户没有出现在这个叫 `sudoers` 的文件里面,那么这个文件在哪里呢? 13 | 14 | 一般在这个位置: 15 | 16 | /etc/sudoers 17 | 18 | 所以只需要把当前用户添加到这个文件就行了,执行 `su` 后根据提示输入 `root` 账户密码,切换到 root 用户,然后用 `vi /etc/sudoers` 或者 `visudo` 命令编辑该文件; 19 | 20 | 在里面可以找到这一行: 21 | 22 | root ALL=(ALL:ALL) ALL 23 | 24 | 大致意思是 root 用户具有所有权限,所以可以在下面加入这么一行: 25 | 26 | user ALL=(ALL:ALL) NOPASSWD:ALL 27 | 28 | 其中 `user` 是当前登录的用户名,这样以后使用该账户执行 `sudo` 就不用输入密码了; 29 | 30 | 如果存在多个账户,要让这些账户执行 `sudo` 时都不用输入密码的话,可以添加下面这行: 31 | 32 | %sudo ALL=(ALL:ALL) NOPASSWD:ALL 33 | 34 | 保存退出就 OK 了。 -------------------------------------------------------------------------------- /_posts/2019-08-02-js-sparse-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 稀疏数组 3 | layout: post 4 | categories: JavaScript 5 | tags: 稀疏数组 sparse 6 | excerpt: 关于JavaScript 中稀疏数组的介绍 7 | --- 8 | # 稀疏数组 9 | 10 | ## 概念 11 | 12 | 在一些后端语言中,如 C,数组内的值通常被分配在一系列连续的内存地址上,但是在 js 中,某些数组内存则不是连续的,所谓**稀疏**,顾名思义,不连续,存在一些空隙; 13 | 14 | 例如: 15 | ```js 16 | var arr = new Array(3); 17 | console.log(arr); 18 | // (3) [empty × 3] 19 | ``` 20 | 21 | 通过以上方法创建数组,其中 `Array(3)` 中的参数 3 表示数组的长度,这个数组就是稀疏的,控制台输出一般带有 `empty` 字样,或者像下面这样创建数组: 22 | 23 | ```js 24 | var arr = [1,,2]; 25 | console.log(arr); 26 | // (3) [1, empty, 2] 27 | ``` 28 | 29 | 因为定义语句中两个逗号之间无字符,没有定义值,同样带有 `empty` 字样,代表稀疏数组,这里可以把 `empty` 理解为上面讲到的 **空隙**; 30 | 31 | ## 特点 32 | 33 | 接下来看一下稀疏数组特殊在什么地方,举个例子说明: 34 | ```js 35 | var arr1 = [1, 2, 3]; // 正常数组 36 | var arr2 = new Array(3); // 稀疏数组 37 | var arr3 = [1, , 3]; // 稀疏数组 38 | 39 | console.log(arr1.length, arr2.length, arr3.length); 40 | // 3 3 3 41 | console.log(arr2[0], arr3[1]); 42 | // undefined undefined 43 | for (var i = 0; i < 3; i++) { 44 | console.log(arr1[i], arr2[i], arr3[i]); 45 | } 46 | // 1 undefined 1 47 | // 2 undefined undefined 48 | // 3 undefined 3 49 | arr1.forEach(function(x){ 50 | console.log(x); 51 | }); 52 | // 1 53 | // 2 54 | // 3 55 | arr2.forEach(function(x){ 56 | console.log(x); 57 | }); 58 | // (无输出) 59 | arr3.forEach(function(x){ 60 | console.log(x); 61 | }); 62 | // 1 63 | // 3 64 | console.log(0 in arr3, 1 in arr3); 65 | // true false 66 | ``` 67 | 68 | 总结一下,创建的稀疏数组,其长度(length)与定义长度值一致;**空隙** 值可以被单独访问到,并且不是之前出现的 `empty` 字样,而是 `undefined`,比如例子中出现 `undefined` 时都是使用 `arr[i]` 这样的索引直接访问方式;使用某些数组方法如 `forEach()` 时,会忽略掉空隙值,只处理正常值,所以也会使得 `1 in arr3` 值为 `false`,即数组中不存在该索引; 69 | 70 | 细想一下,js 这样处理的原因多半是去除不必要的性能开销,当数组相当大时,可以避免处理一些未初始化的值,但这样也同时使得开发中会出现一些问题,所以应尽量避免; 71 | 72 | 举个例子来查看一下性能如何: 73 | ```js 74 | console.time('one'); 75 | // 密集数组 76 | Array(...Array(1e5)).forEach(function(){ 77 | ; 78 | }); 79 | console.timeEnd('one'); 80 | 81 | console.time('two'); 82 | // 稀疏数组 83 | Array(1e5).forEach(function(){ 84 | ; 85 | }); 86 | console.timeEnd('two'); 87 | 88 | // one: 26.3759765625ms 89 | // two: 5.701171875ms 90 | ``` 91 | 92 | 可以看出在处理较大数组时,稀疏数组确实能降低不少性能开销; 93 | 94 | # 密集数组 95 | 96 | ## 概念 97 | 98 | 与稀疏相对应,则存在密集,定义也就是元素中不存在 **空隙** 值,其实密集数组基本就是平时常见的正常数组; 99 | 100 | 例如: 101 | ```js 102 | var arr1 = [1, 2, 3]; 103 | var arr2 = new Array(1, 2, 3); 104 | arr2.forEach(function(x){ 105 | console.log(x); 106 | }); 107 | // 1 108 | // 2 109 | // 3 110 | ``` 111 | 112 | 以上都是一些定义密集数组的方法,并且数组中的值都能被正常访问或遍历处理; 113 | 114 | ## 区别 115 | 116 | 运用时需要注意以下情况: 117 | ```js 118 | var arr1 = [undefined, undefined, undefined]; 119 | var arr2 = new Array(3); 120 | console.log(arr1[0], arr2[0]); 121 | // undefined undefined 122 | arr1.forEach(function(x){ 123 | console.log(x); 124 | }) 125 | // undefined 126 | // undefined 127 | // undefined 128 | arr2.forEach(function(x){ 129 | console.log(x); 130 | }) 131 | // (无输出) 132 | ``` 133 | 134 | 即显式的声明值为 `undefined` 并不代表这个值就是之前提到的**空隙**值,虽然二者通过索引访问时的值都返回 `undefined`,但是其根本还是有区别的,显式声明过的是可以被遍历等操作访问的,不会被当成空隙值被忽略; 135 | 136 | ## 拓展 137 | 138 | 通常在很多情况下,我们想要直接声明一个数组并赋予其一些特定的初始值,并且为了避免问题,通常是希望申明为密集数组的,下面就介绍一些常用的方法或技巧: 139 | ```js 140 | var arr1 = new Array(3).fill(1); 141 | console.log(arr1); 142 | // [1, 1, 1] 143 | 144 | var arr2 = Array.fill().map((x, i) => i); 145 | console.log(arr2); 146 | // [0, 1, 2] 147 | 148 | var arr3 = Array.apply(null, Array(3)); 149 | console.log(arr3); 150 | // [undefined, undefined, undefined] 151 | // 这样声明的是密集数组,不是稀疏的 152 | 153 | var arr4 = new Array(4).join('a').split(''); 154 | console.log(arr4); 155 | // ['a', 'a', 'a'] 156 | // 注意定义数组长度比输出数组大 1 157 | ``` 158 | 159 | 其它更多的方法可以自行类推; -------------------------------------------------------------------------------- /_posts/2019-09-02-js-febonacci.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 实现斐波那契数列(Febonacci Array) 3 | layout: post 4 | categories: JavaScript 5 | tags: 斐波那契 febonacci 6 | excerpt: 斐波那契数列的 JavaScript 实现 7 | --- 8 | 斐波那契(Febonacci)数列是一个神奇的数列,在很多地方都有应用,可以自行搜索相关图片体会其魅力,这里不赘述,直接来分析一下如何通过 JavaScript 来实现; 9 | 10 | # 概念 11 | 12 | 斐波那契数列形式如下: 13 | ``` 14 | 1 1 2 3 5 8 13 21 34... 15 | ``` 16 | 17 | 规律应该很容易看出来,即从第三项开始,每一项的值等于前两项之和,以此类推下去,至于第一项和第二项的值嘛,不要纠结,就是这样规定的... 18 | 19 | 20 | # 斐波那契数 21 | 22 | 首先来实现一下获取指定项的斐波那契数,即获取该数组中第 n 项的值; 23 | 24 | 方法一: 25 | ```js 26 | function getFebNum(n) { 27 | if (n == 1 || n == 2) { 28 | return 1; 29 | } else { 30 | return getFebNum(n - 1) + getFebNum(n - 2); 31 | } 32 | } 33 | ``` 34 | 35 | 方法一使用递归的思路,便于理解代码量也少,但是其算法复杂度较大,当 n 相当大的时候,程序运行也无比复杂; 36 | 37 | 方法二: 38 | ```js 39 | function _getFebNum(n) { 40 | if (n < 1) return 0; 41 | let one = 1, // 初始为第 -2 项 42 | two = 0, // 初始为第 -1 项 43 | three = 0; // 初始为第 1 项 44 | for (let i = 1; i <= n; i++) { 45 | three = one + two; 46 | one = two; 47 | two = three; 48 | } 49 | return three; 50 | } 51 | ``` 52 | 53 | 这种方法算法复杂度就比较小了,只是换了个获取思路,代码量增加也不太容易理解,其中为了缩减代码量,便于递推的进行,把斐波那契数列向后模拟扩展了两项: 54 | 55 | 项 | -2 | -1 | 1 | 2 | 3 | 4 | 5 | ... 56 | ---|----|----|---|---|---|---|---|---- 57 | 值 | 1 | 0 | 1 | 1 | 2 | 3 | 5 | ... 58 | 59 | # 斐波那契数列 60 | 61 | 接下来通过代码实现获取指定长度的斐波那契数列: 62 | 63 | 方法一: 64 | ```js 65 | function getFebArr(n) { 66 | let arr = []; 67 | for (let i = 1; i <= n; i++) { 68 | arr.push(getFebNum(i)); 69 | } 70 | return arr; 71 | } 72 | ``` 73 | 74 | 这个方法通过挨个获取斐波那契数,最后组成一个斐波那契数列,需要用到前面的 `getFebNum` 函数; 75 | 76 | 方法二: 77 | ```js 78 | function _getFebArr(n) { 79 | let arr = []; 80 | if (n < 1) return arr; 81 | let one = 1, 82 | two = 0, 83 | three = 0; 84 | for (let i = 1; i <= n; i++) { 85 | three = one + two; 86 | arr.push(three); 87 | one = two; 88 | two = three; 89 | } 90 | return arr; 91 | } 92 | ``` 93 | 94 | 方法二利用之前 `_getFebNum` 方法的思路,递推地填充斐波那契数列,降低了算法复杂度; -------------------------------------------------------------------------------- /_posts/2019-09-02-js-mutation-array.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 变异与非变异数组方法 3 | layout: post 4 | categories: JavaScript 5 | tags: 变异数组 6 | excerpt: 关于 JavaScript 中数组方法的区分 7 | --- 8 | 在 JavaScript 中,存在大量对数组进行操作的方法,它们都有一个特点,就是关于此操作是否会修改原数组,并以此将数组方法分为**变异数组方法**与**非变异数组方法**,例如 `.pop()` 方法便是删除数组的最后一个元素,而 `.slice()` 方法则是返回一个指定特征的新数组,并不会对原数组进行修改;能有效的区分这两类方法,有助于开发过程中方法选用,避免出现不必要的错误; 9 | 10 | 下面对一些常见的数组方法进行了整理分类: 11 | 12 | | 非变异数组方法 | 变异数组方法 13 | |------------------|------------- 14 | | .join() | .push() 15 | | .concat() | .pop() 16 | | .slice() | .shift() 17 | | .from() | .reverse() 18 | | .map() | .sort() 19 | | .filter() | .splice() 20 | | .every() | .fill() 21 | | .find() | 22 | | .findIndex() | 23 | | .flat() | 24 | | .flatMap() | 25 | | .forEach() | 26 | | .includes() | 27 | | .indexOf() | 28 | | .lastIndexOf() | 29 | | .reduce() | 30 | | .reduceRight() | 31 | | .some() | 32 | | .toString() | 33 | | .toLocalString() | 34 | 35 | 可以看出改变原数组的变异数组方法只有少数几个,非变异的过多可能记不住,因此可以选择记少不记多的原则,记住那几个特殊的变异方法的,其余的便可归类于非变异的了; -------------------------------------------------------------------------------- /_posts/2019-09-02-js-try.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 中 try, catch, throw 的用法 3 | layout: post 4 | categories: JavaScript 5 | tags: try catch 错误 6 | excerpt: JavaScript 中关于错误的调试方法 7 | --- 8 | 程序在运行中难免遇到 bug,所以就需要好的调试手段找出问题所在,`try, catch, throw` 便是 JavaScript 中用来调试并对错误执行相关操作的工具,下面具体介绍其用法; 9 | 10 | # try, catch 11 | 12 | 基本语法结构: 13 | ```js 14 | try { 15 | // ... 16 | // 这里写需要调试的代码段 17 | } catch(error) { 18 | // ... 19 | // 这里写要对获取的错误信息执行的操作 20 | } 21 | ``` 22 | 23 | 举例: 24 | ```js 25 | try { 26 | // 这里故意写错函数名,为了抛出错误 27 | console.logg('This is an error and will not display'); 28 | } catch (e) { 29 | console.log(e); // TypeError: console.logg is not a function 30 | console.log(e.message); // console.logg is not a function 31 | console.log(e.name); // TypeError 32 | console.log(e.stack); // TypeError: console.logg is not a function 33 | } 34 | ``` 35 | 36 | 上面的错误代码如果直接在正常环境中执行,便会直接在后台输出错误: 37 | ``` 38 | TypeError: console.loggg is not a function 39 | ``` 40 | 41 | 但是使用 `try, catch` 结构的话,就可以获取一个包含错误信息的对象,其包含各个部分的错误信息,便于进行一些自定义操作; 42 | 43 | # throw 44 | 45 | `throw` 是在上述结构中使用的一个函数,接受一个参数作为输出信息,throw 的作用是中断后面**所有**语句的执行,包括错误源,但是它前面的语句都会正常执行,它可以用于判断错误的具体位置,例如: 46 | ```js 47 | try { 48 | console.log('This will display.'); 49 | throw('My error position.'); // throw 将会中断语句的执行 50 | // 同样故意制造错误 51 | console.logg('This is an error and will not display.'); 52 | // 后面是正常语句 53 | console.log('This will not display, either.') 54 | } catch (e) { 55 | console.log(e); 56 | } 57 | // This will display. 58 | // My error position. 59 | ``` 60 | 61 | 如果错误发生在 `throw` 语句之前的话,错误便会被正常抛出,而 `throw` 传递的信息不会被输出,例如: 62 | ```js 63 | try { 64 | console.logg('This is an error and wil not display.'); 65 | throw('My error position.'); 66 | // 后面的执行同样会被中断 67 | console.log('This will not display, either.') 68 | } catch(e) { 69 | console.log(e); 70 | } 71 | // TypeError: console.logg is not a function. 72 | ``` 73 | 74 | 因此,在调试过程中可以结合上面两种情况,一步步找出错误的具体位置; -------------------------------------------------------------------------------- /_posts/2019-09-03-js-lcm.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 求最小公倍数 3 | layout: post 4 | categories: JavaScript 5 | tags: 公倍数 公约数 6 | excerpt: JavaScript 实现求最小公倍数的算法 7 | --- 8 | # 最小公倍数(Least Common Multiple) 9 | 10 | **最小公倍数**是中学数学知识中的一个概念,具体定义可以 自行了解,这里只大致解释一下,通常几个正整数会存在许多个倍数,每个倍数除以这几个正整数后都没有余数,而这些倍数之中最小的一个则称为最小公倍数; 11 | 12 | 一般直接计算最小公倍数较为困难,因此需要用到一个计算公式,即两个数的乘积等于这两个数的最大公约数与最小公倍数的乘积,所以知道两个数的最大公约数或者求最小公倍数,就可以求得另外一个,接下来先来实现**最大公约数**的求法; 13 | 14 | # 最大公约数(Greatest Common Divisor) 15 | 16 | 这也是与最小公倍数相似的另一个概念,几个正整数之间一般存在多个约数,即这几个正整数除以这个约数后都没有余数,这些约数中最大的一个称为**最大公约数**;下面来实现求最大公约数的函数; 17 | 18 | ## 最大质因数法 19 | 20 | 思路很简单,即将两个数分别递减,获取能同时被二者除尽的最大的一个数,即最大公约数: 21 | ```js 22 | function getGcd(a, b) { 23 | for (let i = a; i > 0; i--) { 24 | for (let j = b; j > 0; j--) { 25 | if (a % i === 0 && b % j === 0 && i === j) { 26 | return j; 27 | } 28 | } 29 | } 30 | } 31 | ``` 32 | 33 | ## 辗转相除法 34 | 35 | 思路是用两个数中的最大项除以最小项,如果能除尽,那么最小项便是这两个数的最大公约数;不能除尽则用最大项除以最小项所得余数,与最小项再进行同样的递归操作,最后得到最大的约数,也就是所谓的**辗转相除**; 36 | ```js 37 | function getGcd(a, b) { 38 | let max = Math.max(a, b); 39 | let min = Math.min(a, b); 40 | if (max % min === 0) { 41 | return min; 42 | } else { 43 | return getGcd(max % min, min); 44 | } 45 | } 46 | ``` 47 | 48 | # 求最小公倍数 49 | 50 | 有了求最大公约数的函数后,再来求最小公倍数就简单了: 51 | ```js 52 | function getLcm(a, b) { 53 | return a * b / getGcd(a, b); 54 | } 55 | ``` -------------------------------------------------------------------------------- /_posts/2020-01-12-js-array-sort.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 数组排序详解 3 | layout: post 4 | categories: JavaScript 5 | tags: 数组 排序 乱序 6 | excerpt: 关于 JavaScript 中数组排序函数的介绍和应用 7 | --- 8 | 提到 JavaScript 中对数组进行排序操作,可能首先想到的就是 `Array.prototype.sort()` 这个函数,比如以下场景就比较常见: 9 | 10 | ```js 11 | var arr = [3, 1, 2]; 12 | 13 | console.log(arr.sort()); 14 | // [1, 2, 3] 15 | console.log(arr); // sort() 函数会修改原数组 16 | // [1, 2, 3] 17 | 18 | arr = ['c', 'b','B', 'a','A']; 19 | arr.sort(); 20 | console.log(arr); 21 | // ["A", "B", "a", "b", "c"] 22 | ``` 23 | 24 | 和预想的一样,`sort()` 函数默认将数组元素升序排列,但是不要被上面的数字数组的排序结果迷惑,该函数并不是按照数字递增的方式排列的,而是按照元素的 **ASCII** 码或者 **Unicode** 码进行排序,比如字符 `a` 对应的 **ASCII** 码要比字符 `b` 的小,所以 `a` 排在 `b` 前面,同样字符 `A` 的比字符 `a` 的小,所以大写字母 `A` 会排在小写字母 `a` 前面;考虑以下情景: 25 | ```js 26 | var arr = [1, 2, 11, 12]; 27 | arr.sort(); 28 | console.log(arr); 29 | // [1, 11, 12, 2] 30 | ``` 31 | 32 | 是不是有些和预想的不一样,这也验证了之前所说,并不是按照数字递增在排序,而是把数组中的数字类型的元素转换成字符,在拆分字符比较单个字符对应的字符码的大小; 33 | 34 | ## 比较函数 35 | 36 | 那么问题就来了,要按照数字递增方式排序,该怎么操作呢?其实这种情况早就被 `.sort()` 函数考虑到了,只是可能被大家忽略了,就是 `.sort()` 函数还能接受一个参数,叫做 `compareFunction`,顾名思义,就是 **比较函数**,由于该参数是一个函数,所以该函数又能接受两个参数,即比较的值,所以最终就是 `.sort(compareFunction(a, b))`; 37 | 38 | 关于这个 **比较函数**,存在如下规则: 39 | 40 | - 如果 `compareFunction(a, b)` 返回值小于 0 ,那么 `a` 会被排列到 `b` 之前; 41 | - 如果 `compareFunction(a, b)` 返回值等于 0 ,那么 `a` 和 `b` 的相对位置不变; 42 | - 备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本); 43 | - 如果 `compareFunction(a, b)` 返回值大于 0 ,那么 `b` 会被排列到 `a` 之前; 44 | 45 | > `compareFunction(a, b)` 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。 46 | 47 | 在使用它之前,先来看看函数里面的参数 `a, b` 是如何对应数组元素的: 48 | ```js 49 | var arr = [2, 1, 4, 3]; 50 | arr.sort(function(a, b) { 51 | console.log(a, b); 52 | }) 53 | 54 | // 1 2 55 | // 4 1 56 | // 3 4 57 | ``` 58 | 59 | 可以发现,由于这里的比较函数没有返回值,所以对数组就没有排序操作,而每一次遍历中,第二个参数 `b` 对应前一个元素,第一个参数 `a` 对应后一个元素;当然该函数的具体排序方法就不得而知并且因 JS 引擎而异了; 60 | 61 | ## 升序 62 | 63 | 对数组按照升序方式排序,即小的元素排在前面,大的元素排在后面,假设比较函数当前遍历的元素对为 `(2, 1)`,则 `a = 1, b = 2`,要想升序就要 `a` 排到 `b` 的前面,对应上面的规则,就是需要比较函数的返回值小于 0,由于当前 `a - b < 0`;所以直接返回一个 `a - b` 就行了,代码如下: 64 | ```js 65 | var arr = [2, 1, 3, 11, 12, 11] 66 | arr.sort(function(a, b) { 67 | return a - b; 68 | }) 69 | 70 | console.log(arr); 71 | // [1, 2, 3, 11, 11, 12] 72 | ``` 73 | 74 | 针对上面的代码再来分析下,在每一次遍历比较的两个元素中: 75 | 76 | - 如果后一个元素比前一个元素小,即 `a - b < 0`,按照规则就是 `a` 要排到 `b` 的前面,也就是这两个元素会交换,小的在前,大的在后; 77 | - 如果后一个元素比前一个元素大,即 `a - b > 0`,按照规则就是 `b` 要排到 `a` 的前面,由于 `b` 本来就在 `a` 的前面,所以两元素位置不变; 78 | - 如果后一个元素与前一个元素相同,即 `a - b = 0`,按照规则就是 `a` 和 `b` 的位置不变,两元素位置同样不变; 79 | 80 | 最后,数组就变成升序的了; 81 | 82 | ## 降序 83 | 84 | 原理和升序类似,只是思路反过来了,代码如下: 85 | ```js 86 | var arr = [2, 1, 3, 11, 12, 11] 87 | arr.sort(function(a, b) { 88 | return b - a; 89 | }) 90 | 91 | console.log(arr); 92 | // [12, 11, 11, 3, 2, 1] 93 | ``` 94 | 95 | 同样来分析一下,每一次遍历中: 96 | 97 | - 如果前一个元素比后一个元素小,即 `b - a < 0`,按照规则就是 `a` 要排到 `b` 的前面,也就是这两个元素会交换,大的在前,小的在后; 98 | - 如果前一个元素比后一个元素大,即 `b - a > 0`,按照规则就是 `b` 要排到 `a` 的前面,由于 `b` 本来就在 `a` 的前面,所以两元素位置不变; 99 | - 如果前一个元素与后一个元素相同,即 `b - a = 0`,按照规则就是 `a` 和 `b` 的位置不变,两元素位置同样不变; 100 | 101 | 最后,数组也就变成降序了; 102 | 103 | ## 反序 104 | 105 | 这是排序函数一个另一个应用,作用相当于 `.reverse()` 函数,即让数组中的元素顺序颠倒,实现也很简单,就是利用规则,让每次比较函数的返回值小于 0 就行了,例如: 106 | ```js 107 | var arr = [2, 1, 4, 3]; 108 | arr.sort(function(a, b) { 109 | return -1 110 | }); 111 | 112 | console.log(arr); 113 | // [3, 4, 1, 2] 114 | ``` 115 | 116 | ## 乱序 117 | 118 | 这也算是一个比较实用的用途了,即将数组中元素的位置和顺序打乱,增加随机性,实现也简单,即利用规则,让比较函数的返回值随机为 `> 0, < 0, = 0` 这三种情况之一,使得元素是否交换位置具有随机性,也就实现了顺序的打乱,实现代码如下: 119 | ```js 120 | var arr = [1, 2, 3, 4, 5]; 121 | arr.sort((a, b) => { 122 | return 0.5 - Math.random(); 123 | }); 124 | 125 | console.log(arr); 126 | // [4, 3, 2, 1, 5] 127 | 128 | arr.sort((a, b) => { 129 | return 0.5 - Math.random(); 130 | }); 131 | 132 | console.log(arr); 133 | // [5, 3, 1, 2, 4] 134 | ``` -------------------------------------------------------------------------------- /_posts/2020-03-21-programme-float-point.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 关于浮点数的剪不断理还乱 3 | layout: post 4 | categories: 编程 5 | tags: 浮点 定点 二进制小数 规约 阶码 6 | excerpt: 展开介绍关于浮点的表示与转换原理 7 | --- 8 | # 二进制小数 9 | 10 | 谈浮点数前,先了解一些基础知识;对于整数的十进制与二进制转换不难,原理也简单就不再赘述,假如现在要进行转换的十进制数字是带有小数点的,转换方法就会稍微有点不一样了;为了使说明更浅显易懂,先来探究一下十进制小数中的奥秘; 11 | 12 | 以十进制数 **3.125** 为例,小数点以左为整数部分,右为小数部分,它也可以被更具体的拆解为以下形式: 13 | ``` 14 | 3x10^0 + 1x10^-1 + 2x10^-2 + 5x10^-3 15 | ``` 16 | 17 | 这也是十进制数的特点,基数为 10,所以每一位都是与 10 的相应次方的乘积,指数也是有规律的,可以看成以小数点为对称轴,向左就是 10 的 0、1、2、3……次方递增,向右则是 10 的 -1、-2、-3……次方递减,如果换一种形式,那么在运算方面也具有对称性(乘法与除法互为逆运算),就是下面的形式: 18 | ``` 19 | 3x10^0 + 1/10 + 2/10^2 + 5/10^3 20 | ``` 21 | 22 | 这样,理解二进制的小数部分就容易了,已经知道整数十进制转二进制其实就是连续除以 2 取余数,那么根据上面的规律,小数部分看出逆运算,就可以总结为 **连续乘 2 取整数**,举例说明: 23 | ``` 24 | 3.125(十进制) 25 | 26 | 3 / 2 = 1 --> 1 27 | 余 1 --> 1 28 | 0.125 x 2 = 0.25 --> 0 29 | 0.25 x 2 = 0.5 --> 0 30 | 0.5 x 2 = 1 --> 1 31 | 32 | ==> 11.001(二进制) 33 | ``` 34 | 35 | **11.001** 就是 3.125 的二进制小数形式,同时它也可以做如下拆解: 36 | ``` 37 | 1x2^1 + 1x2^0 + 0x2^-1 + 0x2^-2 + 0x2^-3 38 | 39 | = 2 + 1 + 0 + 0 + 0.125 40 | = 3.125 41 | ``` 42 | 43 | 可以看到也是与十进制形式相对应的,只是基数从 10 换成了 2 而已; 44 | 45 | # 定点数 46 | 47 | 当然,都知道机器码都是一堆 `0` 和 `1` 组成的数据,并没有小数点这个专门的符号,要表示数字 3125 还好说,但是 3.125 中间多出的这一点要怎么解决呢……一个很直接的方法就是把小数点应该在的位置焊死 -_-,比如 32 位的系统,规定小数点在 16 位和 17 位之间,那么根据 3.125 的二进制是 11.001,在 32 中的表现就是: 48 | ``` 49 | 0000 0000 0000 0011 0010 0000 0000 0000 50 | ``` 51 | 52 | 这就是 **定点数** 的规则干的事情,看着挺好,要是多用几次系统空间可能就 hold 不住了,不好之处明显就是花掉当前一半的数量级取表述小数部分,当然可以少划分几位给小数,但对小数好像不太公平,万一精度要求高呢,反过来呢对整数又不公平了,手心手背都是肉,得想办法解决才行; 53 | 54 | # 浮点数 55 | 56 | 于是乎,浮点数横空出世;其实上述问题平时肯定都遇到过,比如记个帐,昨日净收入 `31200000000` 元(@_@),肯定不想写这一堆 0 对不对(如果是真的咱愿意写 100 遍……),一般都会写 312 亿或者 `3.12x10^10` 元,重点就在后面这种科学计数表示法,人为了省力省纸省笔墨弄了个科学计数法,处理器也自然用上了浮点数,省空间;具体原理与表示方法后面会讲; 57 | 58 | 59 | 以 C语言为代表,其中就有浮点这一数据类型,比如单精度浮点 float(32 位),双精度浮点 double(64 位)等,可能平时也就直接声明和使用较多,没太关注底层实现的算法,其实也不太复杂,套用一种规则而已,下面开始介绍; 60 | 61 | ## 标准 62 | 63 | 目前关于浮点运算与表示,使用广泛的应该就是 IEEE 754(二进制浮点数算术标准)了,其主要内容如下: 64 | ``` 65 | v = (-1)^s * 2^e * m 66 | 67 | v: 浮点数具体值 68 | s: 符号位,即正负号,0 为正,1 为负 69 | m: 有效数,也叫尾数,可以类比科学计数法前面的有效数字 70 | 另外还有一个小数位 f, m = 1 + f 71 | e: 指数位,即 2 的多少次方 72 | ``` 73 | 74 | 该标准包含了多中位数,以 32 位为例: 75 | ``` 76 | (1) (8) (23) : 位数 77 | 0 00000011 0010000000000000000000 78 | s e f 79 | ``` 80 | 81 | 总结就是: 82 | 83 | - 第一位为符号位 s; 84 | - 后 8 位为指数位 e; 85 | - 最后 23 位为小数位 f; 86 | 87 | 64 位的规则是: 88 | 89 | - 第一位是符号位 s; 90 | - 后 11 位是指数 e; 91 | - 最后 52 位是有效数字 m; 92 | 93 | 知道了这些还不能立刻套用上面的公式经行转换,还需要了解接下来的一些规定; 94 | 95 | ## 指数偏移值 96 | 97 | 浮点的二进制表示中指数位 e 的计算值(即转换成十进制后的值),要在实际指数值(十进制)的基础上加上一个 **偏移值**,标准中规定偏移值为 `2^(e-1) - 1`,如 32 为中 e 是 8 位,所以偏移值为 127,64 位的就为 1023;所以 32 位指数实际值的范围为 `-126 ~ 127`; 98 | 99 | 举个例,指数 e 的实际值为 -3,那么 32 位中加上偏移值就是 `-3 + 127 = 124`,换算成二进制的 8 位指数位就是 `01111100`; 100 | 101 | 这种指数位偏移后的指数值,又叫做 **阶码**,因为科学计数法中的指数是有正负之分的,所以实际指数值加上一个正的适中偏移值,就可以使得浮点表示法中的指数位为无符号的整型(就是变成正整数),利于浮点数的比较大小,就是可以直接从浮点的二进制表示中,由高位向低位逐位进行比较(如果是负数二进制比较大小要复杂一点)。 102 | 103 | ## 表示方式 104 | 105 | 具体的表示方式会根据不同的情况而不同,主要有以下几种情况; 106 | 107 | ### 规约形式 108 | 109 | 即 e 的 8 位数字不是全部为 0 或者 1,此时 `m = 1 + f`,由于小数部分 f 的值在 0 到 1 之间,所以有效数 m 的值在 1 到 2 之间; 110 | 111 | ### 非规约形式 112 | 113 | 这种形式 e 的 8 位全部为 0,小数位 f 值不为 0,用于表示非常接近 0 的数,此时不再是 `m = 1 + f`,而是 `m = f`,即 m 值在 0 到 1 之间;实际上所有非规约的浮点数比规约浮点数更接近于 0; 114 | 115 | ### 零值 116 | 117 | 指数位 e 全为 0 的同时,小数部分(f)为 0,用来表示 `±0`(正负取决于 s 位的值);且规定最小指数位编码(e = 0 时)的实际值应该取 `-126`(本来应该是 `0 - 127 = -127`); 118 | 119 | ### 无穷大 120 | 121 | 如果 e 全为 1,且 m 全为 0,则表示无穷大(Infinity,正负取决于 s 位的值); 122 | 123 | ### NaN 124 | 125 | 如果 e 全为 1,且 m 不全为 0,则表示 `NaN`(Not a Number,非数值类型); 126 | 127 | ## 综合举例 128 | 129 | 后面的例子都以 32 位为例,其它位数根据标准类推; 130 | 131 | 先来看一个十进制转浮点,规约形式的例子,比如用之前的十进制数 3.125,转换为 32 位浮点二进制格式(`0b` 开头的表示二进制数据): 132 | ``` 133 | 3.125 134 | = 0b11.001 135 | = 0b1.1001 x 2^1 136 | 137 | s = 0 138 | 139 | e = 1 140 | => 1 + 127 141 | = 128 142 | = 0b10000000 143 | 144 | m = ob1.1001 145 | f = m - 1 146 | = 0b0.1001 147 | => 0b10010000000000000000000 148 | 149 | ==> 150 | 0 10000000 10010000000000000000000 151 | ``` 152 | 153 | 转换的大致流程总结如下: 154 | 155 | **十进制小数 --> 二进制小数 --> 浮点表示法 --> 二进制浮点** 156 | 157 | 再举一个二进制浮点转十进制小数例子: 158 | ``` 159 | 1 01111111 00100000000000000000000 160 | 161 | s = 1 162 | => -1 163 | 164 | e = 0b01111111 165 | = 127 166 | => 127 - 127 167 | = 0 168 | 169 | f = 0b0.001 170 | m = 1 + f 171 | = 0b1.001 172 | 173 | v = -1 x 0b1.001 x 2^0 174 | = 0b-1.001 175 | = -1.125 176 | 177 | ==> -1.125 178 | ``` 179 | 180 | ## 精度 181 | 182 | 以 32 位单精度浮点数为例,由于分配给有效数字的位数是 23 位,而整数部分默认是 1,它的位置就不用留了,所以小数部分就可以独占 23 位,在加上默认的一个整数位就是 24 位了,同理,64 位双精度浮点数的有效数就是 53 位(52+1),再进行一下算术运算: 183 | ``` 184 | log(2^24) = 7.22 185 | log(2^53) = 15.95 186 | ``` 187 | 188 | 上面的算式表示二进制下的这么多位数的实际值,对应到十进制中有多少位;结果表明,单精度浮点可以保证 7 位十进制的有效数字,双精度的则可以保证 15 位; 189 | 190 | ## “浮”的原因 191 | 192 | 取名为浮点,那么到底“浮”在了什么地方,与定点数相比的优势又是什么?总的看来,其实其转换操作很类似于十进制中的科学计数法,而科学计数法的出现,就是为了实现能简短地书写较大的数,比如写作 `1.0x10^20`,就可以避免在 1 后面写那令人抓狂的 20 个 0 了; 193 | 194 | 同理,二进制中如果用定点数表示小数,那么 32 位的话就最多到 32 位有效数字,而用这种类似科学技术的浮点表示法的话,指数能表示到 100 以上,也就是 100 多位了,相信现在的 100 位系统也是稀有物种了吧;因此,浮点数有效的扩大了能表示的数据范围,科学计数法减少了书写量,浮点表示则是节省了存储空间; 195 | 196 | 另外也是由于科学计数本身的特性,以及指数偏移值,也就是 **阶码** 的应用,小数点也就不再像之前一样固定,具体位置会根据指数的大小最终“漂浮”到不同的位置,甚至到那遥远的地方…… -------------------------------------------------------------------------------- /_posts/2020-04-15-linux-chinese.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kali Linux系统设置中文语言环境 3 | layout: post 4 | categories: Exploit 5 | tags: linux 汉化 中文 乱码 6 | excerpt: 介绍Kali Linux系统如何设置中文以及修复乱码的问题 7 | --- 8 | 主流 Linux 系统安装之后,默认使用的语言环境基本都是英语,所以不管时图形桌面的菜单标题,还是终端的一些输出提示,都是展示的英文,对于觉得阅读英语不太友好的同胞们,第一件事可能就是设置一个友好的汉化环境,下面以 **Kali Linux** 这个发行版的系统为例,介绍一些设置中文语言环境的方法; 9 | 10 | ## 图形界面 11 | 12 | 如果安装的系统有图形界面,那么操作就简单了;一般系统在安装时就会提供语言选项,不过安装好后也能进行修改,一般可以在系统设置的**区域与语言**模块中找到相关的设置,例如下图: 13 | 14 | ![language.jpg](https://i.loli.net/2020/04/15/sOjHYfuMplZ9E6b.jpg) 15 | 16 | 至于其他 Linux 系统,路径应该类似,或者可以在设置里面搜索一下;修改成功需要重新登录生效,这个修改是永久性的; 17 | 18 | ## 终端命令 19 | 20 | 没有图形界面或者在设置里面没有找到的情况下,可以尝试使用终端命令进行修改; 21 | 22 | ### 安装中文环境包 23 | 24 | 切换中文环境之前,需要安装中文语言环境包,直接运行以下命令: 25 | ```sh 26 | sudo dpkg-reconfigure locales 27 | 28 | # 上面的运行不成功可以尝试下面这条命令: 29 | sudo dpkg-reconfigure --force locales 30 | ``` 31 | 32 | 如果提示类似 `locales` 未找到这样的信息,那么就先运行 `apt install locales` 执行安装,然后再运行上面的命令,顺利的话会弹出一个对话框,选择需要安装的语言,因为中文包是 `z` 开头的,列表又是按字母顺序排列,所以使用方向箭头向下浏览到靠近底端位置,应该能看见这样一个选项: 33 | ```sh 34 | [ ] zh_CN.UTF-8 UTF-8 35 | ``` 36 | 37 | 然后把焦点移动到它上面,按下空格键选择,选中的话方括号中会出现星号,再按回车进入下一步,新的对话框会提示选择系统默认的语言设置,这时依然把焦点移动到和上面一样的选项上,最后按回车确认,代码运行完毕后如果没有报错,就安装完成了; 38 | 39 | ### 切换中文环境 40 | 41 | 接下来开始切换语言环境,先运行一下 `locale` 命令查看当前的语言环境,应该会得到以下输出(目前还是英语环境): 42 | ```sh 43 | LANG=en_US.UTF-8 44 | LANGUAGE= 45 | LC_CTYPE="en_US.UTF-8" 46 | LC_NUMERIC="en_US.UTF-8" 47 | LC_TIME="en_US.UTF-8" 48 | LC_COLLATE="en_US.UTF-8" 49 | LC_MONETARY="en_US.UTF-8" 50 | LC_MESSAGES="en_US.UTF-8" 51 | LC_PAPER="en_US.UTF-8" 52 | LC_NAME="en_US.UTF-8" 53 | LC_ADDRESS="en_US.UTF-8" 54 | LC_TELEPHONE="en_US.UTF-8" 55 | LC_MEASUREMENT="en_US.UTF-8" 56 | LC_IDENTIFICATION="en_US.UTF-8" 57 | LC_ALL= 58 | ``` 59 | 60 | 其实这些也都代表这当前系统的对应环境变量值,例如再运行 `echo $LANG` 就会得到输出 `en_US.UTF-8`,其他类似,所以我们修改的重点也是围绕其中的几个变量展开的;由于环境变量的特性,也可以再细分为两种方法; 61 | 62 | #### 临时性修改 63 | 64 | 直接在终端里输入以下命令的话,就能对当前语言的环境变量进行修改: 65 | ```sh 66 | export LANG=zh_CN.UTF-8 67 | ``` 68 | 69 | > 注:这里只用修改 `LANG` 这个变量就行了,后面的其它以 `LC` 开头的变量值会自动改变; 70 | 71 | 然后再运行 `locale` 看一下效果: 72 | ```sh 73 | LANG=zh_CN.UTF-8 74 | LANGUAGE= 75 | LC_CTYPE="zh_CN.UTF-8" 76 | LC_NUMERIC="zh_CN.UTF-8" 77 | LC_TIME="zh_CN.UTF-8" 78 | LC_COLLATE="zh_CN.UTF-8" 79 | LC_MONETARY="zh_CN.UTF-8" 80 | LC_MESSAGES="zh_CN.UTF-8" 81 | LC_PAPER="zh_CN.UTF-8" 82 | LC_NAME="zh_CN.UTF-8" 83 | LC_ADDRESS="zh_CN.UTF-8" 84 | LC_TELEPHONE="zh_CN.UTF-8" 85 | LC_MEASUREMENT="zh_CN.UTF-8" 86 | LC_IDENTIFICATION="zh_CN.UTF-8" 87 | LC_ALL= 88 | ``` 89 | 90 | 确实修改成功了,不过这条命令是临时性的,关闭当前终端或重启后就失效了,而且也仅限于当前终端内输出指定的语言,只适用于临时查看某个语言的输出内容的场景; 91 | 92 | #### 永久性修改 93 | 94 | 要永久性的修改语言环境,其实也就是永久性的修改 `LANG` 这个环境变量的值,要实现它就直接在 `~/.bashrc` 这个文件中末尾追加下面一行内容: 95 | ```sh 96 | export LANG=zh_CN.UTF-8 97 | ``` 98 | 99 | 这样就对当前用户设置了中文语言环境,如果需要应用到系统所有用户的话,就追加到 **`/etc/profile`** 这个文件中;最后重启一下就设置成功了; 100 | 101 | #### 其它修改方法 102 | 103 | 一些教程中会提到修改 `/etc/default/locale` 这个文件的内容,其实上面的安装中文环境这一节中,最后一步其实就是向这个文件中写入以下内容: 104 | ```sh 105 | LANG=zh_CN.UTF-8 106 | ``` 107 | 108 | 不过经测试,这样修改后重启并没有改变当前语言环境,不过要是替换成下面的内容就能修改成功: 109 | ```sh 110 | LANGUAGE=zh_CN.UTF-8 111 | ``` 112 | 113 | 另外下面任意一条命令都能实现设置 `/etc/default/loale` 这个文件的内容: 114 | ```sh 115 | sudo localectl set-locale LANGUAGE=zh_CN.UTF-8 116 | sudo update-lcoale LANGUAGE=zh_CN.UTF-8 117 | ``` 118 | 119 | 修改后重启运行 `locale` 得到的输出是这样的: 120 | ```sh 121 | LANG=en_US.UTF-8 122 | LANGUAGE=zh_CN.UTF-8 123 | LC_CTYPE="en_US.UTF-8" 124 | LC_NUMERIC="en_US.UTF-8" 125 | LC_TIME="en_US.UTF-8" 126 | LC_COLLATE="en_US.UTF-8" 127 | LC_MONETARY="en_US.UTF-8" 128 | LC_MESSAGES="en_US.UTF-8" 129 | LC_PAPER="en_US.UTF-8" 130 | LC_NAME="en_US.UTF-8" 131 | LC_ADDRESS="en_US.UTF-8" 132 | LC_TELEPHONE="en_US.UTF-8" 133 | LC_MEASUREMENT="en_US.UTF-8" 134 | LC_IDENTIFICATION="en_US.UTF-8" 135 | LC_ALL= 136 | ``` 137 | 138 | 即最终只修改了 `LANGUAGE` 这一处的变量值,所以这个方法不怎么推荐;另外也有一些教程提到修改 **`/etc/sysconfig/i18n`** 或 **`/etc/local.conf`** 这两个文件的内容,这应该是其它 Linux 发型版本中的,至少我在 Kali 系统里面没有找到这两个文件; 139 | 140 | ### 安装中文字体包 141 | 142 | 修改好中文环境重启后,还有可能出现的一种常见情况就是,终端或者菜单标题之类的地方出现**乱码**,也有可能出现先刚安装完系统后;其实原因也很简单,就是虽然环境被设置成了中文,但是当前系统中缺乏相应的中文字体,所以识别错误就用一些乱码来占位了; 143 | 144 | 解决方法就是安装一些中文字体包,比如可以运行: 145 | ```sh 146 | sudo apt install fonts-wqy-microhei 147 | ``` 148 | 149 | 安装完成后,按需重启,应该就能看见友好又熟悉的内容了 `^_^`; -------------------------------------------------------------------------------- /_posts/2020-05-24-linux-shell-shortcut.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 提升 Linux 终端命令敲写效率的快捷键参考 3 | layout: post 4 | categories: Linux 5 | tags: linux shell 终端 快捷键 6 | excerpt: 分类介绍 Linux 终端中一些常用操作的快捷键 7 | --- 8 | ## 移动 9 | 10 | | 快捷键 | 描述 | 11 | |----------------------|-----------------------------------------| 12 | | `Ctrl + B` | 光标向前移动一个字符(Backward) | 13 | | `Ctrl + F` | 向后移动一个字符(Forward) | 14 | | `Alt + B`/`Ctrl + →` | 向前移动一个单词 | 15 | | `Alt + F`/`Ctrl + ←` | 向后移动一个单词 | 16 | | `Ctrl + A`/`Home` | 移动到行首(Ahead) | 17 | | `Ctrl + E`/`End` | 移到行尾(End) | 18 | | `Ctrl + XX` | 行首与当前光标之间切换位置(方便在两处修改)| 19 | | `Ctrl + T` | 交换光标处与左边一个字符位置(Transform) | 20 | | `Alt + T` | 交换光标处和左边一个单词位置 | 21 | 22 | 23 | ## 编辑 24 | 25 | | 快捷键 | 描述 | 26 | |------------------------------|---------------------------------------------------| 27 | | `Ctrl + L` | 清屏(不包含输入为运行的命令) | 28 | | `Ctrl + Shift + C` | 复制(到系统粘贴板) | 29 | | `Ctrl + Shift + V` | 粘贴(来自系统粘贴板) | 30 | | `Alt + .` | 粘帖上次命令的最后一个参数 | 31 | | `Ctrl + H`/`Backspace` | 向左删除一个字符 | 32 | | `Ctrl + D`/`Del` | 向右删除一个字符(Delete) | 33 | | `Ctrl + W`/`Alt + Backspace` | 向左剪切一个单词(到终端粘贴板) | 34 | | `Ctrl + Del`/`Alt + D` | 向右剪切一个单词 | 35 | | `Ctrl + U` | 剪切光标左边所有内容(不含光标处) | 36 | | `Ctrl + K` | 剪切光标处以及右边所有内容 | 37 | | `Ctrl + Y` | 粘贴(来自终端粘贴板) | 38 | | `Alt + Y` | 粘贴(按下 Ctrl+Y 后,由新到旧选择历史剪切内容粘贴) | 39 | | `Alt + C` | 光标处往后一个单词首字母大写(capital) | 40 | | `Alt + U` | 光标处往后一个单词字母全大写(Upper case) | 41 | | `Alt + L` | 光标处往后一个单词字母全小写(Lower case) | 42 | 43 | 44 | ## 控制 45 | 46 | | 快捷键 | 描述 | 47 | |-----------------------|-------------------------------------------------------| 48 | | `Ctrl + M`/`Ctrl + O` | 运行命令(类似 `Enter` 键) | 49 | | `Ctrl + C` | 终止命令(未执行的输入命令会清除,已运行则中止进程) | 50 | | `Ctrl + D` | 退出终端(无未执行命令时) | 51 | | `Ctrl + Z` | 挂起命令(切换到后台继续执行) | 52 | | `Ctrl + S` | 阻止屏幕输出(当前在运行持续输出的命令时,如 watch 命令)| 53 | | `Ctrl + Q` | 允许屏幕输出(阻止后恢复输出) | 54 | | `Ctrl + P`/`↑` | 切换上一条命令 | 55 | | `Ctrl + N`/`↓` | 切换下一条命令 | 56 | | `Shift + PageUp` | 向上翻页(历史记录) | 57 | | `Shift + PageDown` | 向下翻页 | 58 | | `Ctrl + R` | 搜索历史记录(输入后立即在输入栏显示匹配项) | 59 | | `Ctrl + G` | 退出历史搜索(按 Esc 退出会保留匹配项) | 60 | 61 | 62 | ## 特殊命令 63 | 64 | 以下命令可以避免重复输入冗长的命令; 65 | 66 | | 快捷键 | 描述 | 67 | |----------|-------------------------------------------------------------| 68 | | `!!` | 获取上一条命令(会输出所执行的完整命令及其结果) | 69 | | `!xx` | 获取最近一条以 xx 开头的命令(xx 为任意字符) | 70 | | `!xx:p` | 类似 `!xx`,只是不会执行,只输出完整命令 | 71 | | `!$` | 获取上一条命令的最后一个参数 | 72 | | `!$:p` | 输出上一条命令的最后一个参数(不执行) | 73 | | `!*` | 获取上一条命令的所有参数 | 74 | | `!*:p` | 输出上一条命令的所有参数(不执行) | 75 | | `^xy` | 执行上一条命令中删除了 xy (任意字符)后剩下的内容 | 76 | | `^ab^xy` | 执行上一条命令中 ab 替换为 xy 后得到的内容(只替换第一个匹配项)| 77 | 78 | 79 | 参考链接: 80 | > - 81 | > - -------------------------------------------------------------------------------- /_posts/2020-09-10-js-react-state-update.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 记一次 React 组件无法更新状态值的问题分析与解决 3 | layout: post 4 | categories: JavaScript 5 | tags: react state getter setter 状态 6 | excerpt: 记录一次React组件中变量绑定state无法正常更新值的问题分析与解决过程 7 | --- 8 | ## 问题 9 | 10 | React 组件中通过直接声明的元素变量(`jsx` 写法),在访问 `state` 中指定的状态值时,如果状态发生改变,使用状态值的元素内容无法得到相应更新; 11 | 12 | 下面的例子中,直接在 class 组件中声明元素变量 `myDiv`,并且需要访问 `this.state` 中的数据,最终对状态值进行展示,按钮用于改变状态值: 13 | ```jsx 14 | import React from 'react'; 15 | 16 | class App extends React.Component { 17 | state = { 18 | msg: 'hello', 19 | }; 20 | 21 | myDiv =
{this.state.msg}
; 22 | 23 | handleClick() { 24 | this.setState({ 25 | msg: 'world', 26 | }) 27 | } 28 | 29 | render() { 30 | return ( 31 | <> 32 |
{this.myDiv}
33 | 36 | 37 | ); 38 | } 39 | } 40 | 41 | export default App; 42 | ``` 43 | 44 | 按理说点击按钮后,状态发生改变(`this.state.msg`),页面的值会发生相应更新,但是页面内容并未发生相应改变,这其实是一个微小的细节问题,下面对其进行展开分析; 45 | 46 | ## 分析 47 | 48 | 上例中,在组件中直接声明了值为元素的一个变量 `myDiv`,并且其内容调用了状态值(`this.state.msg`),其实该变量在声明时状态内容直接被赋予了 `this.state.msg` 的**当前值**,并非想象中的**引用值**,然后状态改变(`this.setState()`)时,React 会重新调用组件的 `render()` 方法,重新渲染组件内容,但是此时该变量中的状态值仍是之前被赋予的字面值,不会再访问一次当前的 `state`,所以其值最终也就不会发生相应的改变; 49 | 50 | 并且在一般的写法中,涉及访问状态的逻辑(如 `{this.state.msg}`)一般都写在整个 `render()` 方法之中,这样每次状态的改变导致 `render` 方法重新执行,使得重新执行获取状态的逻辑,就能每次都访问到最新的状态值了;但有时又很难避免在复用组件时在 `render` 方法以外的地方访问 `state`,并期望数据被动态改变,这里就需要寻求其他解决方案; 51 | 52 | ## 解决方案 53 | 54 | ### 方法一 55 | 56 | 我们可以使用 `getter` 方式来声明变量,`getter/setter` 方法是声明对象属性的一种方式,可以实现该对象指定属性的属性值的访问控制(`getter`)以及修改控制(`setter`),下面是一个简单的使用示例: 57 | ```js 58 | var obj = { 59 | num: 1, 60 | get a() { 61 | return this.num; 62 | } 63 | set b(n) { 64 | this.num = n; 65 | } 66 | } 67 | 68 | console.log(obj.a); // 1 69 | 70 | obj.b = 2; 71 | console.log(obj.a); // 2 72 | ``` 73 | 74 | `getter` 声明的属性的特点是,每次调用对象的该属性,都会执行一次 `getter` 函数内的逻辑,然后返回 `return` 的值;所以如果把之前组件中的 `myDiv` 属性以 `get` 方式进行声明,这样每一次状态改变后,`render()` 方法重新执行,然后就会涉及对该变量的访问,导致重新执行 `getter` 方法中的逻辑,最后就能访问到改变后的状态值(`this.state.msg`),页面也就相应地更新了; 75 | 76 | 改造后的组件代码: 77 | ```jsx 78 | import React from 'react'; 79 | 80 | class App extends React.Component { 81 | state = { 82 | msg: 'hello', 83 | }; 84 | 85 | get myDiv() { 86 | return
{this.state.msg}
; 87 | } 88 | 89 | handleClick() { 90 | this.setState({ 91 | msg: 'world', 92 | }) 93 | } 94 | 95 | render() { 96 | return ( 97 | <> 98 |
{this.myDiv}
99 | 102 | 103 | ); 104 | } 105 | } 106 | 107 | export default App; 108 | ``` 109 | 110 | ### 方法二 111 | 112 | 类似使用 `getter` 的思路,为了让每次状态改变,用到状态的变量也发生相应的更新,另一种方法就是将变量 `myDiv` 声明为**函数**类型,同样也能使每次获取变量时都重新执行一次获取状态的逻辑,以获取最新状态值,改造后代码如下: 113 | ```jsx 114 | import React from 'react'; 115 | 116 | class App extends React.Component { 117 | state = { 118 | msg: 'hello', 119 | }; 120 | 121 | myDiv = () =>
{this.state.msg}
; 122 | // 或者是: 123 | // myDiv() { return
{this.state.msg}
}; 124 | 125 | handleClick() { 126 | this.setState({ 127 | msg: 'world', 128 | }) 129 | } 130 | 131 | render() { 132 | return ( 133 | <> 134 |
{this.myDiv()}
135 | 138 | 139 | ); 140 | } 141 | } 142 | 143 | export default App; 144 | ``` 145 | 146 | 不同之处就是每次调用变量 `myDiv` 时需要使用函数式调用(后面加一对括号),为了方便多处调用,显然方法一更有优势; -------------------------------------------------------------------------------- /_posts/2021-01-18-git-ignorecase.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Git 仓库中文件名大小写问题 3 | layout: post 4 | categories: Git 5 | tags: git 大小写 ignorecase 6 | excerpt: 关于 git 中的文件名大小写识别问题与解决方法 7 | --- 8 | 首先,Windows 下 git 默认配置是对文件/文件夹名称的大小写不敏感: 9 | ```shell 10 | git config --get core.ignorecase 11 | 12 | # true 13 | ``` 14 | 15 | 这就导致了一些时候的难以预料问题的产生,针对这个配置,先引用一下官方帮助文档的原话: 16 | > The default is `false`, except `git-clone` or `git-init` will probe and set core.ignoreCase `true` if appropriate when the repository is created. 17 | 18 | 即 git 默认对大小写敏感,但是会在仓库克隆或初始化时,根据当前系统来设置是否忽略大小写,比如 Windows 下会设置为 `true`,即不敏感,而 Linux 中不会忽略;相信有不少开发者的项目开发与协同工作都是在 **Windows** 系统下进行的,下面就列出 git 的这种机制会导致的问题与解决思路; 19 | 20 | 21 | ### 规范重命名 22 | 23 | 如果分支上直接在编辑器或资源管理器上修改项目中的文件名(只变更大小写),本地虽然可以调试通过,但是 git 并不会识别和记录这个修改,所以下一次提交推送时并不会带上这个重命名修改,远程仓库中这个文件名还是保持不变; 24 | 25 | 因此,如果检出其他分支或者其他协作者拉取代码,项目就会报错,因为一个本地文件的名称如果由小写变成了大写,使用这个文件的代码部分也改成了大写,推送到远程后,远程的这个文件依然是小写,但远程上使用该文件的代码却成功变成了大写,那边启动项目就多半会提示文件不存在了; 26 | 27 | 对于这种情况 git 提供了一种规范的做法,使用 `git mv` 命令: 28 | ```shell 29 | git mv test.txt TEST.txt 30 | ``` 31 | 32 | 以此来实现对文件的重命名,同时 git 也会将其识别为 `Rename` 的变更类型,然后正常提交推送就能同步到远程仓库了;如果是重命名文件夹,由于 Windows 下对文件夹的大小写也不敏感(-_-),所以直接使用上面的方法会失败: 33 | ```shell 34 | git mv test-dir TEST-DIR 35 | 36 | # Rename from 'test-dir' to 'Test-dir/test-dir' failed. 37 | ``` 38 | 39 | 这里就只有迂回一下,先把文件夹命名成其他名称,然后再命名为大写就行了: 40 | ```shell 41 | git mv test-dir tmp 42 | git mv tmp TEST-DIR 43 | ``` 44 | 45 | 46 | ### 修改配置 47 | 48 | 可以选择直接修改 git 配置为不忽略大小写: 49 | ```shell 50 | git config core.ignorecase false 51 | ``` 52 | 53 | 然后直接在资源管理器或编辑器中修改文件名大小写,git 就会识别到了,而且是被识别为 `untracked` 类型的变更,这依然是 Windows 下对文件名大小写不敏感导致的(=_=),如果直接推送到远程的话,那么远程仓库就会同时存在大小写**两个版本**的文件(github/gitlab 服务器通常都是 Linux 系统),为后期维护添加隐患,本地在分支间切换时也可能出现以下报错: 54 | ``` 55 | error: The following untracked working tree files would be overwritten by checkout: 56 | test.txt 57 | Please move or remove them before you switch branches. 58 | Aborting 59 | ``` 60 | 61 | 这种情况下依然需要使用一些迂回的办法,就是先把要重命名的文件改成其他临时名称,提交一次(`git commit`),然后再把临时名称改成想要的名称,再提交一次,最后推送到远程,这样本地和远程都只保留下一个文件了; 62 | ```shell 63 | # rename test.txt --> tmp 64 | git add . 65 | git commit -m "..." 66 | 67 | # rename tmp --> TEST.TXT 68 | git add . 69 | git commit -m "..." 70 | 71 | git push 72 | ``` 73 | 74 | 所以不管是 Windows 还是其他系统下,还是不要轻易修改 git 默认的 `core.ignorecase` 配置,使用规范的 `git mv` 做法就好; -------------------------------------------------------------------------------- /_posts/2021-04-03-js-ts-type-compare.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: TypeScript 中类型 any,void,unknown,never之间的区别 3 | layout: post 4 | excerpt: '分析对比 ts 中基本类型 any, void, unknown, never之间的区别' 5 | categories: JavaScript 6 | tags: ts typescript any unknown never 7 | --- 8 | TypeScript 拓展了 JavaScript 的基本类型与语言特性,为了覆盖类型检查的情景,衍生出了一些额外的类型,其中 `any`, `unknown`, `void`, `never` 这几个类型所适用的情形容易使人混淆,下面通过举例进行一下区分; 9 | 10 | ## any 11 | 12 | 这应该是 typescript 中最开始就会接触到的类型,顾名思义:**任意类型**,这也是 ts 中不写类型申明时的默认类型,即不作任何约束,编译时会跳过对其的类型检查, 13 | ```ts 14 | let val1: any; 15 | val1 = 'abc'; 16 | val1 = 123; 17 | val1 = true; 18 | 19 | const arry: any[] = [123, 'abc', true, null]; 20 | ``` 21 | 22 | ## void 23 | 24 | `void` 表示**无任何类型**,正好与 `any` 相反,没有类型,如果是函数则应没有返回值或者返回 `undefined`,和 C 等语言中的无返回值函数申明类似: 25 | ```ts 26 | function voidFn(): void {} 27 | function voidFn1(): void { return undefined; } 28 | function voidFn2(): void { return; } 29 | 30 | function voidFn3(): void { return 1; } // Error 31 | ``` 32 | 33 | 变量也可以申明为 `void` 类型,只不过只能给这个变量分配 `undefined`, `null` 和 `void` 类型的值(如果 ts 配置文件中设置了 `"strictNullChecks": false`,那么分配 `null` 类型的值也会报错): 34 | ```ts 35 | let val1: void; 36 | let val2: null = null; 37 | let val3: undefined = undefined; 38 | let val4: void; 39 | 40 | val1 = val2; // "strictNullChecks": false 时报错 41 | val1 = val3; 42 | val1 = val4; 43 | ``` 44 | 45 | ## unknown 46 | 47 | 顾名思义,`unknown` 表示**未知类型**,是 `typescript 3.0` 中引入的新类型,即写代码的时候还不清楚会得到怎样的数据类型,如服务器接口返回的数据,`JSON.parse()` 返回的结果等;该类型相当于 `any`,可以理解为官网指定的替代 `any` 类型的**安全**版本(因为不提倡直接使用 `any` 类型); 48 | 49 | 它能被赋值为任何类型,但不能被赋值给除了 `any` 和 `unknown` 之外的其他类型,同时,不允许执行 `unknown` 类型变量的方法(`any` 可以),举个例子: 50 | ```ts 51 | let uk: unknown = 'abc'; 52 | 53 | uk = 123; 54 | uk = true; 55 | uk.toString(); // Error 56 | 57 | let valAny: any = 'abc'; 58 | valAny.toString(); // 'abc' 59 | 60 | let uk1: unknown = uk; 61 | let uk2: any = uk; 62 | let uk2: string = uk; // Error 63 | ``` 64 | 65 | ## never 66 | 67 | `never` 同样顾名思义,表示**永不存在的值**的类型,是 `typescript 2.0` 中引入的新类型,概念有点绕,什么情况下变量会永远不存在值呢?因为通常情况下,变量一旦申明了,就会被分配值,即使没有特别指定,也会被初始化为 `undefined`,同样一个函数即使有个写返回值,也会默认返回 `undefined`,也不是真正的不存在返回值: 68 | ```js 69 | let foo; 70 | console.log(typeof foo); // 'undefined' 71 | 72 | function bar() {}; 73 | console.log(typeof bar()); // 'undefined' 74 | ``` 75 | 76 | 其实确实有一些情形,值会永不存在,比如,从程序运行的维度讲,如果一个函数执行时抛出了**异常**,那么这个函数变永远不会有值了(因为抛出异常会直接中断程序运行,这样程序就运行不到返回值那一步了,即具有不可达的终点,也就永不存在返回了): 77 | ```ts 78 | function err(msg: string): never { 79 | throw new Error(msg); 80 | } 81 | 82 | // 有机会到达终点的函数也算存在返回值,编译会报错 83 | function err1(): never { // Error 84 | if (Math.random() > 0.5) { 85 | throw new Error('message'); 86 | } 87 | } 88 | ``` 89 | 90 | 还有一种极端情况也比较类似,就是函数中执行无限循环的代码(**死循环**),这样也同样使得程序永远无法运行到函数返回值那一步,永不存在返回: 91 | ```ts 92 | function loopForever(): never { 93 | while (true) {}; 94 | } 95 | ``` 96 | 97 | 变量也可以直接申明为 `never` 类型,让它永不存在值,其实就是意思就是永远不能给它**赋值**,否则就会报错,这样就可以形成一种保护机制; 98 | ```ts 99 | let ne: never; 100 | 101 | ne = 123; // Error 102 | ``` 103 | 104 | 另外,`never` 是所有类型的子类型,意思就是它可以赋值给任何类型(前提是配置里 `"strictNullChecks": false`,否则检查不通过); 105 | ```ts 106 | let num: number = 123; 107 | let ne: never; 108 | 109 | num = ne; 110 | ``` 111 | 112 | 同时也没有任何类型是 `never` 的子类型,除了 `never` 自身,即除了 `never` 任何类型都不能赋值给 `never` 类型的变量(如果前提是 `"strictNullChecks": true`,`never` 也不能赋值给 `never`); 113 | ```ts 114 | let ne1: never; 115 | let ne2: never; 116 | 117 | ne1 = ne2; 118 | 119 | // any 也不能分配给 never 120 | let any1: any = 123; 121 | ne1 = any1; // Error 122 | ``` -------------------------------------------------------------------------------- /_posts/2021-04-18-js-ts-generic-type.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: TypeScript 之泛型 3 | layout: post 4 | categories: JavaScript 5 | tags: ts typescript 泛型 generic 6 | excerpt: 介绍TypeScript中泛型的概念与使用场景 7 | --- 8 | ## 背景 9 | 10 | **泛型**用于创建可复用的支持多种类型的组件,比如不仅能支持当前的类型,还能支持未来的类型,为大型系统的构建提供一定灵活性,**泛**有广泛、多种的意思,即泛型可实现对多种类型的支持;泛型是一种已有的概念,除了 TypeScript,同样也存在于其他多种语言中; 11 | 12 | 先举一个基本的例子,ts 中实现一个加法运算的函数,可以是这样的: 13 | ```ts 14 | function addFn(arg1: number, arg2: number): number { 15 | return arg1 + arg2; 16 | } 17 | addFn(1, 2); 18 | ``` 19 | 20 | 如果后期功能拓展,需要上述函数也具备拼接字符串的功能,即: 21 | ```ts 22 | function addFn(arg1: string, arg2: string): string { 23 | return arg1 + arg2; 24 | } 25 | addFn('a', 'b'); 26 | ``` 27 | 28 | 但是这样的申明并不与上面已有的申明兼容,即使使用**联合类型**处理也比较复杂,但是它们的处理逻辑却是一样的,只是类型值换了,重写一个新函数也不符合拓展的初衷,所以需要寻求其他方法; 29 | 30 | 31 | ## 函数重载 32 | 33 | 在 ts 中**重载**是为一个函数提供多个类型定义的操作,使得函数可以根据传参的不同而拥有不同的返回类型;这样,我们就能轻松实现之前例子的拓展需求: 34 | ```ts 35 | function addFn(arg1: string, arg2: string): string; 36 | function addFn(arg1: number, arg2: number): number; 37 | function addFn(arg1: any, arg2: any): any { 38 | // 上面一行只是函数的实现签名,为了兼容上面两个重载签名,不能被直接调用, 39 | // 同时它也并不算作一个重载,真正的重载签名只有最上面的两个 40 | return arg1 + arg2; 41 | } 42 | 43 | // 以下代码都能通过类型检查 44 | addFn(1, 2); 45 | addFn('a', 'b'); 46 | 47 | // 而没在重载定义中的类型会报错 48 | // addFn(true, true); // Error 49 | ``` 50 | 51 | 这个例子中,该申明函数与正常函数的区别是: 52 | - 在函数申明的上方又叠加了几个申明表达式,包裹参数类型和返回类型,末尾以分号结束,每一个申明便是一个重载; 53 | - 然后是在函数区块中写处理逻辑,同时包含进上面的几种参数与返回类型的情况; 54 | - 最后调用时就可以传入不同重载所对应的传参类型,并且能通过类型检查,而不在重载定义中的类型则不会通过类型检查; 55 | - 函数在调用时,ts 会在申明的函数重载中自上而下查找第一个匹配的重载签名,最后一个函数签名称为“实现签名”,并不会被调用; 56 | 57 | 使用重载虽然实现了同时能计算数字和拼接字符串的需求,但是这种写法还是有些复杂,因为参数类型与返回类型具有一定规律性;因此还可以继续寻求更简便的方式; 58 | 59 | 60 | ## 类型变量 61 | 62 | 在 ts 中,可以使用**泛型**来解决上述需求,具体的方式是使用**类型变量**,顾名思义,ts 包含一个庞大的类型处理系统,有各种使用类型的情景,为了应对一些场景,就需要类型值有像**变量**一样的变化性,支持赋值与取值操作; 63 | 64 | 先看一下使用类型变量的具体写法: 65 | ```ts 66 | function addFn(arg1: T, arg2: T): T { 67 | return arg1 + arg2; 68 | } 69 | addFn(1, 2); 70 | addFn('1', '2'); 71 | addFn('a', 'b'); // 调用时也可以省略类型赋值 72 | ``` 73 | 74 | 这里的写法就比写重载的形式简便了许多;示例中出现了 `` 这个标识,其中 `T` 表示**类型变量**,`<>` 表示对类型变量的申明,即申明时使用 `<>` 设置变量,调用时再使用 `<>` 进行赋值,这样所有用到变量 `T` 的地方都会被替换为传入的类型值;这里可以发现,泛型就像类型系统中一个针对类型的**函数**,类型参数就是**形参**; 75 | 76 | 调用时可以省略类型赋值的操作是因为上面的场景中 ts 可以利用**类型推断**机制自动判断出 `T` 的实际类型值(`number`); 77 | 78 | 由于 `T` 表示任意类型,所以不能直接访问某些属性或方法: 79 | ```ts 80 | function fn(arg: T): T { 81 | // return arg.toString(); // Error,因为并不是所有类型都有该方法 82 | return arg; 83 | } 84 | ``` 85 | 86 | 如果是复合类型,则可以使用某些固有属性: 87 | ```ts 88 | function fn(arg: T[]): string { 89 | return arg.toString(); // 普通数组类型都具有该方法 90 | } 91 | ``` 92 | 93 | 类型变量也可以使用其他字母或者单词(通常使用 T),并且可以同时定义多个变量: 94 | ```ts 95 | function fn(arg: M): M { 96 | let one: My; 97 | let two: other; 98 | 99 | return arg; 100 | } 101 | 102 | // 存在多个类型变量时,需要依次赋值类型 103 | fn('abc'); 104 | ``` 105 | 106 | 107 | ## 泛型接口 108 | 109 | 除了函数,泛型也可以在接口中使用,例如: 110 | ```ts 111 | interface IGeneric { 112 | (arg: T): T; 113 | } 114 | 115 | let fn: IGeneric = function(arg) { 116 | return arg; 117 | 118 | // 和接口申明不一致会报错 119 | // return arg + ''; 120 | } 121 | ``` 122 | 123 | 或者是针对整个接口的泛型: 124 | ```ts 125 | interface IGeneric { 126 | a: T; 127 | b: T[]; 128 | c(arg: T): T; 129 | } 130 | 131 | const obj: IGeneric = { 132 | a: 123, 133 | b: [1, 2, 3], 134 | c: (arg) => arg + 1 135 | }; 136 | ``` 137 | 138 | 139 | ## 泛型类 140 | 141 | 针对类定义类型变量时,类的所有非静态成员都可以使用该变量: 142 | ```ts 143 | class CS { 144 | constructor(public attr: T) {} 145 | 146 | fn(): T { 147 | return this.attr; 148 | } 149 | 150 | // 静态成员不能使用泛型类型 151 | // static a: T = ''; // Error 152 | } 153 | 154 | // 实例化时传入类型值 155 | const cs = new CS(123); 156 | 157 | cs.fn(); // 123 158 | ``` 159 | 160 | 161 | ## 泛型约束 162 | 163 | 在一些场景中,可能并不期望类型变量的值太**泛**,而是需要具有某些属性或方法,这时就可以使用 `extends` 关键字对类型加一些**约束**,这和类中的**继承**用途也有些类似;例如: 164 | ```ts 165 | interface IObj { 166 | length: number; 167 | } 168 | 169 | // 将参数约束为具有 length 属性的任意类型 170 | function fn(arg: T): number { 171 | return arg.length; 172 | } 173 | 174 | fn('abc'); // 3 175 | 176 | // 报错,因为数字没有 length 属性 177 | // fn(123); // Error 178 | ``` 179 | 180 | 结合其他 ts 特性,也能表示一些特殊情形,比如下例表示函数第二个参数,需要是第一个参数对象的属性名之一,`keyof` 关键字为索引查询操作符,`keyof T` 表示 `T` 的所有属性构成的联合类型: 181 | ```ts 182 | function fn(obj: T, key: K) { 183 | return obj[key]; 184 | } 185 | 186 | fn({ a: 1 }, 'a'); 187 | 188 | // 报错,因为第一个参数对象中并没有一个叫 'b' 的属性 189 | // fn({ a: 1 }, 'b'); // Error 190 | ``` -------------------------------------------------------------------------------- /_posts/2021-07-05-css-flex-chrome-safari-bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CSS flex 盒子在 Chrome 和 Safari 中的行为差异 3 | layout: post 4 | categories: CSS 5 | tags: flex box chrome safari 6 | excerpt: 分析与解决 flex 盒子在 Chrome 和 Safari 中的行为差异问题 7 | --- 8 | ## 问题 9 | 10 | 最近的开发中有遇到一个页面样式的兼容性问题,大致是使用 `flex` 布局的两个嵌套弹性盒子,在 **Chrome** 和 **Safari** 中对一些特殊情况的处理行为不一致,从而产生了测试 bug; 11 | 12 | ## 复现 13 | 14 | 下面将问题简化为了一个 **demo** 模型,一个定高 `300px` 的 `flex` 盒子 A(红色边框),嵌套了另一个高度被子元素(绿色块)撑开的 `flex` 盒子 B(蓝色边框),其中盒子 B 为垂直伸缩 `flex-direction: column;`,Footer 元素(绿色边框)高度固定 `100px`,背景半透明;代码: 15 | ```html 16 | 17 | 18 | 19 | 20 | 21 | 22 | Demo 23 | 61 | 62 | 63 | Flex Box A - height: 300px; 64 |
65 | Flex Box B - height: auto; 66 |
67 |
height: 100px;
68 |
69 |
70 | 71 |
72 |
73 | height: 100px; 74 |
75 | 76 | 77 | ``` 78 | 79 | 效果: 80 | 81 | ![1](https://img-blog.csdnimg.cn/20210705143709768.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0tOSUdIX1lVTg==,size_16,color_FFFFFF,t_70#pic_center) 82 | 83 | 然后增加绿色块子元素的高度,可以发现在 **Chrome** 中 `flex` 盒子 B 的高度会被该子元素撑开,Footer 元素高度被压缩,而 **Safari** 中的盒子 B 的高度并没有被子元素撑开,而是超出部分被隐藏在了 Footer 下层,同时 Footer 元素也被少量压缩: 84 | 85 | ![2](https://img-blog.csdnimg.cn/20210705143709805.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0tOSUdIX1lVTg==,size_16,color_FFFFFF,t_70#pic_center) 86 | 87 | 当绿色块子元素高度超过最外层 `flex` 盒子 A 的高度时,**Chrome** 中的内层 `flex` 盒子 B 继续被撑开,Footer 元素直接脱离外层 `flex` 盒子,而 **Safari** 中只有子元素超出外层 `flex` 盒子,Footer 依然只被少量压缩: 88 | 89 | ![3](https://img-blog.csdnimg.cn/20210705143709771.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0tOSUdIX1lVTg==,size_16,color_FFFFFF,t_70#pic_center) 90 | 91 | ## 解决 92 | 93 | 最终解决问题的方式是放开外层 `flex` 盒子 A 的**高度限制**,这样无论在 **Chrome** 还是 **Safari** 中 `flex` 盒子都能被自由撑开,行为表现一致: 94 | 95 | ![4](https://img-blog.csdnimg.cn/20210705143709810.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0tOSUdIX1lVTg==,size_16,color_FFFFFF,t_70#pic_center) 96 | 97 | 因此开发中遇到类似**定高**与**弹性**并存的情况,需要合理设计布局,避免不必要的兼容问题; -------------------------------------------------------------------------------- /about.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: "About Me" 4 | css: ["about.css"] 5 | js: ["about.min.js"] 6 | --- 7 | {% include about.html %} -------------------------------------------------------------------------------- /assets/css/about.sass: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | @mixin transition($args...) 4 | -webkit-transition: $args 5 | -moz-transition: $args 6 | -ms-transition: $args 7 | -o-transition: $args 8 | transition: $args 9 | 10 | @keyframes word-waiting 11 | from 12 | border-bottom: 3px solid black 13 | to 14 | border-bottom: none 15 | 16 | .user-pic 17 | img 18 | width: 100px 19 | height: auto 20 | 21 | .user-content 22 | margin-top: 30px 23 | 24 | .typing-text 25 | font-size: 1.5em 26 | 27 | .word-typing 28 | display: inline-block 29 | width: .5em 30 | font-size: 1.5em 31 | border-bottom: 3px solid black 32 | vertical-align: text-bottom 33 | 34 | .word-waiting 35 | display: inline-block 36 | width: .5em 37 | font-size: 1.5em 38 | vertical-align: text-bottom 39 | animation: word-waiting 1s linear infinite -------------------------------------------------------------------------------- /assets/css/article-category.sass: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | #category 4 | li 5 | white-space: nowrap 6 | height: 2.5rem 7 | 8 | a 9 | position: relative 10 | font-weight: bold 11 | 12 | a:hover 13 | color: maroon 14 | 15 | a:before 16 | content: "∟" 17 | position: absolute 18 | left: 10px 19 | bottom: 5px 20 | font-size: 12px -------------------------------------------------------------------------------- /assets/css/categories.sass: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | @mixin transition($args...) 4 | -webkit-transition: $args 5 | -moz-transition: $args 6 | -ms-transition: $args 7 | -o-transition: $args 8 | transition: $args 9 | 10 | .cat-chip 11 | color: #616161 12 | margin-right: 5px 13 | text-decoration: none 14 | 15 | &:hover 16 | div 17 | color: #fff 18 | background-color: #616161 19 | 20 | div 21 | @include transition(all .3s ease-in-out) 22 | 23 | .cat-div 24 | .divider 25 | margin: 20px 0 26 | 27 | .post-date 28 | margin-left: 10px 29 | 30 | ul 31 | &:not(.browser-default) 32 | &.cat-post 33 | padding-left: 0 34 | 35 | a 36 | text-decoration: none 37 | color: #00695c 38 | 39 | li 40 | list-style-position: inside 41 | padding-left: 40px 42 | 43 | &:hover 44 | list-style-type: circle 45 | padding-left: 20px 46 | 47 | @include transition(all .2s ease-in-out) -------------------------------------------------------------------------------- /assets/css/contact.sass: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | .icontain 4 | position: relative 5 | margin-top: 20px 6 | padding-bottom: 100% 7 | height: 0 8 | overflow: hidden 9 | max-width: 100% 10 | 11 | .icontain iframe, 12 | .icontain object, 13 | .icontain embed 14 | position: absolute 15 | top: 0 16 | left: 0 17 | width: 100% 18 | height: 100% -------------------------------------------------------------------------------- /assets/css/icons.sass: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | @font-face 4 | font-family: 'Material Icons' 5 | font-style: normal 6 | font-weight: 400 7 | src: url(/assets/fonts/icon-font.woff2) format('woff2') 8 | 9 | .material-icons 10 | font-family: 'Material Icons' 11 | font-weight: normal 12 | font-style: normal 13 | font-size: 24px 14 | line-height: 1 15 | letter-spacing: normal 16 | text-transform: none 17 | display: inline-block 18 | white-space: nowrap 19 | word-wrap: normal 20 | direction: ltr 21 | -webkit-font-feature-settings: 'liga' 22 | -webkit-font-smoothing: antialiased -------------------------------------------------------------------------------- /assets/css/index.sass: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | main 4 | div 5 | .row 6 | margin-top: 0px 7 | 8 | ul 9 | &:not(.browser-default) 10 | &.pagination 11 | padding-left: 0 12 | 13 | li 14 | a 15 | &:hover 16 | text-decoration: none 17 | 18 | #post-title 19 | margin-bottom: 2px 20 | font-weight: bold 21 | 22 | #post-date 23 | margin-bottom: 8px 24 | font-size: 14px 25 | 26 | i 27 | font-size: 11.5px 28 | margin-right: 10px 29 | 30 | #post-content 31 | margin-top: 5px 32 | font-size: 20px 33 | font-family: cursive -------------------------------------------------------------------------------- /assets/css/post.sass: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | @font-face 4 | font-family: 'Source Code Pro' 5 | src: url(/assets/fonts/SourceCodePro-Regular.ttf) 6 | 7 | @mixin transition($args...) 8 | -webkit-transition: $args 9 | -moz-transition: $args 10 | -ms-transition: $args 11 | -o-transition: $args 12 | transition: $args 13 | 14 | main 15 | strong 16 | font-weight: bold 17 | .page-title 18 | font-size: 1.8em 19 | #page-content 20 | margin-top: 0 21 | 22 | div 23 | .material-placeholder 24 | img 25 | max-height: 60vh 26 | max-width: 90% 27 | margin: auto 28 | .divider 29 | margin: 10px 0 30 | p 31 | font-size: 16px 32 | &.highlighter-rouge 33 | margin: 1em .5em 34 | color: #f8f8f2 35 | pre 36 | padding: 5px 8px 37 | border-radius: 5px 38 | overflow: auto 39 | .program-knight 40 | text-align: center 41 | p 42 | font-size: 20px 43 | font-weight: bold 44 | line-height: 10px 45 | img 46 | width: 250px 47 | div 48 | img 49 | width: 24px 50 | margin-right: 10px 51 | 52 | blockquote 53 | color: #888 54 | background: #e2e2e2 55 | border-left-color: #d2d2d2 56 | overflow: hidden 57 | code 58 | font-family: consolas, 'Source Code Pro' 59 | &.language-plaintext 60 | padding: .2em 61 | border-radius: .2em 62 | color: #c7254e 63 | background: #e6e2e4 64 | 65 | figure 66 | &.highlight 67 | margin: 1em 20px 68 | pre 69 | white-space: pre-wrap 70 | table 71 | width: auto 72 | 73 | #post-info 74 | ul 75 | &:not(.browser-default) 76 | padding-left: 0 77 | width: 40% 78 | li 79 | list-style-type: none 80 | span 81 | font-size: 14px 82 | display: block 83 | margin-bottom: 5px 84 | i 85 | font-size: 11.5px 86 | margin-right: 10px 87 | &#indicate 88 | font-size: 20px 89 | .chip 90 | color: #616161 91 | margin-right: 5px 92 | &:hover 93 | color: #fff 94 | background-color: #616161 95 | @include transition(all .3s ease-in-out) 96 | 97 | #post-content 98 | table, th, td 99 | border: 1px solid #ccc 100 | table 101 | thead 102 | tr 103 | background: #e7e8e9 104 | th 105 | text-align: center 106 | tbody 107 | tr:nth-child(2n + 1) 108 | background: #f7f7f7 109 | 110 | @media only screen and (max-width: 992px) 111 | main 112 | #post-info 113 | h4 114 | text-align: center 115 | ul 116 | &:not(.browser-default) 117 | width: 100% -------------------------------------------------------------------------------- /assets/css/projects.sass: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | .card-image 4 | height: 10em 5 | width: 100% 6 | overflow-x: hidden 7 | 8 | i 9 | color: #fff 10 | padding: 10px 11 | 12 | .card 13 | margin-bottom: 20px 14 | .card-content 15 | height: 7em 16 | overflow: hidden 17 | font-size: 14px 18 | line-height: 110% 19 | 20 | span 21 | width: 100% 22 | 23 | .card-image 24 | a.card-title 25 | font-weight: bold 26 | color: #fff 27 | width: 100% 28 | height: 100% 29 | line-height: 100% 30 | justify-content: center 31 | word-break: break-all 32 | z-index: -1 33 | 34 | .card-reveal 35 | .card-reveal-content 36 | display: block 37 | 38 | span.card-title 39 | font-weight: bold 40 | padding-bottom: 19px 41 | 42 | span.tooltipped 43 | display: block 44 | padding-top: 5px 45 | padding-bottom: 5px 46 | font-size: 16px 47 | 48 | i 49 | font-size: 12px 50 | margin-right: 10px 51 | 52 | .row 53 | div 54 | &.switch 55 | margin-bottom: 5px 56 | 57 | .hidden 58 | display: none -------------------------------------------------------------------------------- /assets/css/syntax.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | // Monokai code theme 4 | .highlight pre { background-color: #272822; } 5 | .highlight .hll { background-color: #676862; } 6 | .highlight .c { color: #75715e } /* Comment */ 7 | .highlight .err { color: #960050; background-color: #1e0010 } /* Error */ 8 | .highlight .k { color: #66d9ef } /* Keyword */ 9 | .highlight .l { color: #ae81ff } /* Literal */ 10 | .highlight .n { color: #f8f8f2 } /* Name */ 11 | .highlight .o { color: #f92672 } /* Operator */ 12 | .highlight .p { color: #f8f8f2 } /* Punctuation */ 13 | .highlight .cm { color: #75715e } /* Comment.Multiline */ 14 | .highlight .cp { color: #75715e } /* Comment.Preproc */ 15 | .highlight .c1 { color: #75715e } /* Comment.Single */ 16 | .highlight .cs { color: #75715e } /* Comment.Special */ 17 | .highlight .ge { font-style: italic } /* Generic.Emph */ 18 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 19 | .highlight .kc { color: #66d9ef } /* Keyword.Constant */ 20 | .highlight .kd { color: #66d9ef } /* Keyword.Declaration */ 21 | .highlight .kn { color: #f92672 } /* Keyword.Namespace */ 22 | .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ 23 | .highlight .kr { color: #66d9ef } /* Keyword.Reserved */ 24 | .highlight .kt { color: #66d9ef } /* Keyword.Type */ 25 | .highlight .ld { color: #e6db74 } /* Literal.Date */ 26 | .highlight .m { color: #ae81ff } /* Literal.Number */ 27 | .highlight .s { color: #e6db74 } /* Literal.String */ 28 | .highlight .na { color: #a6e22e } /* Name.Attribute */ 29 | .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ 30 | .highlight .nc { color: #a6e22e } /* Name.Class */ 31 | .highlight .no { color: #66d9ef } /* Name.Constant */ 32 | .highlight .nd { color: #a6e22e } /* Name.Decorator */ 33 | .highlight .ni { color: #f8f8f2 } /* Name.Entity */ 34 | .highlight .ne { color: #a6e22e } /* Name.Exception */ 35 | .highlight .nf { color: #a6e22e } /* Name.Function */ 36 | .highlight .nl { color: #f8f8f2 } /* Name.Label */ 37 | .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ 38 | .highlight .nx { color: #a6e22e } /* Name.Other */ 39 | .highlight .py { color: #f8f8f2 } /* Name.Property */ 40 | .highlight .nt { color: #f92672 } /* Name.Tag */ 41 | .highlight .nv { color: #f8f8f2 } /* Name.Variable */ 42 | .highlight .ow { color: #f92672 } /* Operator.Word */ 43 | .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ 44 | .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ 45 | .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ 46 | .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ 47 | .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ 48 | .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ 49 | .highlight .sc { color: #e6db74 } /* Literal.String.Char */ 50 | .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ 51 | .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ 52 | .highlight .se { color: #ae81ff } /* Literal.String.Escape */ 53 | .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ 54 | .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ 55 | .highlight .sx { color: #e6db74 } /* Literal.String.Other */ 56 | .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ 57 | .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ 58 | .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ 59 | .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ 60 | .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ 61 | .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ 62 | .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ 63 | .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ 64 | 65 | .highlight .gh { } /* Generic Heading & Diff Header */ 66 | .highlight .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */ 67 | .highlight .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */ 68 | .highlight .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */ -------------------------------------------------------------------------------- /assets/css/tags.sass: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | @mixin transition($args...) 4 | -webkit-transition: $args 5 | -moz-transition: $args 6 | -ms-transition: $args 7 | -o-transition: $args 8 | transition: $args 9 | 10 | .tag-chip 11 | color: #616161 12 | margin-right: 5px 13 | text-decoration: none 14 | 15 | &:hover 16 | div 17 | color: #fff 18 | background-color: #616161 19 | 20 | div 21 | @include transition(all .3s ease-in-out) 22 | 23 | .tag-div 24 | .divider 25 | margin: 20px 0 26 | 27 | .post-date 28 | margin-left: 10px 29 | 30 | ul 31 | &:not(.browser-default) 32 | &.tag-post 33 | padding-left: 0 34 | 35 | a 36 | text-decoration: none 37 | color: #00695c 38 | 39 | li 40 | list-style-position: inside 41 | padding-left: 40px 42 | 43 | &:hover 44 | list-style-type: circle 45 | padding-left: 20px 46 | 47 | @include transition(all .2s ease-in-out) -------------------------------------------------------------------------------- /assets/css/tools.sass: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | .card 4 | display: flex 5 | flex-wrap: wrap 6 | margin-bottom: 2em 7 | overflow: auto 8 | 9 | .card-image 10 | overflow-x: hidden 11 | flex: 3 12 | min-width: 300px 13 | 14 | .card-image-icon 15 | position: absolute 16 | top: 0 17 | right: 0 18 | i 19 | padding: 10px 20 | color: #fff 21 | font-size: 20px 22 | &:hover 23 | color: #2196F3 24 | border-radius: 50% 25 | border: 1px outset #26a69a 26 | a.card-title 27 | position: unset 28 | font-weight: bold 29 | color: #fff 30 | width: 100% 31 | height: 100% 32 | line-height: 100% 33 | justify-content: center 34 | word-break: break-all 35 | z-index: -1 36 | 37 | .card-content 38 | flex: 2 39 | min-width: 200px 40 | overflow: hidden 41 | font-size: 14px 42 | line-height: 110% 43 | 44 | span 45 | width: 100% 46 | -------------------------------------------------------------------------------- /assets/fonts/SourceCodePro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/fonts/SourceCodePro-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/icon-font.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/fonts/icon-font.woff2 -------------------------------------------------------------------------------- /assets/img/ad-huaweiyun-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/ad-huaweiyun-0.png -------------------------------------------------------------------------------- /assets/img/ad-huaweiyun-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/ad-huaweiyun-1.png -------------------------------------------------------------------------------- /assets/img/ad-huaweiyun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/ad-huaweiyun.png -------------------------------------------------------------------------------- /assets/img/alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/alipay.png -------------------------------------------------------------------------------- /assets/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/bg.png -------------------------------------------------------------------------------- /assets/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/favicon.ico -------------------------------------------------------------------------------- /assets/img/icons/access_time.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/call_split.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/chevron_left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/chevron_right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/clear.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/date_range.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/description.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/email.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/home.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/info.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/label.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/menu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/more_vert.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/person.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/rss_feed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/sort.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/icons/star.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/img/knight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/knight.png -------------------------------------------------------------------------------- /assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/logo.png -------------------------------------------------------------------------------- /assets/img/my-weixin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/my-weixin.png -------------------------------------------------------------------------------- /assets/img/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/user.png -------------------------------------------------------------------------------- /assets/img/wechat-slide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/wechat-slide.png -------------------------------------------------------------------------------- /assets/img/wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/wechat.png -------------------------------------------------------------------------------- /assets/img/wxpay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knightyun/knightyun.github.io/0bb13e7a5720183b39deb8ec6a89f7c5774a786a/assets/img/wxpay.png -------------------------------------------------------------------------------- /assets/js/min/about.min.js: -------------------------------------------------------------------------------- 1 | var elTypingText=document.querySelector(".typing-text"),typingTextArr=elTypingText.innerText.split(",").map((e=>e.trim()));elTypingText.innerHTML="",elTypingText.classList.remove("hidden");var options={el:elTypingText,textArr:typingTextArr,typeInterval:200,delInterval:200,typeDelInterval:1500,textInterval:0,cycleTimes:-1,isRandom:!0};async function typeDeleteTextArr(e){for(var t=!(e.cycleTimes>0);t||e.cycleTimes;){e.isRandom&&e.textArr.sort((()=>Math.random()-.5));for(let t=e.textArr.length;t>0;t--){var n={el:e.el,text:e.textArr[t-1],typeInterval:e.typeInterval,delInterval:e.delInterval,typeDelInterval:e.typeDelInterval};await typeDeleteText(n),await new Promise((t=>setTimeout(t,e.textInterval)))}e.cycleTimes--}}async function typeDeleteText(e){await typingText(e.el,e.text,e.typeInterval),await new Promise((t=>setTimeout(t,e.typeDelInterval))),await deletingText(e.el,e.delInterval)}async function typingText(e,t,n){var r=t.split(""),a=r.length;e.innerHTML="";var l=document.createElement("span");e.appendChild(l);for(let t=0;tsetTimeout(e,n)))}l.className="word-waiting"}async function deletingText(e,t){var n=document.createElement("span"),r=e.innerText.length;for(let a=0;asetTimeout(e,t)));n.className="word-waiting"}typeDeleteTextArr(options); -------------------------------------------------------------------------------- /assets/js/min/gen-category.min.js: -------------------------------------------------------------------------------- 1 | var categories=postContent.querySelectorAll("h1, h2, h3, h4, h5, h6");if(categories.length>0){var category=document.querySelector("#category"),categoryBtn=document.querySelector(".category-btn"),li=document.createElement("li"),a=document.createElement("a");a.className="waves-effect",category.classList.remove("hide"),categoryBtn.classList.remove("hide"),categories.forEach((e=>{var t=li.cloneNode(!1),c=a.cloneNode(!1);c.innerText=e.innerText,c.href="#"+e.id,t.appendChild(c),t.style.paddingLeft=32*e.nodeName.slice(-1)+"px",category.appendChild(t)}))} -------------------------------------------------------------------------------- /assets/js/min/main.min.js: -------------------------------------------------------------------------------- 1 | M.AutoInit(),Particles.init({selector:".particles",maxParticles:100,sizeVariations:5,speed:.5,color:["#ffffff","#eeeeee","#dddddd","#cccccc","#bbbbbb","#aaaaaa"],minDistance:100,connectParticles:!0,responsive:[{breakpoint:768,options:{maxParticles:60,minDistance:80}},{breakpoint:425,options:{maxParticles:50,minDistance:70}},{breakpoint:375,options:{maxParticles:40,minDistance:60}},{breakpoint:320,options:{maxParticles:30,minDistance:50}}]}); -------------------------------------------------------------------------------- /assets/js/min/post.min.js: -------------------------------------------------------------------------------- 1 | var postContent=document.querySelector("#post-content"),imgs=postContent.querySelectorAll("img"),len=imgs.length;for(let e=0;e{"A"===e.key&&e.ctrlKey&&e.shiftKey&&(getSelection().selectAllChildren(postContent),document.execCommand("copy"))})); -------------------------------------------------------------------------------- /assets/js/min/projects.min.js: -------------------------------------------------------------------------------- 1 | function toggleForked(){var e=document.querySelector(".fork-switch"),t=document.querySelector("div[id=forked]");e.checked?t.classList.remove("hidden"):t.classList.add("hidden")}document.addEventListener("DOMContentLoaded",(()=>{document.querySelectorAll(".geopattern").forEach((e=>{var t=GeoPattern.generate(e.dataset.patternId).toDataUrl();e.style.backgroundImage=t})),toggleForked()})); -------------------------------------------------------------------------------- /assets/js/min/search.min.js: -------------------------------------------------------------------------------- 1 | var elSearchBox=document.querySelector(".search"),elSearchBtn=document.querySelector(".search-start"),elSearchClear=document.querySelector(".search-clear"),elSearchInput=document.querySelector(".search-input"),elSearchResults=document.querySelector(".search-results"),searchValue="",arrItems=[],arrContents=[],arrLinks=[],arrTitles=[],arrResults=[],indexItem=[],itemLength=0,tmpDiv=document.createElement("div"),tmpAnchor=document.createElement("a"),isSearchFocused=!1,xhr=new XMLHttpRequest||new ActiveXObject("Microsoft.XMLHTTP");function searchConfirm(){if(""==elSearchInput.value)searchClear();else if(elSearchInput.value.search(/^\s+$/)>=0){searchInit();var e=tmpDiv.cloneNode(!0);e.innerText="请输入有效内容...",elSearchResults.appendChild(e)}else searchInit(),searchValue=elSearchInput.value,searchMatching(arrTitles,arrContents,searchValue)}function searchClear(){elSearchInput.value="",elSearchClear.style.display="none",elSearchResults.style.display="none",elSearchResults.classList.remove("result-item")}function searchInit(){arrResults=[],indexItem=[],elSearchResults.innerHTML="",elSearchClear.style.display="block",elSearchResults.style.display="block",elSearchResults.classList.add("result-item")}function searchMatching(e,t,r){var a;try{a=new RegExp(r,"i")}catch(e){var l=tmpDiv.cloneNode(!0);return l.innerHTML='正则表达式语法错误,特殊符号前考虑加上转义符:"∖"',l.className="pink-text result-item",void elSearchResults.appendChild(l)}for(i=0;i"+n[i].slice(s,s+o)+""+n[i].slice(s+o,s+o+10))}}var u=tmpDiv.cloneNode(!0);if(u.className="result-title",u.innerHTML="总匹配:"+indexItem.length+" 项",elSearchResults.appendChild(u),0==indexItem.length){var d=tmpDiv.cloneNode(!0);d.innerText="未匹配到内容...",d.className="teal-text text-darken-3 result-item",elSearchResults.appendChild(d)}for(i=0;i/g,""),arrLinks[i]=arrItems[i].getElementsByTagName("link")[0].childNodes[0].nodeValue.replace(/<.*?>/g,""),arrTitles[i]=arrItems[i].getElementsByTagName("title")[0].childNodes[0].nodeValue.replace(/<.*?>/g,"");elSearchBox.style.display="block"}},xhr.open("get","/feed.xml",!0),xhr.send(),elSearchBtn.onclick=searchConfirm,elSearchClear.onclick=searchClear,elSearchInput.oninput=function(){setTimeout(searchConfirm,0)},elSearchInput.onfocus=function(){isSearchFocused=!0},elSearchInput.onblur=function(){isSearchFocused=!1},window.addEventListener("load",searchClear),document.addEventListener("keydown",(function(e){isSearchFocused||"/"===e.key&&(e.preventDefault(),elSearchInput.focus(),window.isSearchFocused=!0)})); -------------------------------------------------------------------------------- /assets/js/min/tools.min.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded",(()=>{document.querySelectorAll(".geopattern").forEach((e=>{var t=GeoPattern.generate(e.dataset.patternId).toDataUrl();e.style.backgroundImage=t}))})); -------------------------------------------------------------------------------- /assets/js/normal/about.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 个性化展示个人介绍功能实现 3 | * Copyright (C) 2020 knightyun. 4 | */ 5 | 6 | var elTypingText = document.querySelector('.typing-text'); 7 | var typingTextArr = elTypingText.innerText.split(',').map(x => x.trim()); 8 | 9 | elTypingText.innerHTML = ''; 10 | elTypingText.classList.remove('hidden'); 11 | 12 | var options = { 13 | el: elTypingText, 14 | textArr: typingTextArr, 15 | typeInterval: 200, 16 | delInterval: 200, 17 | typeDelInterval: 1500, 18 | textInterval: 0, 19 | cycleTimes: -1, 20 | isRandom: true 21 | } 22 | 23 | typeDeleteTextArr(options); 24 | 25 | // 按指定时间间隔打印和删除一组单词 26 | // 27 | // Options | Type | Description 28 | //=========================================================================== 29 | // el | 'node' | 操作的元素 30 | // textArr | 'array' | 一组要打印和删除的文本 31 | // typeInterval | 'number' | 打印单个字符时间间隔 32 | // delInterval | 'number' | 删除单个字符时间间隔 33 | // typeDelInterval | 'number' | 打印与删除之间的时间间隔 34 | // textInterval | 'number' | 操作每条文本的时间间隔 35 | // cycleTimes | 'number' | 循环操作文本组的次数( > 0 ),<= 0 表示无限循环 36 | // isRandom | 'boolean' | 是否乱序操作文本组 37 | async function typeDeleteTextArr(options) { 38 | // 判断循环次数 39 | var isInfiniteLoop = options.cycleTimes > 0 ? false : true; 40 | 41 | while (isInfiniteLoop || options.cycleTimes) { 42 | // 判断文本数组是否乱序 43 | if (options.isRandom) 44 | options.textArr.sort(() => Math.random() - 0.5); 45 | 46 | for (let i = options.textArr.length; i > 0; i--) { 47 | var _options = { 48 | el: options.el, 49 | text: options.textArr[i - 1], 50 | typeInterval: options.typeInterval, 51 | delInterval: options.delInterval, 52 | typeDelInterval: options.typeDelInterval 53 | } 54 | // 打印和删除单条文本 55 | await typeDeleteText(_options); 56 | // 每组单词的时间间隔 57 | await new Promise(res => setTimeout(res, options.textInterval)); 58 | } 59 | 60 | options.cycleTimes--; 61 | } 62 | } 63 | 64 | // 按指定时间间隔打印和删除单词 65 | // 66 | // Options | Type | Description 67 | //====================================================== 68 | // el | 'node' | 操作的元素 69 | // text | 'array' | 一组要打印和删除的文本 70 | // typeInterval | 'number' | 打印单个字符的时间间隔 71 | // delInterval | 'number' | 删除单个字符的时间间隔 72 | // typeDelInterval | 'number' | 打印与删除之间的时间间隔 73 | async function typeDeleteText(options) { 74 | // 打印单词 75 | await typingText(options.el, options.text, options.typeInterval); 76 | // 打印与删除操作的时间间隔 77 | await new Promise(res => setTimeout(res, options.typeDelInterval)); 78 | // 删除单词 79 | await deletingText(options.el, options.delInterval); 80 | } 81 | 82 | // 按指定时间间隔打印单词 83 | async function typingText(el, text, typeInterval) { 84 | var words = text.split(''); 85 | var len = words.length; 86 | // 清空元素 87 | el.innerHTML = ''; 88 | // 创建光标 89 | var cursor = document.createElement('span'); 90 | el.appendChild(cursor); 91 | 92 | for (let i = 0; i < len; i++) { 93 | var elWord = document.createTextNode(words[i]); 94 | el.insertBefore(elWord, cursor); 95 | cursor.className = 'word-typing'; 96 | 97 | // 延时后进入下次循环 98 | await new Promise(res => setTimeout(res, typeInterval)); 99 | } 100 | // 光标闪烁 101 | cursor.className = 'word-waiting'; 102 | } 103 | 104 | // 按指定时间间隔删除单词 105 | async function deletingText(el, delInterval) { 106 | // 创建光标 107 | var cursor = document.createElement('span'); 108 | var len = el.innerText.length; 109 | 110 | // for (let i = len; i > 0; i--) { 111 | for (let i = 0; i < len; i++) { 112 | // 删除中停止闪烁光标 113 | cursor.className = 'word-typing'; 114 | // 删除最后一个字符以及光标 115 | el.innerText = el.innerText.slice(0, -1); 116 | el.appendChild(cursor); 117 | 118 | // 延时指定时间后进入下次循环 119 | await new Promise(res => setTimeout(res, delInterval)); 120 | } 121 | // 光标闪烁 122 | cursor.className = 'word-waiting'; 123 | } -------------------------------------------------------------------------------- /assets/js/normal/gen-category.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 文章页面生成侧栏目录 3 | * Copyright (C) 2020 knightyun. 4 | */ 5 | var categories = postContent.querySelectorAll('h1, h2, h3, h4, h5, h6'); 6 | 7 | if (categories.length > 0) { // 文章存在标题 8 | var category = document.querySelector('#category'), 9 | categoryBtn = document.querySelector('.category-btn'); 10 | var li = document.createElement('li'), 11 | a = document.createElement('a'); 12 | 13 | a.className = 'waves-effect'; 14 | // 存在目录则显示目录按钮和侧栏 15 | category.classList.remove('hide'); 16 | categoryBtn.classList.remove('hide'); 17 | 18 | categories.forEach(node => { 19 | // 每次 cloneNode 取代 createElement 20 | // 因为克隆一个元素快于创建一个元素 21 | var _li = li.cloneNode(false), 22 | _a = a.cloneNode(false); 23 | 24 | _a.innerText = node.innerText; 25 | // 为标题设置跳转链接 26 | _a.href = '#' + node.id; 27 | _li.appendChild(_a); 28 | // 为不同级别标题应用不同的缩进 29 | _li.style.paddingLeft = node.nodeName.slice(-1) * 32 + 'px'; 30 | category.appendChild(_li); 31 | }) 32 | } -------------------------------------------------------------------------------- /assets/js/normal/main.js: -------------------------------------------------------------------------------- 1 | // Materialize 全部插件初始化 2 | M.AutoInit(); 3 | 4 | // 粒子连线初始化 5 | Particles.init({ 6 | /* 7 | Option | Type | Default | Description 8 | ===================================================================================================== 9 | selector | string | - | Required: CSS selector of your canvas element 10 | maxParticles | integer | 100 | Optional: Maximum amount of particles 11 | sizeVariations | integer | 3 | Optional: Amount of size variations 12 | speed | integer | 0.5 | Optional: Movement speed of the particles 13 | color | string or string[] | #000000 | Optional: Color(s) of the particles and connecting lines 14 | minDistance | integer | 120 | Optional: Distance in px for connecting lines 15 | connectParticles | boolean | false | Optional: true/false if connecting lines should be drawn 16 | responsive | array | null | Optional: Array of objects containing breakpoints and options 17 | */ 18 | selector: '.particles', 19 | maxParticles: 100, 20 | sizeVariations: 5, 21 | speed: 0.5, 22 | color: ['#ffffff', '#eeeeee', '#dddddd', '#cccccc', '#bbbbbb', '#aaaaaa'], 23 | minDistance: 100, 24 | connectParticles: true, 25 | responsive: [{ 26 | breakpoint: 768, 27 | options: { 28 | maxParticles: 60, 29 | minDistance: 80 30 | } 31 | },{ 32 | breakpoint: 425, 33 | options: { 34 | maxParticles: 50, 35 | minDistance: 70 36 | } 37 | },{ 38 | breakpoint: 375, 39 | options: { 40 | maxParticles: 40, 41 | minDistance: 60 42 | } 43 | },{ 44 | breakpoint: 320, 45 | options: { 46 | maxParticles: 30, 47 | minDistance: 50 48 | } 49 | }] 50 | }) -------------------------------------------------------------------------------- /assets/js/normal/post.js: -------------------------------------------------------------------------------- 1 | var postContent = document.querySelector('#post-content'); 2 | var imgs = postContent.querySelectorAll('img'); 3 | var len = imgs.length; 4 | 5 | // 格式化显示所有文章图片 6 | for (let i = 0; i < len; i++) { 7 | imgs[i].classList.add('materialboxed'); 8 | imgs[i].classList.add('z-depth-4'); 9 | } 10 | 11 | // 初始化侧栏目录插件 12 | document.addEventListener('DOMContentLoaded', function () { 13 | var elemCategory = document.querySelector('#category'); 14 | M.Sidenav.init(elemCategory, { 15 | 'edge': 'right' 16 | }); 17 | }); 18 | 19 | // 选中文章内容并复制 20 | document.addEventListener('keyup', e => { 21 | if (e.key === 'A' && e.ctrlKey && e.shiftKey) { 22 | getSelection().selectAllChildren(postContent); 23 | document.execCommand('copy'); 24 | } 25 | }) -------------------------------------------------------------------------------- /assets/js/normal/projects.js: -------------------------------------------------------------------------------- 1 | function toggleForked() { 2 | var forkSwitch = document.querySelector('.fork-switch'), 3 | forked = document.querySelector('div[id=forked]'); 4 | 5 | if (forkSwitch.checked) { 6 | forked.classList.remove('hidden'); 7 | } else { 8 | forked.classList.add('hidden'); 9 | } 10 | } 11 | 12 | document.addEventListener('DOMContentLoaded', () => { 13 | document.querySelectorAll('.geopattern').forEach(el => { 14 | var pattern = GeoPattern.generate(el.dataset.patternId).toDataUrl(); 15 | el.style.backgroundImage = pattern; 16 | }); 17 | toggleForked(); 18 | }) -------------------------------------------------------------------------------- /assets/js/normal/tools.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', () => { 2 | document.querySelectorAll('.geopattern').forEach(el => { 3 | var pattern = GeoPattern.generate(el.dataset.patternId).toDataUrl(); 4 | el.style.backgroundImage = pattern; 5 | }); 6 | }); -------------------------------------------------------------------------------- /baidu_verify_Wkb0Jzk8yx.html: -------------------------------------------------------------------------------- 1 | Wkb0Jzk8yx -------------------------------------------------------------------------------- /categories.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: "Categories" 4 | css: ["categories.css"] 5 | --- 6 | {% include categories.html %} -------------------------------------------------------------------------------- /contact.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: "Contact me" 4 | css: ["contact.css"] 5 | --- 6 | {% include contact.html %} -------------------------------------------------------------------------------- /feed.xml: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | 5 | 6 | 7 | {{ site.title }} 8 | {{ site.url }} 9 | {{ site.description }} 10 | {{ site.time | date_to_rfc822 }} 11 | {% for post in site.posts %} 12 | 13 | {{ post.title | escape }} 14 | 15 | {{ post.url | prepend: site.url }} 16 | 17 | 18 | {{ post.content | escape }} 19 | 20 | {{ post.date | date_to_rfc822 }} 21 | 22 | {{ post.url | prepend: site.url }} 23 | 24 | 25 | {% endfor %} 26 | 27 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | css: ["index.css"] 4 | --- 5 |
6 | {% for post in paginator.posts %} 7 |
8 |
9 |
10 | {{post.title}} 11 |

12 | date_range 13 | {{post.date | date: "%d/%m/%Y %H:%M"}} 14 |

15 |

{{post.excerpt | remove: '

' | remove: '

'}}

16 |
17 | 22 |
23 |
24 | {% endfor %} 25 |
26 | 65 |
66 |
-------------------------------------------------------------------------------- /message.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: "留言板" 4 | --- 5 | {% include comment.html %} -------------------------------------------------------------------------------- /minify.cmd: -------------------------------------------------------------------------------- 1 | :: 用于 Windows 命令行下缩减所有 js 代码 2 | :: 需要系统预先安装 terser (npm install -g terser) 3 | @ for /r assets\js\normal %%i in (*) do @terser %%i -mc -o assets\js\min\%%~ni.min.js 4 | -------------------------------------------------------------------------------- /projects.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: "GitHub Projects" 4 | css: ["projects.css"] 5 | js: [ 6 | "https://cdnjs.cloudflare.com/ajax/libs/geopattern/1.2.3/js/geopattern.min.js", 7 | "projects.min.js" 8 | ] 9 | --- 10 | 11 | {% include projects.html %} -------------------------------------------------------------------------------- /tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: "Tags" 4 | css: ["tags.css"] 5 | --- 6 | {% include tags.html %} -------------------------------------------------------------------------------- /tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: "Online Tools" 4 | css: ["tools.css"] 5 | js: [ 6 | "https://cdnjs.cloudflare.com/ajax/libs/geopattern/1.2.3/js/geopattern.min.js", 7 | "tools.min.js" 8 | ] 9 | --- 10 | 11 | {% include tools.html %} --------------------------------------------------------------------------------