├── .github └── workflows │ └── depoly.yml ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── depoly.sh ├── docs ├── .vuepress │ ├── client.js │ ├── components │ │ ├── leetcodeLink.vue │ │ └── linkAndSolution.vue │ ├── config.js │ ├── js │ │ └── hello.js │ ├── layouts │ │ └── layout.vue │ ├── navbar │ │ ├── algorithm.js │ │ ├── books.js │ │ ├── frontend.js │ │ ├── golang.js │ │ ├── llm.js │ │ ├── python.js │ │ └── vueAnalysis.js │ ├── public │ │ ├── donate.jpg │ │ ├── icon.png │ │ └── logo.jpg │ ├── sidebar │ │ ├── algorithm.js │ │ ├── leetcode.js │ │ ├── rag.js │ │ ├── rollup.js │ │ ├── vueAnalysis.js │ │ ├── vueNextAnalysis.js │ │ └── webpack.js │ └── styles │ │ └── index.scss ├── README.md ├── algorithm │ ├── base │ │ ├── backTracking │ │ │ └── README.md │ │ ├── complexity │ │ │ └── README.md │ │ ├── divideAndConquer │ │ │ └── README.md │ │ ├── dynamicProgramming │ │ │ └── README.md │ │ ├── graph │ │ │ └── README.md │ │ ├── greedy │ │ │ └── README.md │ │ ├── hashMap │ │ │ └── README.md │ │ ├── heap │ │ │ └── README.md │ │ ├── introduction │ │ │ └── README.md │ │ ├── linkedList │ │ │ └── README.md │ │ ├── recommend │ │ │ └── README.md │ │ ├── search │ │ │ └── README.md │ │ ├── sort │ │ │ └── README.md │ │ ├── stackAndQueue │ │ │ └── README.md │ │ └── tree │ │ │ └── README.md │ └── leetcode │ │ ├── graph │ │ ├── easy │ │ │ └── README.md │ │ ├── hard │ │ │ └── README.md │ │ ├── medium │ │ │ └── README.md │ │ └── menu │ │ │ └── README.md │ │ ├── hashMap │ │ ├── easy │ │ │ └── README.md │ │ ├── hard │ │ │ └── README.md │ │ ├── medium │ │ │ └── README.md │ │ └── menu │ │ │ └── README.md │ │ ├── heap │ │ ├── easy │ │ │ └── README.md │ │ ├── hard │ │ │ └── README.md │ │ ├── medium │ │ │ └── README.md │ │ └── menu │ │ │ └── README.md │ │ ├── introduction │ │ └── README.md │ │ ├── linkedList │ │ ├── easy │ │ │ └── README.md │ │ ├── hard │ │ │ └── README.md │ │ ├── medium │ │ │ └── README.md │ │ └── menu │ │ │ └── README.md │ │ ├── queue │ │ ├── easy │ │ │ └── README.md │ │ ├── hard │ │ │ └── README.md │ │ ├── medium │ │ │ └── README.md │ │ └── menu │ │ │ └── README.md │ │ ├── recommend │ │ └── README.md │ │ ├── search │ │ ├── easy │ │ │ └── README.md │ │ ├── hard │ │ │ └── README.md │ │ ├── medium │ │ │ └── README.md │ │ └── menu │ │ │ └── README.md │ │ ├── stack │ │ ├── easy │ │ │ └── README.md │ │ ├── hard │ │ │ └── README.md │ │ ├── medium │ │ │ └── README.md │ │ └── menu │ │ │ └── README.md │ │ └── tree │ │ ├── easy │ │ └── README.md │ │ ├── hard │ │ └── README.md │ │ ├── medium │ │ └── README.md │ │ └── menu │ │ └── README.md ├── books │ ├── git │ │ └── README.md │ └── javascript │ │ ├── algorithm.md │ │ ├── es6.md │ │ ├── know-down.md │ │ ├── know-up.md │ │ ├── red-book.md │ │ └── vue.md ├── cssPrecompiler │ ├── sass │ │ └── README.md │ └── sassLoader │ │ └── README.md ├── designPattern │ └── README.md ├── git │ └── README.md ├── golang │ ├── base │ │ └── README.md │ ├── framework │ │ ├── gin.md │ │ └── gorm.md │ └── tools │ │ └── mod.md ├── images │ ├── books │ │ ├── fileUploadResult.png │ │ ├── tree0.png │ │ ├── tree1.png │ │ ├── tree10.png │ │ ├── tree11.png │ │ ├── tree12.png │ │ ├── tree13.png │ │ ├── tree14.png │ │ ├── tree2.png │ │ ├── tree3.png │ │ ├── tree4.png │ │ ├── tree5.png │ │ ├── tree6.png │ │ ├── tree7.png │ │ ├── tree8.png │ │ └── tree9.png │ ├── css │ │ ├── 1.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 14.gif │ │ ├── 15.png │ │ ├── 16.png │ │ ├── 17.png │ │ ├── 18.png │ │ ├── 19.png │ │ ├── 2.png │ │ ├── 20.gif │ │ ├── 3.png │ │ ├── 4.gif │ │ ├── 4.png │ │ ├── 5.gif │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ ├── 9.png │ │ ├── number-bg.png │ │ ├── number-filp-process.png │ │ └── number-filp.gif │ ├── flex │ │ ├── JDExplame.png │ │ ├── JDResult1.png │ │ ├── columnResult.png │ │ ├── columnReverseResult.png │ │ ├── contentCenterResult.png │ │ ├── contentEndResult.png │ │ ├── contentStartResult.png │ │ ├── dicResult.png │ │ ├── firstDicResult.png │ │ ├── fiveDicResult.png │ │ ├── flexCenterResult.png │ │ ├── flexEndResult.png │ │ ├── flexResult.png │ │ ├── flexStartResult.png │ │ ├── floatThreeResult.png │ │ ├── fourDicResult.png │ │ ├── gridResult.png │ │ ├── gridResult2.png │ │ ├── holyGralyResult.png │ │ ├── nineDicResult.png │ │ ├── nowrapResult.png │ │ ├── nowrapResult1.png │ │ ├── padding+marginResult.png │ │ ├── position+marginResult.png │ │ ├── position+transformResult.png │ │ ├── qidianExplame.png │ │ ├── qidianResult.png │ │ ├── qunarExample.png │ │ ├── qunarResult.png │ │ ├── rowResult.png │ │ ├── rowReverseResult.png │ │ ├── secondDicResult.png │ │ ├── sixDicResult.png │ │ ├── spaceAroundResult.png │ │ ├── spaceBetweenResult.png │ │ ├── steamFlexResult1.png │ │ ├── steamFlexResult2.png │ │ ├── steamResult1.png │ │ ├── steamResult2.png │ │ ├── stickyFooterResult1.png │ │ ├── stickyFooterResult2.png │ │ ├── stickyFooterResult3.png │ │ ├── threeDicResult.png │ │ ├── wrapResult.png │ │ └── wrapReverseResult.png │ ├── git │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ └── 5.png │ ├── interview │ │ ├── 1.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.jpg │ │ ├── 13.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.gif │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ └── 9.png │ ├── python │ │ ├── python-family.png │ │ ├── python-vscode.png │ │ └── try-except.png │ ├── rag │ │ ├── rag-architecture.png │ │ ├── rag-chunk-viz.png │ │ ├── rag_chroma_server.png │ │ ├── rag_embedding.png │ │ └── rag_embedding_history.png │ ├── test │ │ ├── vue-test1.png │ │ ├── vue-test2.png │ │ ├── vue-test3.png │ │ └── vue-test4.png │ ├── typescript │ │ ├── 1.png │ │ └── 2.png │ ├── vue │ │ ├── 1.jpg │ │ ├── 1.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 14.png │ │ ├── 15.png │ │ ├── 16.png │ │ ├── 17.png │ │ ├── 18.png │ │ ├── 19.png │ │ ├── 2.png │ │ ├── 20.png │ │ ├── 21.png │ │ ├── 22.png │ │ ├── 23.png │ │ ├── 24.png │ │ ├── 29.png │ │ ├── 3.png │ │ ├── 30.png │ │ ├── 31.png │ │ ├── 32.png │ │ ├── 33.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ ├── 9.png │ │ ├── lifecycle.png │ │ ├── transition.png │ │ └── vuex.png │ ├── vueAnalysis │ │ ├── $mount.png │ │ ├── composition.png │ │ ├── computed.png │ │ ├── data.png │ │ ├── dom.png │ │ ├── eventsMixin.png │ │ ├── initGlobalAPI.png │ │ ├── initGlobalAPIProcess.png │ │ ├── initMixin.png │ │ ├── instance.png │ │ ├── lifecycleMixin.png │ │ ├── methods.png │ │ ├── notify.png │ │ ├── process.png │ │ ├── props.png │ │ ├── reactive.png │ │ ├── renderMixin.png │ │ ├── stateMixin.png │ │ ├── vdom-hooks.png │ │ └── vue-process.png │ ├── vuepress │ │ ├── 1.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 14.png │ │ ├── 15.png │ │ ├── 16.png │ │ ├── 17.png │ │ ├── 18.png │ │ ├── 19.png │ │ ├── 2.png │ │ ├── 20.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ └── 9.png │ └── webpack │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 14.png │ │ ├── 16.png │ │ ├── 17.png │ │ ├── 19.png │ │ ├── 2.png │ │ ├── 20.png │ │ ├── 21.png │ │ ├── 22.png │ │ ├── 23.png │ │ ├── 24.png │ │ ├── 25.png │ │ ├── 251.png │ │ ├── 26.png │ │ ├── 261.png │ │ ├── 27.png │ │ ├── 28.png │ │ ├── 281.png │ │ ├── 29.png │ │ ├── 30.png │ │ ├── 31.png │ │ ├── 32.png │ │ ├── 33.png │ │ ├── 5.png │ │ ├── 6.png │ │ └── 9.png ├── interview │ └── README.md ├── python │ ├── advanced │ │ └── README.md │ └── base │ │ └── README.md ├── rag │ ├── base │ │ └── README.md │ ├── basic │ │ ├── compare │ │ │ └── README.md │ │ ├── langchain │ │ │ └── README.md │ │ ├── langgraph │ │ │ └── README.md │ │ └── prepare │ │ │ └── README.md │ ├── chunking │ │ ├── README.md │ │ └── methods │ │ │ └── README.md │ ├── embedding │ │ ├── README.md │ │ ├── dense │ │ │ └── README.md │ │ ├── hybrid │ │ │ └── README.md │ │ ├── similarity │ │ │ └── README.md │ │ └── sparse │ │ │ └── README.md │ ├── loader │ │ ├── README.md │ │ ├── csv │ │ │ └── README.md │ │ ├── db │ │ │ └── README.md │ │ ├── document │ │ │ └── README.md │ │ ├── html │ │ │ └── README.md │ │ ├── json │ │ │ └── README.md │ │ ├── markdown │ │ │ └── README.md │ │ ├── ocr │ │ │ └── README.md │ │ ├── pdf │ │ │ └── README.md │ │ └── text │ │ │ └── README.md │ └── vectorStore │ │ ├── README.md │ │ ├── chroma │ │ └── README.md │ │ └── milvus │ │ └── README.md ├── rollup │ ├── README.md │ ├── babel │ │ └── README.md │ ├── base │ │ └── README.md │ ├── changelog │ │ └── README.md │ ├── commit │ │ └── README.md │ ├── concept │ │ └── README.md │ ├── config │ │ └── README.md │ ├── environment │ │ └── README.md │ ├── eslint │ │ └── README.md │ ├── jest │ │ └── README.md │ ├── package │ │ └── README.md │ ├── plugins │ │ └── README.md │ └── typescript │ │ └── README.md ├── test │ └── vueTest.md ├── typescript │ ├── base.md │ └── challenge.md ├── vite │ └── README.md ├── vueAnalysis │ ├── compile │ │ ├── README.md │ │ ├── codegen.md │ │ ├── compileToFunctions.md │ │ ├── optimize.md │ │ └── parse.md │ ├── component │ │ ├── README.md │ │ ├── async.md │ │ ├── createComponent.md │ │ ├── createElement.md │ │ ├── lifecycle.md │ │ ├── merge.md │ │ ├── mount.md │ │ ├── patch.md │ │ ├── register.md │ │ └── render.md │ ├── design │ │ └── README.md │ ├── dom │ │ ├── README.md │ │ ├── diff.md │ │ └── vnode.md │ ├── entry │ │ ├── README.md │ │ ├── events.md │ │ ├── global.md │ │ ├── init.md │ │ ├── lifecycle.md │ │ ├── render.md │ │ └── state.md │ ├── expand │ │ ├── README.md │ │ ├── directive.md │ │ ├── event.md │ │ ├── filter.md │ │ ├── keep-alive.md │ │ ├── plugin.md │ │ ├── slot.md │ │ ├── transition-group.md │ │ ├── transition.md │ │ └── vmodel.md │ ├── introduction │ │ └── README.md │ ├── reactive │ │ ├── README.md │ │ ├── api.md │ │ ├── computed.md │ │ ├── data.md │ │ ├── dep.md │ │ ├── methods.md │ │ ├── nexttick.md │ │ ├── notify.md │ │ ├── prepare.md │ │ ├── problem.md │ │ ├── props.md │ │ ├── reactive.md │ │ └── watch.md │ ├── rollup │ │ ├── README.md │ │ └── vue.md │ ├── router │ │ ├── README.md │ │ ├── change.md │ │ ├── components.md │ │ ├── hooks.md │ │ ├── install.md │ │ └── matcher.md │ └── vuex │ │ ├── README.md │ │ ├── api.md │ │ ├── init.md │ │ ├── install.md │ │ └── utils.md ├── vueNextAnalysis │ ├── catalog │ │ └── README.md │ ├── component │ │ ├── README.md │ │ ├── createApp.md │ │ ├── lifecycle.md │ │ ├── mount.md │ │ ├── register.md │ │ ├── render.md │ │ └── setup.md │ ├── introduction │ │ ├── README.md │ │ └── optimization.md │ ├── monorepo │ │ └── README.md │ ├── reactivity │ │ ├── README.md │ │ ├── base.md │ │ ├── computed.md │ │ ├── reactive.md │ │ ├── readonly.md │ │ ├── ref.md │ │ ├── track.md │ │ ├── trigger.md │ │ └── watch.md │ └── rollup │ │ └── README.md ├── vuepress │ └── README.md └── webpack │ ├── tapable │ └── README.md │ └── webpack │ ├── README.md │ ├── advanced.md │ ├── case.md │ ├── core.md │ ├── install.md │ ├── loader.md │ ├── optimization.md │ ├── plugin.md │ ├── source.md │ ├── start.md │ └── static.md ├── donate.jpg └── package.json /.github/workflows/depoly.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Depoly Github Pages 3 | 4 | on: 5 | # 提交到master分支触发 6 | push: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | # 拉取代码 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | 18 | # 设置node版本 19 | - name: Set Node Version 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: 20 23 | 24 | # 打包 25 | - name: Build 26 | run: npm install && npm run build 27 | 28 | # 部署到gh-pages 29 | - name: Depoly 30 | uses: JamesIves/github-pages-deploy-action@releases/v3 31 | with: 32 | ACCESS_TOKEN: ${{secrets.ACCESS_TOKEN}} 33 | BRANCH: gh-pages 34 | FOLDER: docs/.vuepress/dist 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | docs/.vuepress/dist 2 | docs/.vuepress/.cache 3 | docs/.vuepress/.temp 4 | node_modules 5 | package-lock.json 6 | .temp -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "vuepress", 4 | "leetcode", 5 | "wangtunan", 6 | "Gorm", 7 | "gorm", 8 | "instanceof", 9 | "gitee", 10 | "Repobeats", 11 | "langchain", 12 | "langgraph", 13 | "milvus", 14 | "Faiss", 15 | "Qdrant", 16 | "mathrm", 17 | "numpy", 18 | "chromadb", 19 | "katex", 20 | "metadatas" 21 | ] 22 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | 记录个人博客,见证成长之路
3 | 4 | Github博客地址:https://wangtunan.github.io/blog/
5 | Gitee国内镜像:http://wangtunan.gitee.io/blog/(已废弃)
6 | 7 | ## 仓库活跃度 8 | ![Repobeats analytics image](https://repobeats.axiom.co/api/embed/d13add3751990882fb078ce20d5b32a1a93e5407.svg) 9 | 10 | ## RAG 11 | [RAG基础](https://wangtunan.github.io/blog/rag/base/) 12 | 13 | ## Python 14 | [Python快速入门](https://wangtunan.github.io/blog/python/base)
15 | [Python高级技巧](https://wangtunan.github.io/blog/python/advanced)
16 | 17 | ## 面试 18 | [前端面试之道](https://wangtunan.github.io/blog/interview/) 19 | 20 | ## 前端书籍阅读笔记 21 | [你不知道的 JavaScript 上](https://wangtunan.github.io/blog/books/javascript/know-up.html)
22 | [你不知道的 JavaScript 中下](https://wangtunan.github.io/blog/books/javascript/know-down.html)
23 | [深入理解 ES6](https://wangtunan.github.io/blog/books/javascript/es6.html)
24 | [JavaScript 设计模式与开发实践](https://wangtunan.github.io/blog/designPattern/)
25 | [JavaScript 数据结构和算法](https://wangtunan.github.io/blog/books/javascript/algorithm.html)
26 | 27 | ## Vue 源码分析 28 | [Vue2.0 源码分析](https://wangtunan.github.io/blog/vueAnalysis/introduction/)
29 | [Vue3.0 源码分析](https://wangtunan.github.io/blog/vueNextAnalysis/introduction/)
30 | 31 | ## 算法 32 | [数据结构和算法基础](https://wangtunan.github.io/blog/algorithm/base/introduction/)
33 | [LeetCode刷题](https://wangtunan.github.io/blog/algorithm/leetcode/introduction/)
34 | 35 | ## 打包工具 36 | [Webpack4 基础知识](https://wangtunan.github.io/blog/webpack/webpack/)
37 | [Rollup 基础知识](https://wangtunan.github.io/blog/rollup/)
38 | [Vite 基础知识](https://wangtunan.github.io/blog/vite/)
39 | 40 | ## TypeScript 41 | [TypeScript 基础知识](https://wangtunan.github.io/blog/typescript/base)
42 | [TypeScript 类型挑战](https://wangtunan.github.io/blog/typescript/challenge)
43 | 44 | ## CSS预编译器 45 | [SASS 基础知识](https://wangtunan.github.io/blog/cssPrecompiler/sass/)
46 | 47 | ## 自动化测试 48 | [Vue 应用测试](https://wangtunan.github.io/blog/test/vueTest.html)
49 | 50 | ## VuePress 51 | [VuePress 基础知识](https://wangtunan.github.io/blog/vuepress/)
52 | 53 | ## 鼓励作者 54 | 如果你觉得博客写得还不错,可以帮忙点个star或者打赏犒劳一下 55 | 56 | ![打赏](https://wangtunan.github.io/blog/donate.jpg) 57 | -------------------------------------------------------------------------------- /depoly.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 确保脚本抛出遇到的错误 4 | set -e 5 | 6 | # 生成静态文件 7 | npm run build 8 | 9 | # 进入生成的文件夹 10 | cd docs/.vuepress/dist 11 | 12 | # 如果是发布到自定义域名 13 | # echo 'www.example.com' > CNAME 14 | 15 | git init 16 | git add -A 17 | git commit -m 'depoly脚本更新' 18 | 19 | git config user.name wangtunan 20 | git config user.email why583440138@gmail.com 21 | 22 | # 如果发布到 https://.github.io 23 | # git push -f git@github.com:/.github.io.git master 24 | 25 | # 如果发布到 https://.github.io/ 26 | # git push -f git@github.com:wangtunan/blog.git master:gh-pages 27 | git push -f git@github.com:wangtunan/blog.git master:gh-pages 28 | cd - -------------------------------------------------------------------------------- /docs/.vuepress/client.js: -------------------------------------------------------------------------------- 1 | import { defineClientConfig } from '@vuepress/client' 2 | import Layout from './layouts/layout.vue' 3 | 4 | export default defineClientConfig({ 5 | enhance ({ router }) { 6 | const isProduction = process.env.NODE_ENV === 'production' 7 | if (isProduction) { 8 | router.afterEach(function (to) { 9 | const { fullPath } = to 10 | if (typeof _hmt !== 'undefined' && fullPath) { 11 | _hmt.push(["_trackPageview", fullPath]); 12 | } 13 | }); 14 | } 15 | }, 16 | layouts: { 17 | Layout 18 | } 19 | }) -------------------------------------------------------------------------------- /docs/.vuepress/components/leetcodeLink.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /docs/.vuepress/components/linkAndSolution.vue: -------------------------------------------------------------------------------- 1 | 17 | 36 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | import { registerComponentsPlugin } from '@vuepress/plugin-register-components' 2 | import { commentPlugin } from '@vuepress/plugin-comment' 3 | import { getDirname, path } from '@vuepress/utils' 4 | import { viteBundler } from '@vuepress/bundler-vite' 5 | import { defineUserConfig } from 'vuepress' 6 | import { defaultTheme } from '@vuepress/theme-default' 7 | import { baiduAnalyticsPlugin } from '@vuepress/plugin-baidu-analytics' 8 | import { markdownMathPlugin } from '@vuepress/plugin-markdown-math' 9 | import { prismjsPlugin } from '@vuepress/plugin-prismjs' 10 | 11 | 12 | import frontEndNav from './navbar/frontend.js' 13 | import vueAnalysisNav from './navbar/vueAnalysis.js' 14 | import algorithmNav from './navbar/algorithm.js' 15 | import booksNav from './navbar/books.js' 16 | import pythonNav from './navbar/python.js' 17 | import llmNav from './navbar/llm.js' 18 | 19 | import webpackSidebar from './sidebar/webpack.js' 20 | import rollupSidebar from './sidebar/rollup.js' 21 | import vueAnalysisSidebar from './sidebar/vueAnalysis.js' 22 | import vueNextAnalysisSidebar from './sidebar/vueNextAnalysis.js' 23 | import algorithmSidebar from './sidebar/algorithm.js' 24 | import leetCodeSidebar from './sidebar/leetcode.js' 25 | import ragSidebar from './sidebar/rag.js' 26 | 27 | const __dirname = getDirname(import.meta.url) 28 | 29 | export default defineUserConfig({ 30 | title: '汪图南', 31 | description: '汪图南的个人博客', 32 | base: '/blog/', 33 | lang: 'zh-CN', 34 | head: [ 35 | ['link', { rel: 'icon', href: '/blog/icon.png' }], 36 | ], 37 | port: 3000, 38 | theme: defaultTheme({ 39 | editLink: false, 40 | contributorsText: '贡献者', 41 | lastUpdatedText: '最后更新时间', 42 | repo: 'https://github.com/wangtunan/blog', 43 | repoLabel: 'Github', 44 | navbar: [ 45 | ...llmNav, 46 | ...pythonNav, 47 | { 48 | text: '前端面试之道', 49 | link: '/interview/' 50 | }, 51 | ...frontEndNav, 52 | ...vueAnalysisNav, 53 | ...algorithmNav, 54 | ...booksNav 55 | ], 56 | sidebar: { 57 | '/webpack/webpack/': webpackSidebar, 58 | '/rollup/': rollupSidebar, 59 | '/vueAnalysis/': vueAnalysisSidebar, 60 | '/vueNextAnalysis/': vueNextAnalysisSidebar, 61 | '/algorithm/base/': algorithmSidebar, 62 | '/algorithm/leetcode/': leetCodeSidebar, 63 | '/rag/': ragSidebar 64 | } 65 | }), 66 | bundler: viteBundler({ 67 | viteOptions: { 68 | resolve: { 69 | alias: { 70 | '@images': path.resolve(__dirname, '../images') 71 | } 72 | }, 73 | ssr: { 74 | noExternal: ["vuepress-shared"], 75 | } 76 | } 77 | }), 78 | plugins: [ 79 | baiduAnalyticsPlugin({ 80 | id: '1876f64fd31c9aba1a7a5e157813a075' 81 | }), 82 | registerComponentsPlugin({ 83 | componentsDir: path.resolve(__dirname, './components') 84 | }), 85 | commentPlugin({ 86 | provider: "Giscus", 87 | repo: 'wangtunan/blog', 88 | repoId: 'MDEwOlJlcG9zaXRvcnkxNzcyMzkwNDg=', 89 | category: 'Announcements', 90 | categoryId: 'DIC_kwDOCpB0CM4CZkha', 91 | mapping: "pathname", 92 | lang: 'zh-CN' 93 | }), 94 | markdownMathPlugin({ 95 | type: 'katex', 96 | }), 97 | prismjsPlugin({ 98 | lineNumbers: false 99 | }) 100 | ] 101 | }) 102 | -------------------------------------------------------------------------------- /docs/.vuepress/js/hello.js: -------------------------------------------------------------------------------- 1 | export function Hello () { 2 | console.log('Hello, Vuepress') 3 | } 4 | -------------------------------------------------------------------------------- /docs/.vuepress/layouts/layout.vue: -------------------------------------------------------------------------------- 1 | 8 | 34 | -------------------------------------------------------------------------------- /docs/.vuepress/navbar/algorithm.js: -------------------------------------------------------------------------------- 1 | // 算法nav导航 2 | const algorithmNav = [ 3 | { 4 | text: '算法', 5 | children: [ 6 | { 7 | text: '数据结构和算法(基础)', 8 | link: '/algorithm/base/introduction/' 9 | }, 10 | { 11 | text: 'LeetCode(刷题)', 12 | link: '/algorithm/leetcode/introduction/' 13 | } 14 | ] 15 | } 16 | ] 17 | 18 | export default algorithmNav -------------------------------------------------------------------------------- /docs/.vuepress/navbar/books.js: -------------------------------------------------------------------------------- 1 | // 书籍 2 | const booksNav = [ 3 | { 4 | text: '书籍', 5 | children: [ 6 | { 7 | text: 'JavaScript书籍', 8 | children: [ 9 | { 10 | text: '你不知道的JavaScript(上)', 11 | link: '/books/javascript/know-up/' 12 | }, 13 | { 14 | text: '你不知道的JavaScript(中下)', 15 | link: '/books/javascript/know-down/' 16 | }, 17 | { 18 | text: 'JavaScript数据结构和算法', 19 | link: '/books/javascript/algorithm/' 20 | }, 21 | { 22 | text: 'JavaScript设计模式与开发实践', 23 | link: '/designPattern/' 24 | }, 25 | { 26 | text: '深入理解ES6', 27 | link: '/books/javascript/es6/' 28 | } 29 | ] 30 | }, 31 | { 32 | text: 'Git书籍', 33 | children: [ 34 | { 35 | text: '精通Git', 36 | link: '/books/git/' 37 | } 38 | ] 39 | } 40 | ] 41 | } 42 | ] 43 | 44 | export default booksNav -------------------------------------------------------------------------------- /docs/.vuepress/navbar/frontend.js: -------------------------------------------------------------------------------- 1 | // 前端技术栈nav导航 2 | const frontEndNav = [ 3 | { 4 | text: '前端技术栈', 5 | children: [ 6 | { 7 | text: '打包工具', 8 | children: [ 9 | { 10 | text: 'Webpack', 11 | link: '/webpack/webpack/' 12 | }, 13 | { 14 | text: 'Rollup', 15 | link: '/rollup/' 16 | } 17 | ] 18 | }, 19 | { 20 | text: 'TypeScript', 21 | children: [ 22 | { 23 | text: 'TypeScript基础', 24 | link: '/typescript/base/' 25 | }, 26 | { 27 | text: 'TypeScript类型挑战', 28 | link: '/typescript/challenge/' 29 | } 30 | ] 31 | }, 32 | { 33 | text: 'CSS预编译器', 34 | children: [ 35 | { 36 | text: 'SASS', 37 | link: '/cssPrecompiler/sass/' 38 | } 39 | ] 40 | }, 41 | { 42 | text: '自动化测试', 43 | children: [ 44 | { 45 | text: 'Vue应用测试', 46 | link: '/test/vueTest/' 47 | } 48 | ] 49 | } 50 | ] 51 | } 52 | ] 53 | 54 | export default frontEndNav -------------------------------------------------------------------------------- /docs/.vuepress/navbar/golang.js: -------------------------------------------------------------------------------- 1 | // golang导航 2 | const golangNav = [ 3 | { 4 | text: 'Golang技术栈', 5 | children: [ 6 | { 7 | text: 'Go基础', 8 | link: '/golang/base/' 9 | }, 10 | 11 | { 12 | text: 'Go框架', 13 | children: [ 14 | { 15 | text: 'Gin', 16 | link: '/golang/framework/gin/' 17 | }, 18 | { 19 | text: 'Gorm', 20 | link: '/golang/framework/gorm/' 21 | } 22 | ] 23 | }, 24 | { 25 | text: 'Go工具', 26 | children: [ 27 | { 28 | text: 'Go Modules', 29 | link: '/golang/mod/' 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | ] 36 | 37 | export default golangNav -------------------------------------------------------------------------------- /docs/.vuepress/navbar/llm.js: -------------------------------------------------------------------------------- 1 | // llm导航 2 | const llmNav = [ 3 | { 4 | text: 'LLM', 5 | children: [ 6 | { 7 | text: 'RAG', 8 | children: [ 9 | { 10 | text: 'RAG', 11 | link: '/rag/base/' 12 | } 13 | ] 14 | } 15 | ] 16 | } 17 | ] 18 | 19 | export default llmNav -------------------------------------------------------------------------------- /docs/.vuepress/navbar/python.js: -------------------------------------------------------------------------------- 1 | // python导航 2 | const pythonNav = [ 3 | { 4 | text: 'Python技术栈', 5 | children: [ 6 | { 7 | text: '快速入门', 8 | link: '/python/base/' 9 | }, 10 | { 11 | text: '高级技巧', 12 | link: '/python/advanced/' 13 | } 14 | ] 15 | } 16 | ] 17 | 18 | export default pythonNav -------------------------------------------------------------------------------- /docs/.vuepress/navbar/vueAnalysis.js: -------------------------------------------------------------------------------- 1 | // Vue源码nav导航 2 | const vueAnalysisNav = [ 3 | { 4 | text: 'Vue源码分析', 5 | children: [ 6 | { 7 | text: 'Vue2.0源码分析', 8 | link: '/vueAnalysis/introduction/' 9 | }, 10 | { 11 | text: 'Vue3.0源码分析', 12 | link: '/vueNextAnalysis/introduction/' 13 | } 14 | ] 15 | } 16 | ] 17 | 18 | export default vueAnalysisNav -------------------------------------------------------------------------------- /docs/.vuepress/public/donate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/.vuepress/public/donate.jpg -------------------------------------------------------------------------------- /docs/.vuepress/public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/.vuepress/public/icon.png -------------------------------------------------------------------------------- /docs/.vuepress/public/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/.vuepress/public/logo.jpg -------------------------------------------------------------------------------- /docs/.vuepress/sidebar/algorithm.js: -------------------------------------------------------------------------------- 1 | // 数据结构和算法目录结构 2 | const algorithmBaseSidebar = [ 3 | { 4 | text: '介绍', 5 | collapsable: false, 6 | children: [ 7 | '/algorithm/base/introduction/' 8 | ] 9 | }, 10 | { 11 | text: '推荐', 12 | collapsable: false, 13 | children: [ 14 | '/algorithm/base/recommend/' 15 | ] 16 | }, 17 | { 18 | text: '算法基础', 19 | collapsable: false, 20 | children: [ 21 | '/algorithm/base/complexity/', 22 | '/algorithm/base/linkedList/', 23 | '/algorithm/base/stackAndQueue/', 24 | '/algorithm/base/hashMap/', 25 | '/algorithm/base/tree/', 26 | '/algorithm/base/heap/', 27 | '/algorithm/base/graph/', 28 | '/algorithm/base/search/', 29 | '/algorithm/base/sort/', 30 | '/algorithm/base/divideAndConquer/', 31 | '/algorithm/base/backTracking/', 32 | '/algorithm/base/dynamicProgramming/', 33 | '/algorithm/base/greedy/' 34 | ] 35 | } 36 | ] 37 | 38 | export default algorithmBaseSidebar -------------------------------------------------------------------------------- /docs/.vuepress/sidebar/leetcode.js: -------------------------------------------------------------------------------- 1 | // LeetCode刷题目录结构 2 | const leetCodeSidebar = [ 3 | { 4 | text: '介绍', 5 | collapsable: false, 6 | children: [ 7 | '/algorithm/leetcode/introduction/' 8 | ] 9 | }, 10 | { 11 | text: '推荐', 12 | collapsable: false, 13 | children: [ 14 | '/algorithm/leetcode/recommend/' 15 | ] 16 | }, 17 | { 18 | text: '链表', 19 | collapsable: false, 20 | children: [ 21 | '/algorithm/leetcode/linkedList/menu/', 22 | '/algorithm/leetcode/linkedList/easy/', 23 | '/algorithm/leetcode/linkedList/medium/', 24 | '/algorithm/leetcode/linkedList/hard/' 25 | ] 26 | }, 27 | { 28 | text: '栈', 29 | collapsable: false, 30 | children: [ 31 | '/algorithm/leetcode/stack/menu/', 32 | '/algorithm/leetcode/stack/easy/', 33 | '/algorithm/leetcode/stack/medium/', 34 | '/algorithm/leetcode/stack/hard/', 35 | ] 36 | }, 37 | { 38 | text: '队列', 39 | collapsable: false, 40 | children: [ 41 | '/algorithm/leetcode/queue/menu/', 42 | '/algorithm/leetcode/queue/easy/', 43 | '/algorithm/leetcode/queue/medium/', 44 | '/algorithm/leetcode/queue/hard/' 45 | ] 46 | }, 47 | { 48 | text: '哈希表', 49 | collapsable: false, 50 | children: [ 51 | '/algorithm/leetcode/hashMap/menu/', 52 | '/algorithm/leetcode/hashMap/easy/', 53 | '/algorithm/leetcode/hashMap/medium/', 54 | '/algorithm/leetcode/hashMap/hard/' 55 | ] 56 | }, 57 | { 58 | text: '二叉树', 59 | collapsable: false, 60 | children: [ 61 | '/algorithm/leetcode/tree/menu/', 62 | '/algorithm/leetcode/tree/easy/', 63 | '/algorithm/leetcode/tree/medium/', 64 | '/algorithm/leetcode/tree/hard/' 65 | ] 66 | }, 67 | { 68 | text: '堆', 69 | collapsable: false, 70 | children: [ 71 | '/algorithm/leetcode/heap/menu/', 72 | '/algorithm/leetcode/heap/easy/', 73 | '/algorithm/leetcode/heap/medium/', 74 | '/algorithm/leetcode/heap/hard/' 75 | ] 76 | }, 77 | { 78 | text: '图', 79 | collapsable: false, 80 | children: [ 81 | '/algorithm/leetcode/graph/menu/', 82 | '/algorithm/leetcode/graph/easy/', 83 | '/algorithm/leetcode/graph/medium/', 84 | '/algorithm/leetcode/graph/hard/' 85 | ] 86 | }, 87 | { 88 | text: '搜索', 89 | collapsable: false, 90 | children: [ 91 | '/algorithm/leetcode/search/menu/', 92 | '/algorithm/leetcode/search/easy/', 93 | '/algorithm/leetcode/search/medium/', 94 | '/algorithm/leetcode/search/hard/' 95 | ] 96 | }, 97 | ] 98 | 99 | export default leetCodeSidebar -------------------------------------------------------------------------------- /docs/.vuepress/sidebar/rag.js: -------------------------------------------------------------------------------- 1 | // RAG目录结构 2 | const ragSidebar = [ 3 | { 4 | text: 'RAG基础', 5 | collapsable: false, 6 | children: [ 7 | '/rag/base/' 8 | ] 9 | }, 10 | { 11 | text: '简易RAG', 12 | collapsable: false, 13 | children: [ 14 | '/rag/basic/prepare/', 15 | '/rag/basic/langchain/', 16 | '/rag/basic/langgraph/', 17 | '/rag/basic/compare/' 18 | ] 19 | }, 20 | { 21 | text: '数据导入(Loader)', 22 | collapsable: false, 23 | children: [ 24 | '/rag/loader/', 25 | '/rag/loader/document/', 26 | '/rag/loader/text/', 27 | '/rag/loader/json/', 28 | '/rag/loader/html/', 29 | '/rag/loader/markdown/', 30 | '/rag/loader/csv/', 31 | '/rag/loader/ocr/', 32 | '/rag/loader/pdf/', 33 | '/rag/loader/db/' 34 | ] 35 | }, 36 | { 37 | text: '文本切块(Chunking)', 38 | collapsable: false, 39 | children: [ 40 | '/rag/chunking/', 41 | '/rag/chunking/methods/' 42 | ] 43 | }, 44 | { 45 | text: '数据嵌入(Embedding)', 46 | collapsable: false, 47 | children: [ 48 | '/rag/embedding/', 49 | '/rag/embedding/similarity/', 50 | '/rag/embedding/sparse/', 51 | '/rag/embedding/dense/', 52 | '/rag/embedding/hybrid/', 53 | ] 54 | }, 55 | { 56 | text: '向量存储(VectorStore)', 57 | collapsable: false, 58 | children: [ 59 | '/rag/vectorStore/', 60 | '/rag/vectorStore/chroma/', 61 | '/rag/vectorStore/milvus/' 62 | ] 63 | } 64 | ] 65 | 66 | export default ragSidebar -------------------------------------------------------------------------------- /docs/.vuepress/sidebar/rollup.js: -------------------------------------------------------------------------------- 1 | // rollup目录结构 2 | const rollupSidebar = [ 3 | { 4 | text: 'Rollup基础', 5 | collapsable: false, 6 | children: [ 7 | '/rollup/', 8 | '/rollup/concept/', 9 | '/rollup/base/', 10 | '/rollup/config/', 11 | '/rollup/package/', 12 | '/rollup/plugins/' 13 | ] 14 | }, 15 | { 16 | text: 'Rollup配置案例', 17 | collapsable: false, 18 | children: [ 19 | '/rollup/babel/', 20 | '/rollup/typescript/', 21 | '/rollup/environment/', 22 | '/rollup/eslint/', 23 | '/rollup/jest/', 24 | '/rollup/commit/', 25 | '/rollup/changelog/' 26 | ] 27 | } 28 | ] 29 | 30 | export default rollupSidebar -------------------------------------------------------------------------------- /docs/.vuepress/sidebar/vueNextAnalysis.js: -------------------------------------------------------------------------------- 1 | // Vue3.0源码分析目录结构 2 | const vueNextAnalysisSidebar = [ 3 | { 4 | text: '介绍', 5 | collapsable: false, 6 | children: [ 7 | '/vueNextAnalysis/introduction/', 8 | '/vueNextAnalysis/introduction/optimization.md' 9 | ] 10 | }, 11 | { 12 | text: 'Monorepo和Rollup', 13 | collapsable: false, 14 | children: [ 15 | '/vueNextAnalysis/monorepo/', 16 | '/vueNextAnalysis/rollup/' 17 | ] 18 | }, 19 | { 20 | text: '源码目录', 21 | collapsable: false, 22 | children: [ 23 | '/vueNextAnalysis/catalog/' 24 | ] 25 | }, 26 | { 27 | text: '响应式原理', 28 | collapsable: false, 29 | children: [ 30 | '/vueNextAnalysis/reactivity/', 31 | '/vueNextAnalysis/reactivity/base', 32 | '/vueNextAnalysis/reactivity/ref', 33 | '/vueNextAnalysis/reactivity/reactive', 34 | '/vueNextAnalysis/reactivity/computed', 35 | '/vueNextAnalysis/reactivity/readonly' 36 | ] 37 | }, 38 | { 39 | text: '组件化', 40 | collapsable: false, 41 | children: [ 42 | '/vueNextAnalysis/component/', 43 | '/vueNextAnalysis/component/createApp', 44 | '/vueNextAnalysis/component/setup', 45 | '/vueNextAnalysis/component/mount', 46 | '/vueNextAnalysis/component/lifecycle', 47 | '/vueNextAnalysis/component/register', 48 | '/vueNextAnalysis/component/render' 49 | ] 50 | } 51 | ] 52 | 53 | 54 | export default vueNextAnalysisSidebar -------------------------------------------------------------------------------- /docs/.vuepress/sidebar/webpack.js: -------------------------------------------------------------------------------- 1 | // webpack目录结构 2 | const webpackSidebar = [{ 3 | text: 'Webpack', 4 | collapsable: false, 5 | children: [ 6 | '/webpack/webpack/', 7 | '/webpack/webpack/source.md', 8 | '/webpack/webpack/install.md', 9 | '/webpack/webpack/start.md', 10 | '/webpack/webpack/static.md', 11 | '/webpack/webpack/core.md', 12 | '/webpack/webpack/advanced.md', 13 | '/webpack/webpack/case.md', 14 | '/webpack/webpack/optimization.md', 15 | '/webpack/webpack/loader.md', 16 | '/webpack/webpack/plugin.md' 17 | ] 18 | }] 19 | 20 | export default webpackSidebar 21 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --content-width: 1100px; 3 | } 4 | 5 | :not(pre)>code { 6 | background-color: #fff5f5; 7 | color: #ff502c; 8 | } 9 | 10 | .customer-page-class { 11 | color: #fb3; 12 | background-color: #333; 13 | } 14 | 15 | .vp-navbar { 16 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); 17 | border-bottom: 0; 18 | } -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | lang: zh-CN 4 | heroText: A Personal Blog 5 | heroImage: /logo.jpg 6 | actionText: 开始 → 7 | actionLink: /interview/ 8 | features: 9 | - title: A Blog 10 | details: 专注写作前端博客,记录日常所得。 11 | - title: For Me 12 | details: 故九万里,则风斯在下矣,而后乃今培风;背负青天,而莫之夭阏者,而后乃今将图南。 13 | - title: For Future 14 | details: 记录个人博客,见证成长之路。 15 | footer: Copyright © 2019-present Wangtunan 16 | --- 17 | 18 | ## 鼓励作者 19 | 如果你觉得博客写得还不错,可以帮忙点个star或者打赏犒劳一下 20 | 21 | ![打赏](https://wangtunan.github.io/blog/donate.jpg) -------------------------------------------------------------------------------- /docs/algorithm/base/greedy/README.md: -------------------------------------------------------------------------------- 1 | # 贪心 2 | 3 | ## 贪心算法 4 | 5 | ## 分数背包问题 6 | 7 | ## 最多容量问题 8 | 9 | ## 最大切分乘积问题 10 | 11 | ## 参考 12 | * [Hello 算法 贪心](https://www.hello-algo.com/chapter_greedy/) -------------------------------------------------------------------------------- /docs/algorithm/base/heap/README.md: -------------------------------------------------------------------------------- 1 | # 堆 2 | **堆(heap)**:是一种满足特定条件的完全二叉树,主要分为两种类型,如下: 3 | * **大顶堆**:任意节点的值 >= 其子节点的值。 4 | * **小顶堆**:任意节点的值 <= 其子节点的值。 5 | 6 | 堆作为完全二叉树的特例,具有以下特性: 7 | 1. 最底层节点靠左填充,其它层的节点都被填满。 8 | 2. 我们将堆的二叉树根节点称为**堆顶**,底层最靠右的节点称为**堆底**。 9 | 3. 对于大顶堆(小顶堆),根节点堆顶元素的值分别是最大值(最小值)。 10 | 11 | ![堆](https://www.hello-algo.com/chapter_heap/heap.assets/min_heap_and_max_heap.png) 12 | 13 | ## 堆常见操作和实现 14 | 15 | 堆通常用来实现优先队列,大顶堆相当于元素从大到小的顺序出队的优先队列,从使用角度讲,优先队列和堆相同的数据结构。 16 | 17 | 堆的常见操作如下: 18 | * `push()`:元素入堆。 19 | * `pop()`:堆顶元素出堆。 20 | * `peek()`:访问堆顶元素。 21 | * `size()`:获取堆的元素数量。 22 | * `isEmpty()`:判断堆是否为空。 23 | * `left()`:获取左子节点索引。 24 | * `right()`:获取右子节点索引。 25 | * `parent()`:获取父节点索引。 26 | * `swap()`:交换两个节点的值。 27 | * `siftUp()`:向上堆化。 28 | * `siftDown()`:向下堆化。 29 | 30 | 完整代码请参考,[基于数组实现的大顶堆](https://github.com/wangtunan/js-algorithm/blob/master/src/heap/maxHeap.js)。 31 | 32 | ## 堆的常见应用 33 | * **优先队列**: 堆通常作为实现优先队列的首选数据结构,其入队和出队操作的时间复杂度均为O(logn),而建队操作为O(n),这些操作都非常高效。 34 | * **堆排序**:给定一组数据,我们可以用它们建立一个堆,然后不断地执行元素出堆操作,从而得到有序数据。 35 | * **获取最大的第K个元素**;这是一个经典的算法问题,同时也是一种典型应用,例如选择热度前 10 的新闻作为微博热搜,选取销量前 10 的商品等。 36 | 37 | ## Top K问题 38 | ::: tip 39 | 问题:给定一个长度为`N`的无序数组,请返回数组中前`K`大的元素。 40 | ::: 41 | 42 | 实现`Top K`问题,有以下几种方案,其对比如下: 43 | * **遍历**:其解决问题思路是在第1轮找到第一大的元素,第2轮找到第二大的元素,`K`越趋近于`N`,效率越差,时间复杂度为`O(n²)`。 44 | * **排序**:先对数组进行完整从大到小(从小到大)排序,再返回前`K`个元素或后`K`个元素,其时间复杂度为`O(nlogn)`。 45 | * **堆**:基于小顶堆的特性,高效完成`Top K`问题。时间复杂度范围为`O(n) ~ O(nlogn)` 46 | 47 | 基于小顶堆解决`Top K`问题的思路如下: 48 | 1. 初始化一个小顶堆,其堆顶元素值最小。 49 | 2. 先将数组前`K`个元素依次入堆。 50 | 3. 从第`K + 1`个元素开始,如果当前元素大于堆顶元素,则将堆顶元素出堆,并将当前元素入堆。 51 | 4. 遍历完成后,堆中保存的就是最大的`K`个元素。 52 | 53 | ![Top K元素出堆](https://www.hello-algo.com/chapter_heap/top_k.assets/top_k_heap_step4.png) 54 | 55 | 完整代码请参考,[基于小顶堆实现Top K问题](https://github.com/wangtunan/js-algorithm/blob/master/src/heap/topKHeap.js)。 56 | -------------------------------------------------------------------------------- /docs/algorithm/base/introduction/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 介绍。。。。 -------------------------------------------------------------------------------- /docs/algorithm/base/recommend/README.md: -------------------------------------------------------------------------------- 1 | # 算法相关推荐 2 | 3 | ## 推荐书籍 4 | * [Hello 算法](https://www.hello-algo.com/) 5 | * [JavaScript数据结构和算法](https://www.ituring.com.cn/book/2653) 6 | -------------------------------------------------------------------------------- /docs/algorithm/base/stackAndQueue/README.md: -------------------------------------------------------------------------------- 1 | # 栈和队列 2 | 3 | ## 栈 4 | 栈`Stack`是一种遵循先入后出逻辑的线性数据结构。 5 | 6 | 栈数据结构一般而言有如下几种概念: 7 | 1. 栈数据结构的顶部叫做**栈顶**。 8 | 2. 栈数据结构的底部叫做**栈底**。 9 | 3. 移除栈顶元素的过程叫做**出栈**。 10 | 4. 向栈顶添加元素的过程叫做**入栈**或者**压栈**。 11 | 12 | ![栈](https://www.hello-algo.com/chapter_stack_and_queue/stack.assets/stack_operations.png) 13 | 14 | 根据以上概念或过程,一般栈有如下几种常见操作: 15 | 1. 入栈`push()`,时间复杂度`O(1)`。 16 | 2. 出栈`pop()`,时间复杂度`O(1)`。 17 | 3. 访问栈顶元素`peek()`,时间复杂度`O(1)`。 18 | 19 | 根据不同语言的不同特性,栈有不同的实现方式,在`JavaScript`中,可以使用数组或者链表来实现栈结构。其中栈结构的属性和方法如下: 20 | * `push()`:向栈顶添加一个元素。 21 | * `pop()`:移除栈顶元素。 22 | * `peek()`:访问栈顶元素。 23 | * `isEmpty()`: 判断栈结构是否为空。 24 | * `clear()`:清空栈中所有元素。 25 | * `getSize()`: 获取栈中元素个数。 26 | * `toArray()`:返回栈数组结构。 27 | 28 | ### 栈数组实现 29 | 栈的数组实现,请参考[ArrayStack](https://github.com/wangtunan/js-algorithm/blob/master/src/stack/arrayStack.js) 30 | 31 | ### 栈的链表实现 32 | 栈的链表实现,请参考[LinkedListStack](https://github.com/wangtunan/js-algorithm/blob/master/src/stack/linkedListStack.js) 33 | 34 | ### 两种实现方式对比 35 | **时间效率**: 36 | 1. 基于数组实现的栈,如果入栈的数量超过初始容量,会触发扩容操作,此时效率会变低,但平均效率高。 37 | 2. 基于链表实现的栈,可以提供比较稳定的效率表现。 38 | 39 | **空间效率**: 40 | 1. 基于数组实现的栈,在扩容后可能会存在一定的空间浪费。 41 | 2. 基于链表实现的栈,需要额外存储节点指针,空间开销相对比较大。 42 | 43 | ### 栈的典型应用 44 | * **浏览器的前进,后退;软件中的撤销,反撤销**:当打开网页时,会将上一个网页进行入栈操作,这样我们可以通过浏览器的后退功能回到上一页,其中后退操作其实就是出栈。 45 | * **程序内存管理**:每次调用函数时,系统都会在栈顶添加一个栈帧,用于记录函数的上下文信息。在递归函数中,向下递推阶段会不断执行入栈操作,而向上回溯阶段则会执行出栈操作。 46 | 47 | ## 队列 48 | 队列`Queue`是一种遵循先入先出规则的线性数据结构。 49 | 50 | 队列数据结构一般而言有如下几种概念: 51 | 1. 队列的头部叫做**队首**。 52 | 2. 队列的尾部叫做**队尾**。 53 | 3. 队列的尾部添加元素叫**入队**。 54 | 4. 队列的头部移除元素叫**出队**。 55 | 56 | ![队列](https://www.hello-algo.com/chapter_stack_and_queue/queue.assets/queue_operations.png) 57 | 58 | 根据以上概念或过程,一般队列有如下几种常见操作: 59 | 1. 入队`push()`,时间复杂度`O(1)`。 60 | 2. 出队`pop()`,时间复杂度`O(1)`。 61 | 3. 访问队首元素`peek()`,时间复杂度`O(1)`。 62 | 63 | 根据不同语言的不同特性,队列有不同的实现方式,在`JavaScript`中,可以使用数组或者链表来实现队列结构。其中队列结构的属性和方法如下: 64 | * `push()`:入队,向队列尾部添加一个元素。 65 | * `pop()`:出队,移除队首元素。 66 | * `peek()`:访问队首元素。 67 | * `isEmpty()`: 判断队列结构是否为空。 68 | * `clear()`:清空队列中所有元素。 69 | * `getSize()`: 获取队列元素个数。 70 | * `toArray()`:返回队列数组结构。 71 | 72 | ### 队列数组实现 73 | 队列的数组实现,请参考[ArrayQueue](https://github.com/wangtunan/js-algorithm/blob/master/src/queue/arrayQueue.js) 74 | 75 | ### 队列链表实现 76 | 队列的链表实现,请参考[LinkedListQueue](https://github.com/wangtunan/js-algorithm/blob/master/src/queue/linkedListQueue.js) 77 | 78 | ### 队列典型应用 79 | * **购物商城订单**:购物者下单后,订单将加入队列中,系统随后会根据顺序依次处理队列中的订单。 80 | * **各类待办事项**:任何需要实现“先来后到”功能的场景,例如打印机的任务队列、餐厅的出餐队列等。队列在这些场景中可以有效地维护处理顺序。 81 | 82 | ## 双端队列 83 | 在队列`Queue`中,我们仅能在队首删除元素,队尾添加元素。为了增加灵活性,双端队列`Dequeue`允许我们在队首和队尾添加和删除元素。 84 | ![双端队列](https://www.hello-algo.com/chapter_stack_and_queue/deque.assets/deque_operations.png) 85 | 86 | 根据双端队列的特性,一般双端队列有如下几种常见操作: 87 | 1. 队首入队`pushFirst`,时间复杂度`O(1)`。 88 | 2. 队尾入队`pushLast`,时间复杂度`O(1)`。 89 | 3. 队首出队`popFirst`,时间复杂度`O(1)`。 90 | 4. 队尾出队`popLast`,时间复杂度`O(1)`。 91 | 5. 访问队首元素`peekFirst`,时间复杂度`O(1)`。 92 | 6. 访问队尾元素`peekLast`,时间复杂度`O(1)`。 93 | 94 | ### 双端队列数组实现 95 | 双端队列的数组实现,请参考[ArrayDequeue](https://github.com/wangtunan/js-algorithm/blob/master/src/queue/arrayDequeue.js) 96 | 97 | ### 双端队列链表实现 98 | 双端队列的链表实现,请参考[LinkedListDequeue](https://github.com/wangtunan/js-algorithm/blob/master/src/queue/linkedListDequeue.js) 99 | 100 | ### 双端队列典型应用 101 | 双向队列兼具栈与队列的逻辑,因此它可以实现这两者的所有应用场景,同时提供更高的自由度。 102 | 103 | 许多软件的**撤销**功能通常使用栈来实现:系统每次将更改操作`push`到栈中,然后通过`pop`实现撤销。然而实际场景下,会考虑到系统资源占用情况,例如只存储50次更改操作。超过时,需要在栈底(队首)执行删除操作,但栈是无法做到在栈底执行删除操作的,所以需要使用**双端队列**来实现。 104 | 105 | ## 参考 106 | * [Hello 算法 栈和队列](https://www.hello-algo.com/chapter_stack_and_queue/) -------------------------------------------------------------------------------- /docs/algorithm/leetcode/graph/easy/README.md: -------------------------------------------------------------------------------- 1 | # 简单 -------------------------------------------------------------------------------- /docs/algorithm/leetcode/graph/hard/README.md: -------------------------------------------------------------------------------- 1 | # 困难 -------------------------------------------------------------------------------- /docs/algorithm/leetcode/graph/menu/README.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | 3 | | LeetCode题目 | 难度 | 4 | | ------ | --- | 5 | | [200.岛屿的数量](https://leetcode.cn/problems/number-of-islands/) | 中等 | 6 | | [207.课程表](https://leetcode.cn/problems/course-schedule) | 中等 | 7 | | [208.实现 Trie (前缀树)](https://leetcode.cn/problems/implement-trie-prefix-tree) | 中等 | 8 | | [994.腐烂的橘子](https://leetcode.cn/problems/rotting-oranges) | 中等 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/hashMap/easy/README.md: -------------------------------------------------------------------------------- 1 | # 简单 2 | 3 | ## 1.两数之和 4 | 5 | 6 | ```js 7 | // n表示nums数组的长度 8 | // 时间复杂度:O(n),需要遍历一遍数组 9 | // 空间复杂度:O(n),为哈希表存储开销 10 | var twoSum = function (nums, target) { 11 | const map = {}; 12 | for (let i = 0; i < nums.length; i++) { 13 | const diff = target - nums[i]; 14 | if (map.hasOwnProperty(diff)) { 15 | return [map[diff], i]; 16 | } else { 17 | map[nums[i]] = i; 18 | } 19 | } 20 | return []; 21 | }; 22 | ``` 23 | 24 | ## 242.有效的字母异位词 25 | 26 | 27 | ```js 28 | // n为最长字符串的长度 29 | // 时间复杂度:O(n),需要遍历一次最长的字符串 30 | // 空间复杂度:O(1),仅为字符串26个字母数组的内存开销 31 | var isAnagram = function (s, t) { 32 | if (s.length !== t.length) { 33 | return false; 34 | } 35 | let map = new Array(26).fill(0); 36 | for (let i = 0; i < s.length; i++) { 37 | map[s.charCodeAt(i) - 97]++; 38 | } 39 | for (let j = 0; j < t.length; j++) { 40 | const currCode = t.charCodeAt(j) - 97; 41 | map[currCode]--; 42 | if (map[currCode] < 0) { 43 | return false; 44 | } 45 | } 46 | return true; 47 | }; 48 | ``` -------------------------------------------------------------------------------- /docs/algorithm/leetcode/hashMap/hard/README.md: -------------------------------------------------------------------------------- 1 | # 困难 2 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/hashMap/medium/README.md: -------------------------------------------------------------------------------- 1 | # 中等 2 | 3 | ## 49.字母异位词分组 4 | 5 | 6 | 方法一:排序 7 | ```js 8 | // m和n分别表示strs数组的长度以及其中字符串长度最长的元素 9 | // 时间复杂度:O(mnlogn), nlogn表示需要字符串元素进行排序 10 | // 空间复杂度:O(mn),维护哈希表的内存开销 11 | var groupAnagrams = function (strs) { 12 | const map = {}; 13 | for (let i = 0; i < strs.length; i++) { 14 | const newStr = strs[i].split('').sort().join(','); 15 | if (map.hasOwnProperty(newStr)) { 16 | map[newStr].push(strs[i]); 17 | } else { 18 | map[newStr] = [strs[i]]; 19 | } 20 | } 21 | return Object.values(map); 22 | }; 23 | ``` 24 | 25 | 方法二:质数乘积 26 | ```js 27 | // way2: 质数乘积 28 | // m和n分别表示strs数组的长度以及其中字符串长度最长的元素 29 | // 时间复杂度:O(mn), 需要遍历一遍strs字符串以及每次迭代的字符串的每个字母 30 | // 空间复杂度:O(mn),维护哈希表的内存开销 31 | var groupAnagrams = function (strs) { 32 | const prime = [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]; 33 | const map = {}; 34 | for (let i = 0; i < strs.length; i++) { 35 | const str = strs[i]; 36 | let sum = 1; 37 | for (let j = 0; j < str.length; j++) { 38 | sum *= prime[str.charCodeAt(j) - 97]; 39 | } 40 | if (map.hasOwnProperty(sum)) { 41 | map[sum].push(str); 42 | } else { 43 | map[sum] = [str]; 44 | } 45 | } 46 | return Object.values(map); 47 | }; 48 | ``` 49 | 50 | ## 128.最长连续序列 51 | 52 | 53 | ```js 54 | // n为nums数组的长度 55 | // 时间复杂度:O(n),需要遍历一遍数组 56 | // 时间复杂度:O(n),去重后哈希表的内存开销 57 | var longestConsecutive = function (nums) { 58 | const numsSet = new Set(nums); 59 | let length = 0; 60 | for (const num of numsSet) { 61 | if (!numsSet.has(num - 1)) { 62 | let currNum = num; 63 | let currLength = 1; 64 | while (numsSet.has(currNum + 1)) { 65 | currNum++; 66 | currLength++; 67 | } 68 | length = Math.max(length, currLength); 69 | } 70 | } 71 | return length; 72 | }; 73 | ``` -------------------------------------------------------------------------------- /docs/algorithm/leetcode/hashMap/menu/README.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | | LeetCode题目 | 难度 | 3 | | ------ | --- | 4 | | [1.两数之和](https://leetcode.cn/problems/two-sum) | 简单 | 5 | | [242.有效的字母异位词](https://leetcode.cn/problems/valid-anagram) | 简单 | 6 | | [49.字母异位词分组](https://leetcode.cn/problems/group-anagrams) | 中等 | 7 | | [128.最长连续序列](https://leetcode.cn/problems/longest-consecutive-sequence) | 中等 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/heap/easy/README.md: -------------------------------------------------------------------------------- 1 | # 简单 2 | 撰写中。。。 -------------------------------------------------------------------------------- /docs/algorithm/leetcode/heap/hard/README.md: -------------------------------------------------------------------------------- 1 | # 困难 2 | 3 | ## 295.数据流的中位数 4 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/heap/medium/README.md: -------------------------------------------------------------------------------- 1 | # 中等 2 | 3 | ## 215.数组中的第K个最大元素 4 | 5 | 6 | 方法一:基于大顶堆排序 7 | ```js 8 | class MaxHeap { 9 | constructor(nums) { 10 | const size = nums.length; 11 | this.nums = nums; 12 | for (let i = Math.floor(size / 2) - 1; i >= 0; i--) { 13 | this.maxHeapify(i, size); 14 | } 15 | } 16 | swap(i, j) { 17 | const temp = this.nums[i]; 18 | this.nums[i] = this.nums[j]; 19 | this.nums[j] = temp; 20 | } 21 | maxHeapify(i, size) { 22 | while (true) { 23 | let l = 2 * i + 1; 24 | let r = 2 * i + 2; 25 | let m = i; 26 | if (l < size && this.nums[l] > this.nums[m]) { 27 | m = l; 28 | } 29 | if (r < size && this.nums[r] > this.nums[m]) { 30 | m = r; 31 | } 32 | if (m === i) { 33 | break; 34 | } 35 | this.swap(m, i) 36 | i = m; 37 | } 38 | } 39 | } 40 | 41 | // way1: 基于大顶堆 42 | // n为数组的元素长度 43 | // 时间复杂度:O(nlogn),O(nlogn) 44 | // 空间复杂度:O(logn),递归使用栈空间的开销 45 | var findKthLargest = function (nums, k) { 46 | let size = nums.length; 47 | const heap = new MaxHeap(nums); 48 | for (let i = nums.length - 1; i >= nums.length - k + 1; i--) { 49 | heap.swap(0, i); 50 | --size; 51 | heap.maxHeapify(0, size); 52 | } 53 | return nums[0]; 54 | }; 55 | ``` 56 | 57 | ## 347.前K个高频元素 58 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/heap/menu/README.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | | LeetCode题目 | 难度 | 3 | | ------ | --- | 4 | | [215.数组中的第K个最大元素](https://leetcode.cn/problems/kth-largest-element-in-an-array) | 中等 | 5 | | [347.前K个高频元素](https://leetcode.cn/problems/top-k-frequent-elements) | 中等 | 6 | | [295.数据流的中位数](https://leetcode.cn/problems/find-median-from-data-stream) | 困难 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/introduction/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 介绍 -------------------------------------------------------------------------------- /docs/algorithm/leetcode/linkedList/hard/README.md: -------------------------------------------------------------------------------- 1 | # 困难 2 | ## 23.合并K个升序链表 3 | 4 | 5 | 6 | 基础:合并两个有序链表。 7 | ```js 8 | var mergeTwoLists = function(list1, list2) { 9 | const dummy = new ListNode(0) 10 | let curr = dummy 11 | 12 | while(list1 !== null && list2 !== null) { 13 | if (list1.val <= list2.val) { 14 | curr.next = list1 15 | list1 = list1.next 16 | } else { 17 | curr.next = list2 18 | list2 = list2.next 19 | } 20 | curr = curr.next 21 | } 22 | 23 | curr.next = list1 === null ? list2 : list1 24 | 25 | return dummy.next 26 | } 27 | ``` 28 | 29 | 方法一:顺序合并 30 | ```js 31 | // n为链表的长度,k为链表的个数 32 | // 时间复杂度:O(k²n),两两合并 33 | // 空间复杂度:O(1),仅定义常量 34 | var mergeKLists = function(lists) { 35 | let head = null 36 | for(let i = 0; i < lists.length; i++) { 37 | head = mergeTwoLists(head, lists[i]) 38 | } 39 | return head 40 | }; 41 | ``` 42 | 43 | 方法二:分而治之 44 | ```js 45 | // n为链表的长度,k为链表的个数 46 | // 时间复杂度:O(kn * logn) 47 | // 空间复杂度:O(logk),递归时栈空间的开销 48 | var merge = function(lists, start, end) { 49 | if (start === end) { 50 | return lists[start] 51 | } else if (start > end) { 52 | return null 53 | } else { 54 | const middle = (start + end) >> 1 55 | return mergeTwoLists( 56 | merge(lists, start, middle), 57 | merge(lists, middle + 1, end) 58 | ) 59 | } 60 | } 61 | var mergeKLists = function(lists) { 62 | return merge(lists, 0, lists.length - 1) 63 | } 64 | ``` 65 | 66 | ## 25.K个一组翻转链表 67 | 68 | 69 | ```js 70 | // n为链表的长度 71 | // 时间复杂度:O(n),需要(n/k)次迭代。 72 | // 时间复杂度:O(1),仅定义常量。 73 | var reverseList = function(head, tail) { 74 | let prev = null; 75 | let curr = head; 76 | while(prev !== tail) { 77 | const next = curr.next; 78 | curr.next = prev; 79 | prev = curr; 80 | curr = next; 81 | } 82 | return [tail, head]; 83 | }; 84 | 85 | var reverseKGroup = function (head, k) { 86 | const dummy = new ListNode(0, head); 87 | let pre = dummy; 88 | 89 | while (head) { 90 | let tail = pre; 91 | for (let i = 0; i < k; i++) { 92 | tail = tail.next; 93 | if (!tail) { 94 | return dummy.next; 95 | } 96 | } 97 | 98 | const next = tail.next; 99 | [head, tail] = reverseList(head, tail); 100 | pre.next = head; 101 | tail.next = next; 102 | pre = tail; 103 | head = tail.next; 104 | } 105 | 106 | return dummy.next; 107 | }; 108 | ``` 109 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/linkedList/menu/README.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | | LeetCode题目 | 难度 | 3 | | ------ | --- | 4 | | [21.合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/) | 简单 | 5 | | [141.环形链表](https://leetcode.cn/problems/linked-list-cycle/) | 简单 | 6 | | [160.相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists/) | 简单 | 7 | | [206.反转链表](https://leetcode.cn/problems/reverse-linked-list/) | 简单 | 8 | | [234.回文链表](https://leetcode.cn/problems/palindrome-linked-list/) | 简单 | 9 | | [2.两数相加](https://leetcode.cn/problems/add-two-numbers/) | 中等 | 10 | | [19.删除链表倒数第N个节点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/) | 中等 | 11 | | [24.两两交互链表中的节点](https://leetcode.cn/problems/swap-nodes-in-pairs/) | 中等 | 12 | | [138.随机链表的复制](https://leetcode.cn/problems/copy-list-with-random-pointer/) | 中等 | 13 | | [142.环形链表Ⅱ](https://leetcode.cn/problems/linked-list-cycle-ii/) | 中等 | 14 | | [146.LRU缓存](https://leetcode.cn/problems/lru-cache) | 中等 | 15 | | [148.排序链表](https://leetcode.cn/problems/sort-list) | 中等 | 16 | | [23.合并K个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists) | 困难 | 17 | | [25.K个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group) | 困难 | 18 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/queue/easy/README.md: -------------------------------------------------------------------------------- 1 | # 简单 2 | 3 | ## 41.数据流中的移动平均值 4 | 5 | 6 | ```js 7 | // n为窗口大小size 8 | // 时间复杂度:O(1),next时往数组尾部添加元素,时间复杂度O(1) 9 | // 空间复杂度:O(n),队列数组的内存开销 10 | var MovingAverage = function(size) { 11 | this.queue = []; 12 | this.size = size; 13 | this.sum = 0; 14 | }; 15 | MovingAverage.prototype.next = function(val) { 16 | if (this.queue.length >= this.size) { 17 | this.sum -= this.queue.shift(); 18 | } 19 | this.sum += val; 20 | this.queue.push(val); 21 | return this.sum / this.queue.length; 22 | }; 23 | ``` -------------------------------------------------------------------------------- /docs/algorithm/leetcode/queue/hard/README.md: -------------------------------------------------------------------------------- 1 | # 困难 2 | 撰写中。。。 -------------------------------------------------------------------------------- /docs/algorithm/leetcode/queue/medium/README.md: -------------------------------------------------------------------------------- 1 | # 中等 2 | 3 | ## 200.岛屿的数量 4 | 5 | 6 | 方法一:广度优先遍历BFS 7 | ```js 8 | // way1: 广度优先遍历 9 | // m和n分别为矩阵行的数量和列的数量 10 | // 时间复杂度:O(m * n) 11 | // 空间复杂度:O(min(m, n)),最坏情况下遍历完整个矩阵 12 | var bfs = (grid, i, j) => { 13 | const queue = [[i, j]]; 14 | while (queue.length > 0) { 15 | const [i, j] = queue.shift(); 16 | if (i >= 0 && j >= 0 && i < grid.length && j < grid[0].length && grid[i][j] === '1') { 17 | grid[i][j] = '0'; 18 | queue.push([i + 1, j]); 19 | queue.push([i - 1, j]); 20 | queue.push([i, j + 1]); 21 | queue.push([i, j - 1]); 22 | } 23 | } 24 | } 25 | var numIslands = function (grid) { 26 | let count = 0; 27 | for (let i = 0; i < grid.length; i++) { 28 | for (let j = 0; j < grid[0].length; j++) { 29 | if (grid[i][j] === '1') { 30 | bfs(grid, i, j); 31 | count++; 32 | } 33 | } 34 | } 35 | return count; 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/queue/menu/README.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | | LeetCode题目 | 难度 | 3 | | ------ | --- | 4 | | [41.数据流中的移动平均值](https://leetcode.cn/problems/qIsx9U) | 简单 | 5 | | [200.岛屿的数量](https://leetcode.cn/problems/number-of-islands/) | 中等 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/recommend/README.md: -------------------------------------------------------------------------------- 1 | # LeetCode刷题推荐 2 | 3 | ## LeetCode合集推荐 4 | * [LeetCode Hot 100题](https://leetcode.cn/studyplan/top-100-liked/) 5 | * [LeetCode 面试经典 150 题](https://leetcode.cn/studyplan/top-interview-150/) 6 | * [LeetCode 剑指Offer](https://leetcode.cn/studyplan/coding-interviews/) 7 | 8 | ## LeetCode刷题博客推荐 9 | * [ssh前端算法](https://github.com/sl1673495/leetcode-javascript) 10 | * [宫水三叶的刷题日记](https://github.com/SharingSource/LogicStack-LeetCode) 11 | * [krahets LeetBook图解算法数据结构](https://github.com/krahets/LeetCode-Book) -------------------------------------------------------------------------------- /docs/algorithm/leetcode/search/easy/README.md: -------------------------------------------------------------------------------- 1 | # 简单 2 | 3 | ## 35.搜索插入位置 4 | 5 | 6 | 方法:二分查找 7 | ```js 8 | // n为数组元素的数量 9 | // 时间复杂度:O(nlogn) 10 | // 空间复杂度:O(1) 11 | var searchInsert = function (nums, target) { 12 | const len = nums.length; 13 | let left = 0; 14 | let right = len - 1; 15 | while (left <= right) { 16 | const mid = Math.floor((left + right) / 2); 17 | const val = nums[mid]; 18 | if (val === target) { 19 | return mid; 20 | } else if (val < target) { 21 | left = mid + 1; 22 | } else { 23 | right = mid - 1; 24 | } 25 | } 26 | return left; 27 | }; 28 | ``` -------------------------------------------------------------------------------- /docs/algorithm/leetcode/search/hard/README.md: -------------------------------------------------------------------------------- 1 | # 困难 2 | 3 | ## 4.寻找两个正序数组的中位数 4 | 5 | 6 | 方法一:暴力合并数组 7 | ```js 8 | // m,n分别为两个数组的元素数量 9 | // 时间复杂度:O(m + n) 10 | // 空间复杂度:O(m + n) 11 | var getNumsMid = function (nums) { 12 | const len = nums.length; 13 | const mid = Math.floor(len / 2); 14 | if (len % 2 === 0) { 15 | return (nums[mid - 1] + nums[mid]) / 2; 16 | } else { 17 | return nums[mid]; 18 | } 19 | } 20 | var findMedianSortedArrays = function (nums1, nums2) { 21 | const m = nums1.length; 22 | const n = nums2.length; 23 | if (m === 0) { 24 | return getNumsMid(nums2); 25 | } 26 | if (n === 0) { 27 | return getNumsMid(nums1); 28 | } 29 | let count = 0; 30 | let i = 0; 31 | let j = 0; 32 | let nums = []; 33 | while (count < (m + n)) { 34 | // 第一个数组先遍历完毕时 35 | if (i === m) { 36 | while (j < n) { 37 | nums[count++] = nums2[j++]; 38 | } 39 | break; 40 | } 41 | // 第二个数组先遍历完毕时 42 | if (j === n) { 43 | while (i < m) { 44 | nums[count++] = nums1[i++]; 45 | } 46 | break; 47 | } 48 | // 按大小排序 49 | if (nums1[i] < nums2[j]) { 50 | nums[count++] = nums1[i++]; 51 | } else { 52 | nums[count++] = nums2[j++]; 53 | } 54 | } 55 | // 在新数组中去中位数 56 | return getNumsMid(nums); 57 | }; 58 | ``` 59 | 方法二:虚拟合并 60 | ```js 61 | // m,n分别为两个数组的元素数量 62 | // 时间复杂度:O(m + n) 63 | // 空间复杂度:O(1) 64 | var findMedianSortedArrays = function (nums1, nums2) { 65 | const m = nums1.length; 66 | const n = nums2.length; 67 | let len = m + n; 68 | let left = -1; 69 | let right = -1; 70 | let aStart = 0; 71 | let bStart = 0; 72 | let i = 0; 73 | while (i <= len / 2) { 74 | left = right; 75 | if (aStart < m && (nums1[aStart] < nums2[bStart] || bStart >= n)) { 76 | right = nums1[aStart++]; 77 | } else { 78 | right = nums2[bStart++]; 79 | } 80 | i++; 81 | } 82 | if (len % 2 === 0) { 83 | return (left + right) / 2; 84 | } else { 85 | return right; 86 | } 87 | } 88 | ``` 89 | 方法三:二分法 90 | ```js 91 | // 撰写中。。。 92 | ``` -------------------------------------------------------------------------------- /docs/algorithm/leetcode/search/menu/README.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | | LeetCode题目 | 难度 | 3 | | ------ | --- | 4 | | [35.搜索插入位置](https://leetcode.cn/problems/search-insert-position) | 简单 | 5 | | [33.搜索旋转排序数组](https://leetcode.cn/problems/search-in-rotated-sorted-array) | 中等 | 6 | | [34.在排序数组中查找元素的第一个和最后一个位置](https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array) | 中等 | 7 | | [74.搜索二维矩阵](https://leetcode.cn/problems/search-a-2d-matrix) | 中等 | 8 | | [153.寻找旋转排序数组中的最小值](https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array) | 中等 | 9 | | [4.寻找两个正序数组的中位数](https://leetcode.cn/problems/median-of-two-sorted-arrays) | 困难 | 10 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/stack/easy/README.md: -------------------------------------------------------------------------------- 1 | # 简单 2 | ## 20.有效括号 3 | 4 | 5 | ```js 6 | // n为字符串的长度 7 | // 时间复杂度:O(n),需要遍历一遍字符串 8 | // 空间复杂度:O(n),定义栈数组 9 | var isValid = function(s) { 10 | const len = s.length; 11 | if (len % 2 !== 0) { 12 | return false; 13 | } 14 | const stack = []; 15 | const matchMap = { 16 | ')': '(', 17 | '}': '{', 18 | ']': '[' 19 | } 20 | for(let i = 0; i < len; i++) { 21 | const char = s.charAt(i); 22 | const peek = stack[stack.length - 1]; 23 | if (peek && peek === matchMap[char]) { 24 | stack.pop(); 25 | } else { 26 | stack.push(char); 27 | } 28 | } 29 | 30 | return stack.length === 0; 31 | }; 32 | ``` -------------------------------------------------------------------------------- /docs/algorithm/leetcode/stack/hard/README.md: -------------------------------------------------------------------------------- 1 | # 困难 2 | ## 84.柱状图中最大的矩形 3 | 4 | 5 | 方法一:暴力法 6 | ::: warning 7 | 能运行测试用例,但提交会判定超时 8 | ::: 9 | ```js 10 | // n为数组的长度 11 | // 时间复杂度:O(n²),外层for循环 + 内存while循环 12 | // 空间复杂度:O(1),仅变量存储开销 13 | var largestRectangleArea = function(heights) { 14 | const len = heights.length; 15 | let result = 0; 16 | for(let i = 0; i < len; i++) { 17 | const currHeight = heights[i] 18 | let left = i; 19 | let right = i; 20 | 21 | while(left > 0 && heights[left - 1] >= currHeight) { 22 | left--; 23 | } 24 | while(right < len - 1 && heights[right + 1] >= currHeight) { 25 | right++; 26 | } 27 | 28 | const width = right - left + 1; 29 | result = Math.max(result, width * currHeight); 30 | } 31 | return result; 32 | }; 33 | ``` 34 | 方法二:单调栈 + 空间优化 35 | ```js 36 | // n为数组的长度 37 | // 时间复杂度:O(n),遍历数组 38 | // 空间复杂度:O(n),栈和预处理数组(left,right)的存储开销 39 | var largestRectangleArea = function(heights) { 40 | const length = heights.length; 41 | const left = new Array(length).fill(-1); 42 | const right = new Array(length).fill(length); 43 | const stack = []; 44 | let result = 0; 45 | 46 | for(let index = 0; index < length; index++) { 47 | while(stack.length > 0 && heights[index] < heights[stack[stack.length - 1]]) { 48 | right[stack.pop()] = index; 49 | } 50 | left[index] = stack.length === 0 ? -1 : stack[stack.length - 1] 51 | stack.push(index); 52 | } 53 | 54 | for(let index = 0; index < length; index++) { 55 | const height = heights[index]; 56 | const width = right[index] - left[index] - 1; 57 | result = Math.max(result, height * width); 58 | } 59 | return result; 60 | } 61 | ``` 62 | 方法三:单调栈 + 哨兵 63 | ```js 64 | // n为数组的长度 65 | // 时间复杂度:O(n),遍历数组 66 | // 空间复杂度:O(n),栈和添加了哨兵的新数组的存储开销 67 | var largestRectangleArea = function(heights) { 68 | const newHeights = [0, ...heights, 0]; 69 | const length = newHeights.length; 70 | const stack = new Array(length).fill(0); 71 | let result = 0; 72 | for (let index = 0; index < length; index++) { 73 | while(newHeights[index] < newHeights[stack[stack.length - 1]]) { 74 | const height = newHeights[stack.pop()]; 75 | const width = index - stack[stack.length - 1] - 1; 76 | result = Math.max(result, width * height); 77 | } 78 | stack.push(index); 79 | } 80 | 81 | return result; 82 | } 83 | ``` -------------------------------------------------------------------------------- /docs/algorithm/leetcode/stack/menu/README.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | | LeetCode题目 | 难度 | 3 | | ------ | --- | 4 | | [20.有效括号](https://leetcode.cn/problems/valid-parentheses) | 简单 | 5 | | [150.逆波兰表达式求值](https://leetcode.cn/problems/evaluate-reverse-polish-notation) | 中等 | 6 | | [155.最小栈](https://leetcode.cn/problems/min-stack) | 中等 | 7 | | [394.字符串解码](https://leetcode.cn/problems/decode-string) | 中等 | 8 | | [739.每日温度](https://leetcode.cn/problems/daily-temperatures) | 中等 | 9 | | [84.柱状图中最大的矩形](https://leetcode.cn/problems/largest-rectangle-in-histogram) | 困难 | -------------------------------------------------------------------------------- /docs/algorithm/leetcode/tree/hard/README.md: -------------------------------------------------------------------------------- 1 | # 困难 2 | 3 | ## 124.二叉树中的最大路径和 4 | 5 | 6 | 方法一:深度优先遍历 7 | ```js 8 | // way1: 深度优先遍历 9 | // n为二叉树节点的数量 10 | // 时间复杂度:O(n),每个节点都需要遍历 11 | // 空间复杂度:O(n),最坏情况为一个链表,递归调用栈的内存开销为O(n) 12 | var maxPathSum = function (root) { 13 | var maxSum = -Infinity; 14 | var maxGain = (root) => { 15 | if (root === null) { 16 | return 0; 17 | } 18 | const leftGain = Math.max(maxGain(root.left), 0); 19 | const rightGain = Math.max(maxGain(root.right), 0); 20 | const pathGain = root.val + leftGain + rightGain; 21 | maxSum = Math.max(maxSum, pathGain); 22 | return root.val + Math.max(leftGain, rightGain); 23 | } 24 | maxGain(root); 25 | return maxSum; 26 | }; 27 | ``` -------------------------------------------------------------------------------- /docs/algorithm/leetcode/tree/menu/README.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | | LeetCode题目 | 难度 | 3 | | ------ | --- | 4 | | [94.二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal) | 简单 | 5 | | [101.对称二叉树](https://leetcode.cn/problems/symmetric-tree) | 简单 | 6 | | [104.二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree) | 简单 | 7 | | [108.将有序数组转换为二叉搜索树](https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree) | 简单 | 8 | | [226.翻转二叉树](https://leetcode.cn/problems/invert-binary-tree) | 简单 | 9 | | [543.二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree) | 简单 | 10 | | [98.验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree) | 中等 | 11 | | [102.二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal) | 中等 | 12 | | [105.从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal) | 中等 | 13 | | [114.二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list) | 中等 | 14 | | [199.二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view) | 中等 | 15 | | [230.二叉搜索树中第K小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-bst) | 中等 | 16 | | [236.二叉树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree) | 中等 | 17 | | [437.路径总和 III](https://leetcode.cn/problems/path-sum-iii) | 中等 | 18 | | [124.二叉树中的最大路径和](https://leetcode.cn/problems/path-sum-iii) | 困难 | -------------------------------------------------------------------------------- /docs/books/javascript/red-book.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: heading 3 | --- 4 | 5 | # JavaScript高级程序设计 -------------------------------------------------------------------------------- /docs/books/javascript/vue.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: heading 3 | --- 4 | # 深入浅出Vue.js 5 | 6 | ## Vue简介 7 | 8 | ## 架构设计和项目结构 9 | 10 | ### 目录结构 11 | 12 | ### 架构设计 13 | 14 | ## 数据响应式原理 15 | 16 | ### Object的变化侦测 17 | 18 | ### Array的变化侦测 19 | 20 | ### 变化侦测扩展API的实现原理 21 | 22 | ## 虚拟DOM 23 | 24 | ### 虚拟DOM简介 25 | 26 | ### VNode介绍 27 | 28 | ### Patch介绍 29 | 30 | ## 模板编译原理 31 | 32 | ### 模板编译 33 | 34 | ### 解析器 35 | 36 | ### 优化器 37 | 38 | ### 代码生成器 39 | 40 | ## 实例方法和全局API的实现原理 41 | 42 | ### 数据相关的实例方法 43 | 44 | ### 事件相关的实例方法 45 | 46 | ### 生命周期相关的实例方法 47 | 48 | ### 全局API 49 | 50 | ## 生命周期 51 | 52 | ### 生命周期图示 53 | 54 | ### 初始化阶段 55 | 56 | ### 模板编译阶段 57 | 58 | ### 挂载阶段 59 | 60 | ### 卸载阶段 61 | 62 | ## 从源码深入了解初始化实例 63 | 64 | ### 初始化实例属性 65 | 66 | ### 初始化事件 67 | 68 | ### 初始化inject 69 | 70 | ### 初始化状态 71 | 72 | ### 初始化provide 73 | 74 | ## 指令的奥秘 75 | 76 | ### 指令原理 77 | 78 | ### 自定义指令原理 79 | 80 | ### 虚拟DOM的钩子函数 81 | 82 | ## 过滤器的奥秘 83 | 84 | ### 过滤器的原理 85 | 86 | ### 解析过滤器 87 | 88 | ## 最佳实践 89 | 90 | ### 合理使用key 91 | 92 | ### 动态路由组件复用 93 | 94 | ### 路由向下传递query 95 | 96 | ### 一些需要避免的问题 97 | 98 | ### 命名规范 99 | -------------------------------------------------------------------------------- /docs/cssPrecompiler/sassLoader/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: atuo 3 | --- 4 | ### Sass-Loader源码分析 -------------------------------------------------------------------------------- /docs/golang/framework/gin.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: heading 3 | --- 4 | 5 | # Gin 6 | Gin -------------------------------------------------------------------------------- /docs/golang/framework/gorm.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: heading 3 | --- 4 | 5 | # Gorm 6 | Gorm -------------------------------------------------------------------------------- /docs/golang/tools/mod.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: heading 3 | --- 4 | 5 | # Go Modules 6 | Go Modules -------------------------------------------------------------------------------- /docs/images/books/fileUploadResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/fileUploadResult.png -------------------------------------------------------------------------------- /docs/images/books/tree0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree0.png -------------------------------------------------------------------------------- /docs/images/books/tree1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree1.png -------------------------------------------------------------------------------- /docs/images/books/tree10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree10.png -------------------------------------------------------------------------------- /docs/images/books/tree11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree11.png -------------------------------------------------------------------------------- /docs/images/books/tree12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree12.png -------------------------------------------------------------------------------- /docs/images/books/tree13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree13.png -------------------------------------------------------------------------------- /docs/images/books/tree14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree14.png -------------------------------------------------------------------------------- /docs/images/books/tree2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree2.png -------------------------------------------------------------------------------- /docs/images/books/tree3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree3.png -------------------------------------------------------------------------------- /docs/images/books/tree4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree4.png -------------------------------------------------------------------------------- /docs/images/books/tree5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree5.png -------------------------------------------------------------------------------- /docs/images/books/tree6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree6.png -------------------------------------------------------------------------------- /docs/images/books/tree7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree7.png -------------------------------------------------------------------------------- /docs/images/books/tree8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree8.png -------------------------------------------------------------------------------- /docs/images/books/tree9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/books/tree9.png -------------------------------------------------------------------------------- /docs/images/css/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/1.png -------------------------------------------------------------------------------- /docs/images/css/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/10.png -------------------------------------------------------------------------------- /docs/images/css/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/11.png -------------------------------------------------------------------------------- /docs/images/css/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/12.png -------------------------------------------------------------------------------- /docs/images/css/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/13.png -------------------------------------------------------------------------------- /docs/images/css/14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/14.gif -------------------------------------------------------------------------------- /docs/images/css/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/15.png -------------------------------------------------------------------------------- /docs/images/css/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/16.png -------------------------------------------------------------------------------- /docs/images/css/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/17.png -------------------------------------------------------------------------------- /docs/images/css/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/18.png -------------------------------------------------------------------------------- /docs/images/css/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/19.png -------------------------------------------------------------------------------- /docs/images/css/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/2.png -------------------------------------------------------------------------------- /docs/images/css/20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/20.gif -------------------------------------------------------------------------------- /docs/images/css/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/3.png -------------------------------------------------------------------------------- /docs/images/css/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/4.gif -------------------------------------------------------------------------------- /docs/images/css/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/4.png -------------------------------------------------------------------------------- /docs/images/css/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/5.gif -------------------------------------------------------------------------------- /docs/images/css/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/6.png -------------------------------------------------------------------------------- /docs/images/css/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/7.png -------------------------------------------------------------------------------- /docs/images/css/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/8.png -------------------------------------------------------------------------------- /docs/images/css/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/9.png -------------------------------------------------------------------------------- /docs/images/css/number-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/number-bg.png -------------------------------------------------------------------------------- /docs/images/css/number-filp-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/number-filp-process.png -------------------------------------------------------------------------------- /docs/images/css/number-filp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/css/number-filp.gif -------------------------------------------------------------------------------- /docs/images/flex/JDExplame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/JDExplame.png -------------------------------------------------------------------------------- /docs/images/flex/JDResult1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/JDResult1.png -------------------------------------------------------------------------------- /docs/images/flex/columnResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/columnResult.png -------------------------------------------------------------------------------- /docs/images/flex/columnReverseResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/columnReverseResult.png -------------------------------------------------------------------------------- /docs/images/flex/contentCenterResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/contentCenterResult.png -------------------------------------------------------------------------------- /docs/images/flex/contentEndResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/contentEndResult.png -------------------------------------------------------------------------------- /docs/images/flex/contentStartResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/contentStartResult.png -------------------------------------------------------------------------------- /docs/images/flex/dicResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/dicResult.png -------------------------------------------------------------------------------- /docs/images/flex/firstDicResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/firstDicResult.png -------------------------------------------------------------------------------- /docs/images/flex/fiveDicResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/fiveDicResult.png -------------------------------------------------------------------------------- /docs/images/flex/flexCenterResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/flexCenterResult.png -------------------------------------------------------------------------------- /docs/images/flex/flexEndResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/flexEndResult.png -------------------------------------------------------------------------------- /docs/images/flex/flexResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/flexResult.png -------------------------------------------------------------------------------- /docs/images/flex/flexStartResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/flexStartResult.png -------------------------------------------------------------------------------- /docs/images/flex/floatThreeResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/floatThreeResult.png -------------------------------------------------------------------------------- /docs/images/flex/fourDicResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/fourDicResult.png -------------------------------------------------------------------------------- /docs/images/flex/gridResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/gridResult.png -------------------------------------------------------------------------------- /docs/images/flex/gridResult2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/gridResult2.png -------------------------------------------------------------------------------- /docs/images/flex/holyGralyResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/holyGralyResult.png -------------------------------------------------------------------------------- /docs/images/flex/nineDicResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/nineDicResult.png -------------------------------------------------------------------------------- /docs/images/flex/nowrapResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/nowrapResult.png -------------------------------------------------------------------------------- /docs/images/flex/nowrapResult1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/nowrapResult1.png -------------------------------------------------------------------------------- /docs/images/flex/padding+marginResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/padding+marginResult.png -------------------------------------------------------------------------------- /docs/images/flex/position+marginResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/position+marginResult.png -------------------------------------------------------------------------------- /docs/images/flex/position+transformResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/position+transformResult.png -------------------------------------------------------------------------------- /docs/images/flex/qidianExplame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/qidianExplame.png -------------------------------------------------------------------------------- /docs/images/flex/qidianResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/qidianResult.png -------------------------------------------------------------------------------- /docs/images/flex/qunarExample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/qunarExample.png -------------------------------------------------------------------------------- /docs/images/flex/qunarResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/qunarResult.png -------------------------------------------------------------------------------- /docs/images/flex/rowResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/rowResult.png -------------------------------------------------------------------------------- /docs/images/flex/rowReverseResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/rowReverseResult.png -------------------------------------------------------------------------------- /docs/images/flex/secondDicResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/secondDicResult.png -------------------------------------------------------------------------------- /docs/images/flex/sixDicResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/sixDicResult.png -------------------------------------------------------------------------------- /docs/images/flex/spaceAroundResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/spaceAroundResult.png -------------------------------------------------------------------------------- /docs/images/flex/spaceBetweenResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/spaceBetweenResult.png -------------------------------------------------------------------------------- /docs/images/flex/steamFlexResult1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/steamFlexResult1.png -------------------------------------------------------------------------------- /docs/images/flex/steamFlexResult2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/steamFlexResult2.png -------------------------------------------------------------------------------- /docs/images/flex/steamResult1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/steamResult1.png -------------------------------------------------------------------------------- /docs/images/flex/steamResult2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/steamResult2.png -------------------------------------------------------------------------------- /docs/images/flex/stickyFooterResult1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/stickyFooterResult1.png -------------------------------------------------------------------------------- /docs/images/flex/stickyFooterResult2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/stickyFooterResult2.png -------------------------------------------------------------------------------- /docs/images/flex/stickyFooterResult3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/stickyFooterResult3.png -------------------------------------------------------------------------------- /docs/images/flex/threeDicResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/threeDicResult.png -------------------------------------------------------------------------------- /docs/images/flex/wrapResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/wrapResult.png -------------------------------------------------------------------------------- /docs/images/flex/wrapReverseResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/flex/wrapReverseResult.png -------------------------------------------------------------------------------- /docs/images/git/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/git/1.png -------------------------------------------------------------------------------- /docs/images/git/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/git/2.png -------------------------------------------------------------------------------- /docs/images/git/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/git/3.png -------------------------------------------------------------------------------- /docs/images/git/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/git/4.png -------------------------------------------------------------------------------- /docs/images/git/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/git/5.png -------------------------------------------------------------------------------- /docs/images/interview/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/1.png -------------------------------------------------------------------------------- /docs/images/interview/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/10.png -------------------------------------------------------------------------------- /docs/images/interview/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/11.png -------------------------------------------------------------------------------- /docs/images/interview/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/12.png -------------------------------------------------------------------------------- /docs/images/interview/13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/13.jpg -------------------------------------------------------------------------------- /docs/images/interview/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/13.png -------------------------------------------------------------------------------- /docs/images/interview/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/2.png -------------------------------------------------------------------------------- /docs/images/interview/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/3.png -------------------------------------------------------------------------------- /docs/images/interview/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/4.png -------------------------------------------------------------------------------- /docs/images/interview/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/5.gif -------------------------------------------------------------------------------- /docs/images/interview/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/6.png -------------------------------------------------------------------------------- /docs/images/interview/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/7.png -------------------------------------------------------------------------------- /docs/images/interview/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/8.png -------------------------------------------------------------------------------- /docs/images/interview/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/interview/9.png -------------------------------------------------------------------------------- /docs/images/python/python-family.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/python/python-family.png -------------------------------------------------------------------------------- /docs/images/python/python-vscode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/python/python-vscode.png -------------------------------------------------------------------------------- /docs/images/python/try-except.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/python/try-except.png -------------------------------------------------------------------------------- /docs/images/rag/rag-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/rag/rag-architecture.png -------------------------------------------------------------------------------- /docs/images/rag/rag-chunk-viz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/rag/rag-chunk-viz.png -------------------------------------------------------------------------------- /docs/images/rag/rag_chroma_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/rag/rag_chroma_server.png -------------------------------------------------------------------------------- /docs/images/rag/rag_embedding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/rag/rag_embedding.png -------------------------------------------------------------------------------- /docs/images/rag/rag_embedding_history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/rag/rag_embedding_history.png -------------------------------------------------------------------------------- /docs/images/test/vue-test1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/test/vue-test1.png -------------------------------------------------------------------------------- /docs/images/test/vue-test2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/test/vue-test2.png -------------------------------------------------------------------------------- /docs/images/test/vue-test3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/test/vue-test3.png -------------------------------------------------------------------------------- /docs/images/test/vue-test4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/test/vue-test4.png -------------------------------------------------------------------------------- /docs/images/typescript/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/typescript/1.png -------------------------------------------------------------------------------- /docs/images/typescript/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/typescript/2.png -------------------------------------------------------------------------------- /docs/images/vue/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/1.jpg -------------------------------------------------------------------------------- /docs/images/vue/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/1.png -------------------------------------------------------------------------------- /docs/images/vue/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/10.png -------------------------------------------------------------------------------- /docs/images/vue/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/11.png -------------------------------------------------------------------------------- /docs/images/vue/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/12.png -------------------------------------------------------------------------------- /docs/images/vue/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/13.png -------------------------------------------------------------------------------- /docs/images/vue/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/14.png -------------------------------------------------------------------------------- /docs/images/vue/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/15.png -------------------------------------------------------------------------------- /docs/images/vue/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/16.png -------------------------------------------------------------------------------- /docs/images/vue/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/17.png -------------------------------------------------------------------------------- /docs/images/vue/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/18.png -------------------------------------------------------------------------------- /docs/images/vue/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/19.png -------------------------------------------------------------------------------- /docs/images/vue/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/2.png -------------------------------------------------------------------------------- /docs/images/vue/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/20.png -------------------------------------------------------------------------------- /docs/images/vue/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/21.png -------------------------------------------------------------------------------- /docs/images/vue/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/22.png -------------------------------------------------------------------------------- /docs/images/vue/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/23.png -------------------------------------------------------------------------------- /docs/images/vue/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/24.png -------------------------------------------------------------------------------- /docs/images/vue/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/29.png -------------------------------------------------------------------------------- /docs/images/vue/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/3.png -------------------------------------------------------------------------------- /docs/images/vue/30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/30.png -------------------------------------------------------------------------------- /docs/images/vue/31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/31.png -------------------------------------------------------------------------------- /docs/images/vue/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/32.png -------------------------------------------------------------------------------- /docs/images/vue/33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/33.png -------------------------------------------------------------------------------- /docs/images/vue/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/4.png -------------------------------------------------------------------------------- /docs/images/vue/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/5.png -------------------------------------------------------------------------------- /docs/images/vue/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/6.png -------------------------------------------------------------------------------- /docs/images/vue/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/7.png -------------------------------------------------------------------------------- /docs/images/vue/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/8.png -------------------------------------------------------------------------------- /docs/images/vue/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/9.png -------------------------------------------------------------------------------- /docs/images/vue/lifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/lifecycle.png -------------------------------------------------------------------------------- /docs/images/vue/transition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/transition.png -------------------------------------------------------------------------------- /docs/images/vue/vuex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vue/vuex.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/$mount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/$mount.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/composition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/composition.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/computed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/computed.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/data.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/dom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/dom.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/eventsMixin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/eventsMixin.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/initGlobalAPI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/initGlobalAPI.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/initGlobalAPIProcess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/initGlobalAPIProcess.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/initMixin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/initMixin.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/instance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/instance.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/lifecycleMixin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/lifecycleMixin.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/methods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/methods.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/notify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/notify.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/process.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/props.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/props.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/reactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/reactive.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/renderMixin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/renderMixin.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/stateMixin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/stateMixin.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/vdom-hooks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/vdom-hooks.png -------------------------------------------------------------------------------- /docs/images/vueAnalysis/vue-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vueAnalysis/vue-process.png -------------------------------------------------------------------------------- /docs/images/vuepress/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/1.png -------------------------------------------------------------------------------- /docs/images/vuepress/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/10.png -------------------------------------------------------------------------------- /docs/images/vuepress/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/11.png -------------------------------------------------------------------------------- /docs/images/vuepress/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/12.png -------------------------------------------------------------------------------- /docs/images/vuepress/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/13.png -------------------------------------------------------------------------------- /docs/images/vuepress/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/14.png -------------------------------------------------------------------------------- /docs/images/vuepress/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/15.png -------------------------------------------------------------------------------- /docs/images/vuepress/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/16.png -------------------------------------------------------------------------------- /docs/images/vuepress/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/17.png -------------------------------------------------------------------------------- /docs/images/vuepress/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/18.png -------------------------------------------------------------------------------- /docs/images/vuepress/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/19.png -------------------------------------------------------------------------------- /docs/images/vuepress/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/2.png -------------------------------------------------------------------------------- /docs/images/vuepress/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/20.png -------------------------------------------------------------------------------- /docs/images/vuepress/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/3.png -------------------------------------------------------------------------------- /docs/images/vuepress/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/4.png -------------------------------------------------------------------------------- /docs/images/vuepress/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/5.png -------------------------------------------------------------------------------- /docs/images/vuepress/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/6.png -------------------------------------------------------------------------------- /docs/images/vuepress/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/7.png -------------------------------------------------------------------------------- /docs/images/vuepress/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/8.png -------------------------------------------------------------------------------- /docs/images/vuepress/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/vuepress/9.png -------------------------------------------------------------------------------- /docs/images/webpack/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/10.png -------------------------------------------------------------------------------- /docs/images/webpack/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/11.png -------------------------------------------------------------------------------- /docs/images/webpack/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/12.png -------------------------------------------------------------------------------- /docs/images/webpack/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/13.png -------------------------------------------------------------------------------- /docs/images/webpack/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/14.png -------------------------------------------------------------------------------- /docs/images/webpack/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/16.png -------------------------------------------------------------------------------- /docs/images/webpack/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/17.png -------------------------------------------------------------------------------- /docs/images/webpack/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/19.png -------------------------------------------------------------------------------- /docs/images/webpack/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/2.png -------------------------------------------------------------------------------- /docs/images/webpack/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/20.png -------------------------------------------------------------------------------- /docs/images/webpack/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/21.png -------------------------------------------------------------------------------- /docs/images/webpack/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/22.png -------------------------------------------------------------------------------- /docs/images/webpack/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/23.png -------------------------------------------------------------------------------- /docs/images/webpack/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/24.png -------------------------------------------------------------------------------- /docs/images/webpack/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/25.png -------------------------------------------------------------------------------- /docs/images/webpack/251.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/251.png -------------------------------------------------------------------------------- /docs/images/webpack/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/26.png -------------------------------------------------------------------------------- /docs/images/webpack/261.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/261.png -------------------------------------------------------------------------------- /docs/images/webpack/27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/27.png -------------------------------------------------------------------------------- /docs/images/webpack/28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/28.png -------------------------------------------------------------------------------- /docs/images/webpack/281.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/281.png -------------------------------------------------------------------------------- /docs/images/webpack/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/29.png -------------------------------------------------------------------------------- /docs/images/webpack/30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/30.png -------------------------------------------------------------------------------- /docs/images/webpack/31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/31.png -------------------------------------------------------------------------------- /docs/images/webpack/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/32.png -------------------------------------------------------------------------------- /docs/images/webpack/33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/33.png -------------------------------------------------------------------------------- /docs/images/webpack/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/5.png -------------------------------------------------------------------------------- /docs/images/webpack/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/6.png -------------------------------------------------------------------------------- /docs/images/webpack/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/docs/images/webpack/9.png -------------------------------------------------------------------------------- /docs/rag/base/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | **RAG**:Retrieval-Augmented Generation,检索增强生成,是大型语言模型(LLM)中的一种重要架构,它通过结合信息检索和文本生成来提高模型输出的准确性和相关性。 4 | 5 | ![RAG系统架构](../../images/rag/rag-architecture.png) -------------------------------------------------------------------------------- /docs/rag/basic/compare/README.md: -------------------------------------------------------------------------------- 1 | # LangChain vs LangGraph 2 | 3 | | 对比维度 | LangChain | LangGraph | 4 | |-----------------|-----------|-----------| 5 | | **架构设计** | 链式(`Chain-based`),线性流程 | 图状(`Graph-based`),支持 `DAG`(有向无环图) | 6 | | **RAG 典型实现** | `RetrievalQA` 链,顺序执行:查询 → 检索 → 生成 | 可分解为多个节点,支持动态路由、多轮检索 | 7 | | **复杂任务处理** | 需要嵌套链,适用于简单到中等复杂度任务 | 原生支持复杂逻辑、条件分支、循环 | 8 | | **并行处理能力** | 顺序执行为主,并行需额外实现 | 内置并行执行,可同时运行独立节点 | 9 | | **状态管理** | 通过 `Memory` 组件管理 | 更灵活,可跟踪全局状态 | 10 | | **调试与可观察性** | 基本回调系统,调试较简单 | 完整执行跟踪,可视化更直观 | 11 | | **学习曲线** | 较低,适合快速上手 | 较高,需理解图计算概念 | 12 | | **性能** | 简单任务开销小 | 复杂任务更高效(支持并行) | 13 | | **适用场景** | 标准问答、简单 `RAG`、快速原型 | 多阶段 `RAG`、动态决策、企业级应用 | 14 | | **错误处理** | 相对简单 | 更健壮,支持节点级错误恢复 | 15 | | **扩展性** | 适合小型到中型项目 | 更适合大型、高定制化系统 | 16 | 17 | 总结: 18 | * **LangChain**:适合简单、线性的 `RAG` 任务,开发速度快,学习成本低。 19 | * **LangGraph**:适合复杂、动态的 `RAG` 系统,支持并行、条件分支和循环,适合企业级应用。 20 | -------------------------------------------------------------------------------- /docs/rag/basic/langchain/README.md: -------------------------------------------------------------------------------- 1 | # LangChain实现RAG 2 | 3 | 安装`langchain_community`包,并使用`loader`加载网页数据。 4 | ```py 5 | from langchain_community.document_loaders import WebBaseLoader 6 | 7 | # 加载网页数据 8 | web_data = WebBaseLoader( 9 | web_path="https://zh.wikipedia.org/wiki/黑神话:悟空" 10 | ).load() 11 | 12 | print(web_data) 13 | ``` 14 | 15 | 安装`langchain_text_splitters`包,并使用分割器分割网页数据。 16 | ```py 17 | from langchain_text_splitters import RecursiveCharacterTextSplitter 18 | text_splitter = RecursiveCharacterTextSplitter( 19 | chunk_size=1000, 20 | chunk_overlap=200 21 | ) 22 | text_split_data = text_splitter.split_documents(web_data) 23 | 24 | print(text_split_data) 25 | ``` 26 | 27 | 安装`langchain-huggingface`,并设置`embedding`。 28 | ```py 29 | from langchain_huggingface import HuggingFaceEmbeddings 30 | 31 | embedding = HuggingFaceEmbeddings( 32 | model_name="BAAI/bge-small-zh-v1.5" 33 | ) 34 | ``` 35 | 36 | 安装`langchain_core`,并设置向量存储。 37 | ```py 38 | from langchain_core.vectorstores import InMemoryVectorStore 39 | 40 | vector_store = InMemoryVectorStore(embeddings) 41 | vector_store.add_documents(text_split_data) 42 | ``` 43 | 至此,网页数据已经向量化存入到我们的内存中。 44 | 45 | 存入内存以后,需要做检索相关的工作。 46 | ```py 47 | # retriever 48 | question = "黑神话是哪家公司开发的,是什么类型的游戏,什么时间发布的?" 49 | retriever_docs = vector_store.similarity_search( 50 | query=question, 51 | k=2 52 | ) 53 | retriever_content = "\n\n".join(doc.page_content for doc in retriever_docs) 54 | 55 | print(retriever_content) 56 | ``` 57 | 58 | 向量存储检索完毕后,接下来要准备检索内容放置到提示词中。 59 | ```py 60 | # prompt 61 | from langchain_core.prompts import ChatPromptTemplate 62 | 63 | prompt = ChatPromptTemplate.from_template(""" 64 | 请你依据上下文来回答问题\n 65 | 如果上下文中没有,你直接回答"抱歉,我无法从上下文中提供相关信息。" 66 | 上下文:{context} 67 | 问题:{question} 68 | 回答: 69 | """) 70 | query = prompt.format( 71 | context=retriever_content, 72 | question=question 73 | ) 74 | 75 | print(query) 76 | ``` 77 | 最后,安装`langchain_deepseek`,并调用大模型`api`得到结果。 78 | ```py 79 | llm = ChatDeepSeek( 80 | model="deepseek-chat", 81 | api_key=api_key, 82 | temperature=0.5 83 | ) 84 | response = llm.invoke( 85 | input=query 86 | ) 87 | 88 | print(response.content) 89 | ``` 90 | 最后回答: 91 | ```markdown 92 | 1. **开发公司**:游戏科学(Game Science) 93 | 2. **游戏类型**:动作角色扮演(ARPG) 94 | 3. **发布时间**: 95 | - Microsoft Windows 和 PlayStation 5 平台:**2024年8月20日** 96 | - Xbox Series X/S 版:**待定**(暂未发售) 97 | 98 | 其他补充: 99 | - 中国新华社称其为“中国首款3A游戏”,改编自《西游记》。 100 | - 首发3天销量破1000万份,一个月内销量超2000万份。 101 | ``` 102 | -------------------------------------------------------------------------------- /docs/rag/basic/langgraph/README.md: -------------------------------------------------------------------------------- 1 | # LangGraph实现RAG 2 | 安装`langchain_community`包,并使用`loader`加载网页数据。 3 | ```py 4 | from langchain_community.document_loaders import WebBaseLoader 5 | 6 | # 加载网页数据 7 | web_data = WebBaseLoader( 8 | web_path="https://zh.wikipedia.org/wiki/黑神话:悟空" 9 | ).load() 10 | 11 | print(web_data) 12 | ``` 13 | 14 | 安装`langchain_text_splitters`包,并使用分割器分割网页数据。 15 | ```py 16 | from langchain_text_splitters import RecursiveCharacterTextSplitter 17 | text_splitter = RecursiveCharacterTextSplitter( 18 | chunk_size=1000, 19 | chunk_overlap=200 20 | ) 21 | text_split_data = text_splitter.split_documents(web_data) 22 | 23 | print(text_split_data) 24 | ``` 25 | 26 | 安装`langchain-huggingface`,并设置`embedding`。 27 | ```py 28 | from langchain_huggingface import HuggingFaceEmbeddings 29 | 30 | embedding = HuggingFaceEmbeddings( 31 | model_name="BAAI/bge-small-zh-v1.5" 32 | ) 33 | ``` 34 | 35 | 安装`langchain_core`,并设置向量存储。 36 | ```py 37 | from langchain_core.vectorstores import InMemoryVectorStore 38 | 39 | vector_store = InMemoryVectorStore(embeddings) 40 | vector_store.add_documents(text_split_data) 41 | ``` 42 | 至此,网页数据已经向量化存入到我们的内存中。 43 | 44 | 接下来,需要安装`langgraph`: 45 | ```sh 46 | $ pip install langgraph 47 | ``` 48 | 然后设置定义`State`、`Retriever`和`Generation`。 49 | ```py 50 | from langchain import hub 51 | from typing_extensions import TypedDict 52 | from langchain_deepseek import ChatDeepSeek 53 | from langchain_core.documents import Document 54 | from langgraph.graph import START, StateGraph 55 | from typing import List 56 | 57 | # prompt 58 | prompt = hub.pull("rlm/rag-prompt") 59 | 60 | class State(TypedDict): 61 | question: str 62 | context: List[Document] 63 | answer: str 64 | 65 | # retrieve 66 | def retrieve(state: State): 67 | retriever_docs = vector_store.similarity_search( 68 | query=state['question'], 69 | k=2 70 | ) 71 | retriever_content = "\n\n".join(doc.page_content for doc in retriever_docs) 72 | return { "context": retriever_content } 73 | 74 | # generate 75 | def generate(state: State): 76 | llm = ChatDeepSeek( 77 | model="deepseek-chat", 78 | api_key=api_key, 79 | temperature=0.5 80 | ) 81 | query = prompt.invoke({ 82 | "question": state['question'], 83 | "context": state['context'] 84 | }) 85 | response = llm.invoke( 86 | input=query 87 | ) 88 | return { "answer": response.content } 89 | ``` 90 | 91 | 最后定义`Graph`并调用大模型`API`得到结果: 92 | ```py 93 | graph = ( 94 | StateGraph(State) 95 | .add_sequence([retrieve, generate]) 96 | .add_edge(START, 'retrieve') 97 | .compile() 98 | ) 99 | 100 | question="黑神话是什么公司开发的,什么类型的游戏,什么时间发布?" 101 | response_content = graph.invoke({ "question": question }) 102 | print(response_content.get('answer')) 103 | ``` 104 | 105 | 最后回答: 106 | ```text 107 | 《黑神话:悟空》是由游戏科学开发的动作角色扮演游戏,于2024年8月20日发布。 108 | ``` 109 | -------------------------------------------------------------------------------- /docs/rag/basic/prepare/README.md: -------------------------------------------------------------------------------- 1 | # 前置准备 2 | ::: tip 3 | 所有跟llm请求相关的,默认都基于DeepSeek 4 | ::: 5 | 首先定义环境变量文件`.env`,其代码如下: 6 | ```env 7 | # DeepSeek api key 8 | DEEPSEEK_API_KEY = 'your api key' 9 | 10 | # DeepSeek endpoint 11 | DEEPSEEK_API_BASE = 'https://api.deepseek.com/v1' 12 | ``` 13 | 然后安装一个依赖包: 14 | ```sh 15 | $ pip install dotenv 16 | ``` 17 | 接着定义两个文件`env_tools.py`和`chain.py`,其代码分别是: 18 | ```py 19 | # env_tools.py 20 | import os 21 | from dotenv import load_dotenv, find_dotenv 22 | 23 | load_dotenv(find_dotenv()) 24 | 25 | def get_api_key(): 26 | return os.getenv('DEEPSEEK_API_KEY') 27 | 28 | def get_api_base(): 29 | return os.getenv('DEEPSEEK_API_BASE') 30 | ``` 31 | 32 | ```py 33 | # chain.py 34 | from env_tools import get_api_key, get_api_base 35 | 36 | api_key = get_api_key() 37 | api_base = get_api_base() 38 | 39 | print(api_key) 40 | print(api_base) 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/rag/chunking/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | ## 为什么要切块 4 | 将比较长的文本分解成适当大小的片段,有助于嵌入、索引和存储,并提高检索的精确度。 5 | 6 | 具体体现在: 7 | * 大模型一次处理文本`Token`的数量是有限制的。 8 | * 对嵌入模型而言,其向量一般都有维度限制,如果文本比较长,则必然在压缩向量维度时**丢失**一些相关信息。 9 | * 对生成模型而言,如果上线文太长,则在检索信息时必然低效和不精确。 10 | 11 | ## 分块可视化工具 12 | ::: tip 13 | [ChunkViz](https://chunkviz.up.railway.app/) 14 | ::: 15 | 16 | ![ChunkViz](../../images/rag//rag-chunk-viz.png) -------------------------------------------------------------------------------- /docs/rag/embedding/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | ::: tip 3 | `Embedding`是AI领域的基石技术,它将抽象符号转化为可计算的数学表示,从而赋能各类机器学习任务。 4 | ::: 5 | 6 | ## 什么是Embedding 7 | `Embedding`是将高维、离散或复杂的数据(如单词、图像、用户行为等)映射到低维连续向量空间的技术。这些向量(即嵌入)能够捕捉原始数据的语义、关系或特征,使机器更容易处理和计算。 8 | 9 | ![Embedding](../../images/rag/rag_embedding.png) 10 | 11 | ## Embedding类型 12 | 13 | * `Word Embedding`: 将单词映射为向量,例如`Word2Vec`、`GloVe`。 14 | * `Image Embedding`: 用`CNN`提取图像的向量表示,例如`ResNet`的特征向量。 15 | * `Graph Embedding`: 将图中的节点/边表示为向量,例如:`Node2Vec`、`GNN`。 16 | * 用户/商品嵌入(推荐系统):将用户/商品表示为向量,用于预测偏好,例如:矩阵分解、深度学习。 17 | 18 | ## Embedding维度 19 | ::: tip 20 | `Embedding`维度就是其向量的长度。 21 | ::: 22 | 23 | `Embedding`维度:即向量的长度,是嵌入技术中的关键参数,直接影响模型的表达能力、计算效率和下游任务效果。 24 | 25 | **维度的本质**:是将离散对象(如单词)映射到的连续向量的长度,例如:`[0.1, -0.3, ..., 0.8]`,理论而言,维度越高,能编码的信息越丰富,但也可能带来冗余和过拟合。 26 | 27 | 常见维度设置案例: 28 | | 分类 | 模型 | 维度 | 29 | | --- | --- | --- | 30 | | **词嵌入** | `Word2Vec`、`GloVe`、`FastText` | 50/100/200/300/ | 31 | | **推荐系统** | YouTube推荐 | 256 | 32 | | **预训练模型** | `BERT-base`、`BERT-large` | 768、1024 | 33 | | **图像嵌入** | `ResNet-50` | 2048 | 34 | 35 | ## 发展历史 36 | 37 | ![Embedding发展历史](../../images/rag/rag_embedding_history.png) 38 | 39 | **初始阶段:分布式表示** 40 | * 特点:每个词对应一个唯一的`ID`或`One-Hot`向量(大多数值为0,某一位为1)。 41 | * 局限性:无法表达词与词之间的语义关系(如“狗”和“猫”是独立的)。 42 | 43 | **分布式词向量:Word2Vec 时代** 44 | * 特点:词的意义来自上下文分布,词向量低维稠密,支持词向量计算。 45 | * 影响:开启词嵌入大规模训练的时代。 46 | * 模型:`Word2Vec`(2013 Google)、`GloVe`(2014 Stanford)、`FastText`(2016 Facebook)。 47 | 48 | **上下文相关嵌入:BERT 革命** 49 | * 特点:词的表示取决于上下文,输出的是句子中每个词的上下文相关表示。 50 | * 模型:`ELMo`(2018 AllenNLP)、`BERT`(2018 Google)、`GPT-2`(2019 OpenAI)。 51 | 52 | **多模态嵌入** 53 | * 特点:可以将图像和文本映射到同一向量空间,支持跨语言的嵌入,不同语言语义相近的句子有相近向量表示。 54 | * 影响:嵌入模型从单一文本向多模态、任务无关、可解释性发展。 55 | * 模型:`LoRA`(2021)、`CLIP`(2021 OpenAI)、`Flamingo`(2022 DeepMind)。 56 | 57 | **API和应用时代** 58 | * 特点:支持全语言、支持超长文本、适配向量数据库。 59 | * 模型:`BGE`(2023 BAAI)、`text-embedding-3`(2024 OpenAI)。 60 | -------------------------------------------------------------------------------- /docs/rag/embedding/dense/README.md: -------------------------------------------------------------------------------- 1 | # 密集嵌入 2 | 3 | **密集嵌入(Dense Embedding)**:每个词或对象用一个低维、稠密向量表示。 4 | 5 | ## 特点 6 | 7 | * 维度:通常是几维到几千维,维度较低。 8 | * 可解释性:难以理解单个维度的含义,可解释性差。 9 | * 语义信息:通过模型训练出来的连续表示,包含语义信息。 10 | * 效率:适合用余弦相似度/点积做相似度计算,效率较高。 11 | * 上下文:包含上下文,例如`BERT`输出。 12 | 13 | ## 示例 14 | * **词嵌入模型**:`Word2Vec`、`GloVe`。 15 | * **上下文模型**:`BERT`、`GPT`(基于`Transformer`编码)。 16 | * **推荐系统**:矩阵分解(`MF`)、深度神经网络(如`YouTube DNN`)。 17 | 18 | ## 应用场景 19 | * **文本处理**:语义搜索、机器翻译。 20 | * **推荐系统**:用户/物品的隐向量匹配。 21 | * **计算机视觉**:`CNN`特征(如`ResNet`输出)。 22 | * **分类任务**:深度学习模型(如`BERT`微调)。 23 | 24 | ## 实现案例 25 | ::: tip 26 | [FlagEmbedding 文档](https://github.com/FlagOpen/FlagEmbedding) 27 | ::: 28 | 29 | ```py 30 | from FlagEmbedding import BGEM3FlagModel 31 | 32 | passage = ["猢狲施展烈焰拳,击退妖怪;随后开启金刚体,抵挡神兵攻击。"] 33 | model = BGEM3FlagModel( 34 | model_name_or_path="BAAI/bge-m3", 35 | use_fp16=True 36 | ) 37 | 38 | passage_embedding = model.encode( 39 | sentences=passage, 40 | return_sparse=True, # 返回稀疏嵌入 41 | return_dense=True # 返回密集嵌入 42 | ) 43 | 44 | # 分别提取稀疏嵌入、密集嵌入和多向量嵌入 45 | dense_vecs = passage_embedding.get('dense_vecs') 46 | sparse_vecs = passage_embedding.get('lexical_weights') 47 | 48 | # 展示稀疏嵌入和密集嵌入的示例 49 | print("密集嵌入维度:", dense_vecs[0].shape) 50 | print("密集嵌入前10维:", dense_vecs[0][:10]) # 仅显示前10维 51 | 52 | print("稀疏嵌入总长度:", len(sparse_vecs[0])) 53 | print("稀疏嵌入前10个非零值:", list(sparse_vecs[0].items())[:10]) # 仅显示前10个非零值 54 | ``` 55 | 输出结果: 56 | ```text 57 | 密集嵌入维度: (1024,) 58 | 密集嵌入前10维: [ 59 | 0.0115688, 60 | 0.02439203, 61 | -0.02763909, 62 | -0.00984308, 63 | -0.04426071, 64 | -0.02911919, 65 | 0.03953099, 66 | 0.02165177, 67 | 0.01074664, 68 | -0.03528614 69 | ] 70 | 71 | 稀疏嵌入总长度: 23 72 | 稀疏嵌入前10个非零值: [ 73 | ('6', np.float32(0.07353998)), 74 | ('28323', np.float32(0.07607669)), 75 | ('8869', np.float32(0.15832466)), 76 | ('48124', np.float32(0.16404563)), 77 | ('213212', np.float32(0.20880711)), 78 | ('75133', np.float32(0.25368175)), 79 | ('4', np.float32(0.05709494)), 80 | ('31833', np.float32(0.111040354)), 81 | ('12461', np.float32(0.18773092)), 82 | ('101184', np.float32(0.18636838)) 83 | ] 84 | ``` -------------------------------------------------------------------------------- /docs/rag/embedding/hybrid/README.md: -------------------------------------------------------------------------------- 1 | # 混合嵌入 2 | 3 | **混合嵌入(Hybrid Embedding)**:是现代信息检索和推荐系统中一种结合了**稀疏嵌入(Sparse Embedding)** 和 **密集嵌入(Dense Embedding)** 的方法,旨在发挥两者的优势,弥补各自的缺陷,提升模型的表达能力、泛化能力和可解释性。它在推荐系统、搜索引擎、自然语言处理(NLP)、计算机视觉(CV)等领域有广泛应用 4 | 5 | ## 为什么需要混合嵌入 6 | 7 | | 类型 | 优点 | 缺点 | 8 | | -------------------- | ------------ | ---------------- | 9 | | 稀疏嵌入(如 `BM25`, `TF-IDF`) | 精确匹配强、可解释性高 | 不理解同义词、语义差 | 10 | | 密集嵌入(如 `BERT` 向量) | 语义理解强、支持近似匹配 | 忽略拼写/实体差异,泛化可能过强 | 11 | | 混合嵌入 | 精确匹配 | 语义泛化 | 12 | 13 | ## 混合嵌入的典型结构 14 | 混合嵌入通常由两部分组成: 15 | 16 | * **稀疏嵌入层**:处理离散特征(如类别型变量)。 17 | * **密集嵌入层**:处理连续特征(如文本、图像)。 18 | * **融合策略**:将两种嵌入结合(如拼接、加权、注意力机制)。 19 | 20 | ## 混合嵌入的实现方案 21 | 22 | | **方法** | **最佳场景** | **计算开销** | **特点** | 23 | |---|---|---|---| 24 | | **并行混合Wide & Deep**| 推荐系统、广告CTR| 低 | 稀疏部分记忆历史行为,密集部分泛化语义,适合特征明确的场景 | 25 | | **交叉混合DeepFM** | 电商特征交叉 | 中 | 结合FM的二阶特征交互和DNN的高阶非线性,适合需要显式特征交叉的任务| 26 | | **动态门控混合Gating Network** | 多模态数据(文本+图像)| 高 | 动态调整稀疏/密集特征权重,适合异构数据融合 | 27 | | **特征拼接混合Concatenation** | 结构化数据分类 | 低 | 简单直接拼接特征,适合快速原型开发或特征维度相近的场景 | 28 | | **图混合嵌入Graph Hybrid** | 社交网络/知识图谱 | 高 | 用GNN处理关系数据,DNN处理属性数据,适合图结构与非结构化数据混合的场景 | 29 | -------------------------------------------------------------------------------- /docs/rag/embedding/sparse/README.md: -------------------------------------------------------------------------------- 1 | # 稀疏嵌入 2 | 3 | **稀疏嵌入(Sparse Embedding)**:向量的大部分维度为`0`,只有极少数维度有值(如`1`)。 4 | 5 | ## 特点 6 | 7 | * 维度:每个维度对应一个特定的`token`或特征,通常维度极高。 8 | * 可解释性:每一位可映射回某个词或特征,可解释性强。 9 | * 效率:依赖稀疏矩阵处理技术。 10 | * 上下文信息:静态表示,不包含上下文。 11 | 12 | 13 | ## 示例 14 | * `One-hot`:是一种最基本的文本表示方法,对于一个词汇表中的每个词,创建一个全为`0`的向量,只有该词对应的位置才为`1`。 15 | ```py 16 | # 词汇表 17 | glossary = ["apple", "banana", "orange"] 18 | 19 | # banana向量 20 | banana = [0, 1, 0] 21 | ``` 22 | * `TF-IDF`:是一种加权技术,用于衡量词对文档的重要程度。其中`TF`表示某词在该文档中出现的频率(频数),`IDF`衡量某词在整个语料库中是否具有代表性(逆文档频率)。 23 | $$ 24 | \mathrm{TF}(t, d) = \frac{词t在文档d中出现的次数}{文档d中的总词数} 25 | $$ 26 | 27 | $$ 28 | \mathrm{IDF}(t) = \log\left(\frac{N}{1 + 包含词t的文档数} \right) 29 | $$ 30 | 31 | * `BM-25`:是一种信息检索中的打分函数,用于估算文档与查询词的相关性。它是在`TF-IDF`的基础上改进的。 32 | $$ 33 | \mathrm{BM25}(d, q) = \sum_{t \in q} \mathrm{IDF}(t) \cdot \frac{f(t, d) \cdot (k_1 + 1)}{f(t, d) + k_1 \cdot \left(1 - b + b \cdot \frac{|d|}{\mathrm{avgdl}}\right)} 34 | $$ 35 | 36 | ## 应用场景 37 | * **文本处理**:关键词检索,布尔搜索。 38 | * **推荐系统**:用户行为日志。 39 | * **计算机视觉**:传统特征。 40 | * **分类任务**:线性模型。 41 | 42 | ## 实现案例 43 | ::: tip 44 | 以`IF-IDF`为例 45 | ::: 46 | 47 | ```py 48 | import math 49 | from collections import Counter 50 | 51 | # 战斗日志 52 | battle_logs = [ 53 | "猢狲,施展,烈焰拳,击退,妖怪;随后开启,金刚体,抵挡,神兵,攻击。", 54 | "妖怪,使用,寒冰箭,攻击,猢狲,但被,烈焰拳,反击,击溃。", 55 | "猢狲,召唤,烈焰拳,与,毁灭咆哮,击败,妖怪,随后,收集,妖怪,精华。" 56 | ] 57 | # 超参数 58 | k1 = 1.5 59 | b = 0.75 60 | 61 | # 构建词表 62 | vocabulary = set(word for log in battle_logs for word in log.split(",")) 63 | vocab_to_idx = {word: idx for idx, word in enumerate(vocabulary)} 64 | 65 | # 计算df idf 66 | N = len(battle_logs) 67 | df = Counter(word for log in battle_logs for word in set(log.split(","))) 68 | idf = {word: math.log((N - df[word] + 0.5) / (df[word] + 0.5) + 1) for word in vocabulary} 69 | 70 | # 日志长度 71 | avg_log_len = sum(len(log.split(",")) for log in battle_logs) / N 72 | 73 | # BM25稀疏嵌入生成 74 | def bm25_sparse_embedding(log): 75 | tf = Counter(log.split(",")) 76 | log_len = len(log.split(",")) 77 | embedding = {} 78 | for word, freq in tf.items(): 79 | if word in vocabulary: 80 | idx = vocab_to_idx[word] 81 | score = idf[word] * (freq * (k1 + 1)) / (freq + k1 * (1 - b + b * log_len / avg_log_len)) 82 | embedding[idx] = score 83 | return embedding 84 | 85 | # 生成稀疏向量 86 | for log in battle_logs: 87 | print(f"log: {log}") 88 | sparse_embedding = bm25_sparse_embedding(log) 89 | print(f"稀疏嵌入:{sparse_embedding}") 90 | print("=" * 50) 91 | ``` 92 | 输出结果: 93 | ```text 94 | log: 猢狲,施展,烈焰拳,击退,妖怪;随后开启,金刚体,抵挡,神兵,攻击。 95 | 稀疏嵌入:{ 96 | 12: 0.13780819879399125, 97 | 8: 1.0122437130726, 98 | 18: 0.13780819879399125, 99 | 7: 1.0122437130726, 100 | 2: 1.0122437130726, 101 | 10: 1.0122437130726, 102 | 13: 1.0122437130726, 103 | 21: 1.0122437130726, 104 | 20: 1.0122437130726 105 | } 106 | ================================================== 107 | log: 妖怪,使用,寒冰箭,攻击,猢狲,但被,烈焰拳,反击,击溃。 108 | 稀疏嵌入:{ 109 | 14: 0.485057126267841, 110 | 5: 1.0122437130726, 111 | 16: 1.0122437130726, 112 | 4: 1.0122437130726, 113 | 12: 0.13780819879399125, 114 | 22: 1.0122437130726, 115 | 18: 0.13780819879399125, 116 | 11: 1.0122437130726, 117 | 0: 1.0122437130726 118 | } 119 | ================================================== 120 | log: 猢狲,召唤,烈焰拳,与,毁灭咆哮,击败,妖怪,随后,收集,妖怪,精华。 121 | 稀疏嵌入:{ 122 | 12: 0.12572760993867385, 123 | 19: 0.9235080629006516, 124 | 18: 0.12572760993867385, 125 | 17: 0.9235080629006516, 126 | 6: 0.9235080629006516, 127 | 3: 0.9235080629006516, 128 | 14: 0.6429294928361478, 129 | 9: 0.9235080629006516, 130 | 1: 0.9235080629006516, 131 | 15: 0.9235080629006516 132 | } 133 | ================================================== 134 | ``` -------------------------------------------------------------------------------- /docs/rag/loader/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | ::: tip 4 | 所有loader都可以从`langchain_community.document_loaders`中引入 5 | ::: 6 | 文档地址:[LangChain Loader](https://python.langchain.com/api_reference/community/document_loaders.html#) 7 | 8 | `LangChain`中有非常多的`loader`来加载各种各样的文档,例如: 9 | * `TextLoader`:用来加载纯文本,例如`.txt`文件。 10 | * `CSVLoader`:用来加载`.csv`格式文件。 11 | * `JSONLoader`: 用来加载`.json`格式文件。 12 | * 等等 13 | -------------------------------------------------------------------------------- /docs/rag/loader/csv/README.md: -------------------------------------------------------------------------------- 1 | # CSV 2 |
3 | 原始CSV内容: 4 | 5 | ```csv 6 | Category,Name,Description,PowerLevel 7 | 装备,铜云棒,一根结实的青铜棒,挥舞时能发出破空之声,适合近战攻击。,85 8 | 装备,百戏衬钱衣,一件精美的战斗铠甲,能够提供强大的防御并抵御剧毒伤害。,90 9 | 技能,天雷击,召唤天雷攻击敌人,造成大范围雷电伤害。,95 10 | 技能,火焰舞,施展火焰舞步,将敌人包围在炽热的火焰之中。,92 11 | 人物,悟空,主角,拥有七十二变和腾云驾雾的能力,行侠仗义。,100 12 | 人物,银角大王,强大的妖王之一,擅长操控各种法宝,具有极高的战斗力。,88 13 | ``` 14 |
15 | 16 | ## CSVLoader 17 | ::: tip 18 | [CSVLoader 文档](https://python.langchain.com/api_reference/community/document_loaders/langchain_community.document_loaders.csv_loader.CSVLoader.html) 19 | ::: 20 | 21 | ```py 22 | from langchain_community.document_loaders import CSVLoader 23 | 24 | data_loader = CSVLoader( 25 | file_path="data/黑悟空/黑神话悟空.csv", 26 | encoding="utf-8", 27 | content_columns=("名称", "描述"), # 只加载这两列 28 | csv_args={ 29 | "fieldnames": ["名称", "描述"] # 自定义列名 30 | } 31 | ) 32 | 33 | documents = data_loader.load() 34 | 35 | for document in documents[:3]: 36 | print(document.page_content) 37 | print("=" * 50) 38 | ``` 39 | 输出结果: 40 | ```text 41 | 名称: Category 42 | 描述: Name 43 | ================================================== 44 | 名称: 装备 45 | 描述: 铜云棒 46 | ================================================== 47 | 名称: 装备 48 | 描述: 百戏衬钱衣 49 | ================================================== 50 | ``` 51 | 52 | ## DirectoryLoader 53 | ::: tip 54 | [DirectoryLoader 文档](https://python.langchain.com/api_reference/community/document_loaders/langchain_community.document_loaders.directory.DirectoryLoader.html) 55 | ::: 56 | 可以使用`DirectoryLoader` + `CSVLoader`批量加载`.csv`文件。 57 | 58 | ```py 59 | from langchain_community.document_loaders import DirectoryLoader, CSVLoader 60 | 61 | data_loader = DirectoryLoader( 62 | path="./data/灭神纪", 63 | glob="**/*.csv", 64 | loader_cls=lambda path: CSVLoader( 65 | path, 66 | encoding="utf-8" 67 | ) 68 | ) 69 | 70 | documents = data_loader.load() 71 | 72 | print(f"文档数据总数:{len(documents)}") 73 | ``` 74 | 75 | ## UnstructuredCSVLoader 76 | ::: tip 77 | [UnstructuredCSVLoader 文档](https://python.langchain.com/api_reference/community/document_loaders/langchain_community.document_loaders.csv_loader.UnstructuredCSVLoader.html) 78 | ::: 79 | 可以使用`UnstructuredCSVLoader`把`.csv`文件转换为`html`结构: 80 | 81 | ```py 82 | from langchain_community.document_loaders import UnstructuredCSVLoader 83 | 84 | data_loader = UnstructuredCSVLoader( 85 | file_path="./data/黑悟空/黑神话悟空.csv", 86 | encoding="utf-8", 87 | mode="elements" 88 | ) 89 | 90 | documents = data_loader.load() 91 | 92 | print(documents[0].metadata.get('text_as_html')) 93 | ``` 94 | 输出结果: 95 | ```py 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 |
CategoryNameDescriptionPowerLevel
装备铜云棒一根结实的青铜棒,挥舞时能发出破空之声,适合近战攻击。85
装备百戏衬钱 衣一件精美的战斗铠甲,能够提供强大的防御并抵御剧毒伤害。90
技能天雷击召唤天雷攻击敌人,造成大范围雷电伤害。95
技能火焰舞施展火焰 舞步,将敌人包围在炽热的火焰之中。92
人物悟空主角,拥有七十二变和腾云驾雾的能力,行侠仗义。100
人物银角大王强大的妖王之一,擅长操控各种法 宝,具有极高的战斗力。88
140 | ``` -------------------------------------------------------------------------------- /docs/rag/loader/db/README.md: -------------------------------------------------------------------------------- 1 | # DataBase 2 | ::: tip 3 | [SQLDatabaseLoader 文档](https://python.langchain.com/api_reference/community/document_loaders/langchain_community.document_loaders.sql_database.SQLDatabaseLoader.html) 4 | ::: 5 | 6 | 使用`SQLDatabaseLoader`加载数据库数据时,我们以`SQLite`数据库为例。 7 | 8 | ## 数据准备 9 | ```py 10 | import sqlite3 11 | 12 | # 创建测试数据库 13 | def create_sample_db(db_path: str): 14 | conn = sqlite3.connect(db_path) 15 | cursor = conn.cursor() 16 | 17 | # 创建users表 18 | cursor.execute(""" 19 | CREATE TABLE IF NOT EXISTS users ( 20 | id INTEGER PRIMARY KEY, 21 | name TEXT NOT NULL, 22 | email TEXT UNIQUE, 23 | active INTEGER DEFAULT 1 24 | ) 25 | """) 26 | 27 | # 插入测试数据 28 | cursor.executemany( 29 | "INSERT INTO users (name, email) VALUES (?, ?)", 30 | [ 31 | ("张三", "zhang@example.com"), 32 | ("李四", "li@example.com"), 33 | ("王五", "wang@example.com"), 34 | ("赵六", "zhao@example.com"), 35 | ("钱七", "qian@example.com") 36 | ] 37 | ) 38 | 39 | 40 | conn.commit() 41 | conn.close() 42 | 43 | if __name__ == "__main__": 44 | create_sample_db("example.db") 45 | print("测试数据库已创建") 46 | ``` 47 | 48 | ## 加载数据 49 | 50 | ```py 51 | from langchain_community.document_loaders import SQLDatabaseLoader 52 | from langchain_community.utilities import SQLDatabase 53 | 54 | db = SQLDatabase.from_uri(f"sqlite:///example.db") 55 | 56 | data_loader = SQLDatabaseLoader( 57 | db=db, 58 | query="SELECT id, name FROM users WHERE active = 1" 59 | ) 60 | 61 | documents = data_loader.load() 62 | 63 | for document in documents: 64 | print(document.page_content) 65 | print("=" * 50) 66 | 67 | ``` 68 | 输出结果: 69 | ```py 70 | id: 1 71 | name: 张三 72 | ================================================== 73 | id: 2 74 | name: 李四 75 | ================================================== 76 | id: 3 77 | name: 王五 78 | ================================================== 79 | id: 4 80 | name: 赵六 81 | ================================================== 82 | id: 5 83 | name: 钱七 84 | ================================================== 85 | ``` -------------------------------------------------------------------------------- /docs/rag/loader/document/README.md: -------------------------------------------------------------------------------- 1 | # Document类型 2 | 3 | `LangChain`中通过各种`loader`加载后的对象是`Document`类型,其包含`page_content`和`metadata`两个重要属性。 4 | 5 | 除了可以从`loader`加载,还可以手动构造`Document`对象数据,例如: 6 | 7 | ```py 8 | from langchain_core.documents import Document 9 | 10 | documents = [ 11 | Document( 12 | page_content="唐僧是师傅", 13 | metadata={"source": "师徒四人.txt"} 14 | ), 15 | Document( 16 | page_content="悟空是大师兄", 17 | metadata={"source": "师徒四人.txt"} 18 | ), 19 | Document( 20 | page_content="八戒是二师兄", 21 | metadata={"source": "师徒四人.txt"} 22 | ), 23 | Document( 24 | page_content="沙僧是三师兄", 25 | metadata={"source": "师徒四人.txt"} 26 | ), 27 | Document( 28 | page_content="白龙马是小师弟", 29 | metadata={"source": "师徒四人.txt"} 30 | ) 31 | ] 32 | 33 | print(documents) 34 | ``` 35 | 输出结果: 36 | ```text 37 | [ 38 | Document(metadata={'source': '师徒四人.txt'}, page_content='唐僧是师傅'), 39 | Document(metadata={'source': '师徒四人.txt'}, page_content='悟空是大师兄'), 40 | Document(metadata={'source': '师徒四人.txt'}, page_content='八戒是二师兄'), 41 | Document(metadata={'source': '师徒四人.txt'}, page_content='沙僧是三师兄'), 42 | Document(metadata={'source': '师徒四人.txt'}, page_content='白龙马是小师弟') 43 | ] 44 | ``` -------------------------------------------------------------------------------- /docs/rag/loader/html/README.md: -------------------------------------------------------------------------------- 1 | # HTML网页数据 2 | ::: tip 3 | [WebBaseLoader文档](https://python.langchain.com/api_reference/community/document_loaders/langchain_community.document_loaders.web_base.WebBaseLoader.html) 4 | ::: 5 | 6 | ## 选型方案对比 7 | | 加载器名称 | 动态渲染支持 | 核心功能 | 优势场景 | 主要限制| 8 | |----|----|----|----|----| 9 | | **WebBaseLoader** | ❌ | 静态HTML快速解析 | 轻量级抓取静态页面(如文档、博客)| 无法处理JavaScript动态内容| 10 | | **UnstructuredURLLoader** | ❌ | 多格式解析(HTML/PDF等),自动清理文本 | 混合格式内容提取(如带PDF的网页) | 复杂页面可能丢失部分结构 | 11 | | **SeleniumURLLoader** | ✅ | 完整浏览器环境渲染 | 需要登录或交互的动态页面(如SPA) | 配置复杂,运行效率低 | 12 | | **RSSFeedLoader** | ❌ | 结构化解析RSS/Atom订阅源 | 新闻/博客更新追踪 | 仅支持标准订阅格式 | 13 | | **AsyncHtmlLoader** | ❌ | 异步并发批量抓取 | 大规模静态页面采集(50+URLs)| 需要异步编程支持 | 14 | 15 | 16 | ## WebBaseLoader 17 | ::: tip 18 | [WebBaseLoader 文档](https://python.langchain.com/docs/integrations/document_loaders/web_base/) 19 | ::: 20 | 21 | ```py 22 | import bs4 23 | from langchain_community.document_loaders import WebBaseLoader 24 | 25 | # bs_kwargs参数作用是只加载网页主题内容 26 | data_loader = WebBaseLoader( 27 | web_path="https://zh.wikipedia.org/wiki/黑神话:悟空", 28 | bs_kwargs={ 29 | "parse_only": bs4.SoupStrainer(id="bodyContent") 30 | } 31 | ) 32 | 33 | documents = data_loader.load() 34 | document = documents[0] 35 | print(f"{document.metadata}\n") 36 | print(document.page_content) 37 | ``` 38 | 39 | ## RSSFeedLoader 40 | ::: tip 41 | [RSSFeedLoader 文档](https://python.langchain.com/docs/integrations/document_loaders/rss/) 42 | ::: 43 | 44 | 首先需要安装必要的包: 45 | ```sh 46 | $ pip install feedparser newspaper3k listparser 47 | ``` 48 | 49 | ```py 50 | import os 51 | import certifi 52 | 53 | from langchain_community.document_loaders import RSSFeedLoader 54 | 55 | # 设置SSL,防止加载时报错 56 | os.environ["SSL_CERT_FILE"] = certifi.where() 57 | 58 | # RSS Feed地址 59 | urls = [ 60 | "https://36kr.com/feed", 61 | "https://www.huxiu.com/rss/1.xml", 62 | "https://www.ruanyifeng.com/blog/atom.xml", 63 | "https://www.oschina.net/news/rss" 64 | ] 65 | 66 | loader = RSSFeedLoader(urls=urls) 67 | documents = loader.load() 68 | 69 | for i, doc in enumerate(documents[:5]): 70 | print(f"文章 {i+1}:") 71 | print(f"标题: {doc.metadata.get('title', '无标题')}") 72 | print(f"发布时间: {doc.metadata.get('published', '未知时间')}") 73 | print(f"来源: {doc.metadata.get('source', '未知来源')}") 74 | print(f"链接: {doc.metadata.get('link', '无链接')}") 75 | print("-" * 80) 76 | ``` 77 | 输出结果: 78 | ```text 79 | 文章 1: 80 | 标题: 谷歌的 NotebookLM 能生成中文播客了 81 | 发布时间: 未知时间 82 | 来源: 未知来源 83 | 链接: http://www.ruanyifeng.com/blog/2025/05/notebooklm.html 84 | -------------------------------------------------------------------------------- 85 | 文章 2: 86 | 标题: 科技爱好者周刊(第 346 期):未来就是永恒感的丧失 87 | 发布时间: 未知时间 88 | 来源: 未知来源 89 | 链接: http://www.ruanyifeng.com/blog/2025/04/weekly-issue-346.html 90 | -------------------------------------------------------------------------------- 91 | 文章 3: 92 | 标题: 巨头的新战场:AI 编程 IDE(暨 字节 Trae 调用 MCP 教程) 93 | 发布时间: 未知时间 94 | 来源: 未知来源 95 | 链接: http://www.ruanyifeng.com/blog/2025/04/trae-mcp.html 96 | -------------------------------------------------------------------------------- 97 | ``` -------------------------------------------------------------------------------- /docs/rag/loader/markdown/README.md: -------------------------------------------------------------------------------- 1 | # Markdown 2 | ::: tip 3 | [UnstructuredMarkdownLoader文档](https://python.langchain.com/api_reference/community/document_loaders/langchain_community.document_loaders.markdown.UnstructuredMarkdownLoader.html) 4 | ::: 5 | 6 | ```py 7 | from langchain_community.document_loaders import UnstructuredMarkdownLoader 8 | 9 | data_loader = UnstructuredMarkdownLoader( 10 | file_path="./data/黑悟空/黑悟空版本介绍.md", 11 | mode="elements", 12 | strategy="fast" 13 | ) 14 | 15 | documents = data_loader.load() 16 | 17 | for doc in documents[:5]: 18 | print("========文档内容========") 19 | print(f"""element_id={doc.metadata.get('element_id')}, parent_id={doc.metadata.get('parent_id')}""") 20 | print(f"""{doc.page_content}""") 21 | ``` 22 | 输出结果: 23 | ```text 24 | ========文档内容======== 25 | element_id=b89add9386b58a1638e0b96d19f08d0d, parent_id=None 26 | 黑神话:悟空 🐵 27 | ========文档内容======== 28 | element_id=4d1fd58a257960aafb046fc47605c217, parent_id=b89add9386b58a1638e0b96d19f08d0d 29 | 黑神话:悟空 是由中国游戏开发团队制作的一款备受瞩目的动作冒险游戏,以《西游记》为背景,重新演绎了经典故事,带来了极 30 | 具冲击力的视觉和游戏体验。 31 | ========文档内容======== 32 | element_id=2aecac605c643fd6e5877eb2943061d9, parent_id=b89add9386b58a1638e0b96d19f08d0d 33 | 游戏版本介绍 34 | ========文档内容======== 35 | element_id=066222dfa5c88f6daf909cc9f97ddc30, parent_id=2aecac605c643fd6e5877eb2943061d9 36 | 1. 数字标准版 💻 37 | ========文档内容======== 38 | element_id=871db441632d0e97daf97578eef69d48, parent_id=066222dfa5c88f6daf909cc9f97ddc30 39 | 包含基础游戏 40 | ``` -------------------------------------------------------------------------------- /docs/rag/loader/ocr/README.md: -------------------------------------------------------------------------------- 1 | # OCR 2 | 撰写中。。。 -------------------------------------------------------------------------------- /docs/rag/loader/pdf/README.md: -------------------------------------------------------------------------------- 1 | # PDF 2 | 撰写中。。。 -------------------------------------------------------------------------------- /docs/rag/loader/text/README.md: -------------------------------------------------------------------------------- 1 | # 简单文本导入 2 | 3 | ## TextLoader 4 | ::: tip 5 | [TextLoader文档](https://python.langchain.com/api_reference/community/document_loaders/langchain_community.document_loaders.text.TextLoader.html) 6 | ::: 7 | 8 | ```py 9 | from langchain_community.document_loaders import TextLoader 10 | 11 | text_loader = TextLoader( 12 | file_path="./data/黑悟空/设定.txt", 13 | encoding="utf-8" 14 | ) 15 | 16 | documents = text_loader.load() 17 | 18 | print(documents) 19 | ``` 20 | 输出结果: 21 | ```text 22 | [ 23 | Document( 24 | metadata={'source': './data/黑悟空/设定.txt'}, 25 | page_content='《黑神话:悟空》的故事可分为六个章节,名为“火照黑云”、“风起黄昏”、“夜生白露”、“曲度紫鸳”、“日落红尘”和“未竟”, 26 | 并且拥有两个结局,玩家的选择和经历将影响最终的结局。\n\n每个章节结尾,附有二维 和三维的动画过场, 27 | 展示和探索《黑神话:悟空》中的叙事和主题元素。游戏的设定融合了中国的文化和自然地标。 28 | 例如重庆的大足石刻、山西省的小西天、南禅寺、铁佛寺、广胜寺和鹳雀楼等,都在游戏中出现。 29 | 游戏也融入了佛教和道教的哲学元素。' 30 | ) 31 | ] 32 | ``` 33 | 34 | ## DirectoryLoader 35 | ::: tip 36 | [DirectoryLoader文档](https://python.langchain.com/api_reference/community/document_loaders/langchain_community.document_loaders.directory.DirectoryLoader.html) 37 | ::: 38 | 39 | 可使用`DirectoryLoader`一次性加载某个目录下所有`txt`文件。 40 | ```py 41 | from langchain_community.document_loaders import DirectoryLoader, TextLoader 42 | 43 | markdown_loader = DirectoryLoader( 44 | path="./data/黑悟空", 45 | glob=["**/*.txt"], 46 | loader_cls=lambda path: TextLoader(path, encoding="utf-8") 47 | ) 48 | 49 | documents = markdown_loader.load() 50 | 51 | print(f"文档数:{len(documents)}") 52 | ``` 53 | 54 | ## Unstructured 55 | ::: tip 56 | [Unstructured 文档](https://docs.unstructured.io/open-source/introduction/quick-start) 57 | ::: 58 | 59 | 如要在加载文档时有自定义要求,可使用`Unstructured`获取更多信息。 60 | ```py 61 | from unstructured.partition.text import partition_text 62 | 63 | elements = partition_text( 64 | "./data/黑悟空/设定.txt" 65 | ) 66 | 67 | for element in elements: 68 | print("============================") 69 | print(f"文档内容: {element.text}") 70 | 71 | print("元数据:") 72 | metadata_dict = element.metadata.__dict__ 73 | for key, value in metadata_dict.items(): 74 | if not key.startswith('_') and value is not None: 75 | print(f" {key}: {value}") 76 | ``` 77 | 78 | 输出结果: 79 | ```text 80 | ============================ 81 | 文档内容: 《黑神话:悟空》的故事可分为六个章节,名为“火照黑云”、“风起黄昏”、“夜生白露”、“曲度紫鸳”、“日落红尘”和“未竟”, 82 | 并且拥有两个结局,玩家的选择和经历将影响最终的结局。 83 | 元数据: 84 | last_modified: 2025-04-27T22:13:40 85 | languages: ['zho'] 86 | file_directory: ./data/黑悟空 87 | filename: 设定.txt 88 | filetype: text/plain 89 | ============================ 90 | 文档内容: 每个章节结尾,附有二维和三维的动画过场,展示和探索《黑神话:悟空》中的叙事和主题元素。 91 | 元数据: 92 | last_modified: 2025-04-27T22:13:40 93 | languages: ['zho'] 94 | file_directory: ./data/黑悟空 95 | filename: 设定.txt 96 | filetype: text/plain 97 | ============================ 98 | 文档内容: 游戏的设定融合了中国的文化和自然地标。例如重庆的大足石刻、山西省的小西天、南禅寺、铁佛寺、广胜寺和鹳雀楼等, 99 | 都在游戏中出现。游戏也融入了佛教和道教的哲学元素。 100 | 元数据: 101 | last_modified: 2025-04-27T22:13:40 102 | languages: ['zho'] 103 | file_directory: ./data/黑悟空 104 | filename: 设定.txt 105 | filetype: text/plain 106 | ``` -------------------------------------------------------------------------------- /docs/rag/vectorStore/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | ## 向量 4 | 5 | ### 向量和标量 6 | 7 | **向量(Vector)**:是一个有方向和大小的量,常以一组有序的浮点数组来表示,例如: 8 | ```py 9 | vector = [0.1, 0.8, -0.3, ..., 0.05] 10 | ``` 11 | 12 | **标量(Scalar)**:是一个只有大小,没有方向的量(例如,温度,质量)。 13 | 14 | ### 向量的分类 15 | 16 | 向量按存储内容可分为: 17 | * **数值向量**:包含纯数字。 18 | * **特征向量**:表示对象特征的数值。 19 | * **词向量**:表示词语语义。 20 | 21 | ### 向量的运算 22 | 向量之间可以进行运算: 23 | * 加法:对应的分量相加,例如:`[a1, a2] + [b1, b2] = [a1 + b1, a2 + b2]`。 24 | * 数乘:标量乘以向量的每一个分量,例如:`k * [v1, v2] = [v1 * k, v2 * k]`。 25 | * 点积:两个向量中,对应的每一个分量相乘,最后求和,例如:`[a1, a2] * [b1, b2] = a1 * b1 + a2 * b2`。 26 | * 余弦相似度:求`cos`。 27 | * 欧氏距离:求`d(a,b)`。 28 | 29 | ```py 30 | import numpy as np 31 | 32 | a = np.array([1, 2, 3]) 33 | b = np.array([4, 5, 6]) 34 | k = 2 35 | 36 | # 向量的加法 37 | print(a + b) # 输出[5 7 9] 38 | 39 | # 数乘 40 | print(k * a) # 输出[2 4 6] 41 | 42 | # 点积 43 | print(np.dot(a, b)) # 输出32 44 | 45 | # 余弦相似度 46 | cos_sim = np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)) 47 | print(cos_sim) # 输出0.9746318461970762 48 | 49 | # 欧氏距离 50 | euclidean_dist = np.linalg.norm(a - b) 51 | print(euclidean_dist) # 输出5.196152422706632 52 | ``` 53 | ## 向量数据库 54 | 55 | **向量数据库(Vector DB)**:是一种专门用于存储、索引和查询向量数据(高维数值数组)的数据库系统。与传统数据库基于精确匹配的查询方式不同,向量数据库通过计算向量之间的相似度来检索数据,这使得它特别适合处理非结构化数据(如图像、文本、音频等)的相似性搜索。 56 | 57 | 58 | ### 核心功能 59 | 60 | 其核心功能如下: 61 | * **向量操作**:支持向量插入/更新/删除。 62 | * **近似最近邻(ANN)搜索**:在精度和性能之间取得平衡的搜索算法。 63 | * **向量相似性搜索**:基于余弦相似度、欧氏距离或内积等度量方式。 64 | * **索引构建与压缩**:构建如 `HNSW`、`IVF`、`PQ` 等索引结构。 65 | * **高维数据处理**:能够有效处理数百至数千维的数据。 66 | * **与结构化数据关联**:支持元数据存储与联合查询。 67 | * **大规模数据处理**:支持数十亿级别的向量高效检索。 68 | 69 | ### 主流向量数据库对比 70 | ::: tip 71 | [LangChain官方 向量存储方案对比](https://python.langchain.com/docs/integrations/vectorstores/)
72 | [向量数据库Benchmark对比](https://ann-benchmarks.com/index.html) 73 | ::: 74 | | 向量数据库 | 原生向量支持 | 是否开源 | 是否分布式 | 特点/优势 | 缺陷不足 | 典型适用场景 | 75 | | --- | --- | --- | --- | --- | --- | --- | 76 | | **Milvus** | 是 | 是 | 是 | 企业级、分布式、支持亿级数据量 | 资源需求高,部署复杂 | 图像搜索、推荐系统 | 77 | | **Qdrant** | 是 | 是 | 是 | REST/gRPC、支持过滤、异步搜索 | 较新项目、生态不如 Milvus 全 | 向量+元数据混合过滤 | 78 | | **Weaviate** | 是 | 是 | 是 | GraphQL 接口,支持嵌入生成和元数据联查 | 容器部署稍重 | 语义搜索、问答系统 | 79 | | **Pinecone** | 是 | 否 | 是 | 商业实现,全托管、免维护、上线快 | 付费、不可私有部署 | 快速开发、MVP、原型验证 | 80 | | **Faiss** | 是 | 是 | 否 | 高性能 ANN 算法库,支持多种索引,学术界流行 | 无服务层、不分布式 | 离线处理、研究、原型验证 | 81 | | **Chroma** | 是 | 是 | 否 | 零配置、本地知识库友好 | 不支持 ANN、大数据不适用 | 轻量 RAG、个人项目 | 82 | | **Redis** | `7.0+`支持 | 是 | 是 | 极低延迟,实时向量搜索 | 内存占用高、不适合超大规模 | 实时推荐、个性化问答 | 83 | | **MongoDB** | `5.0+`支持 | 是 | 是 | 适合文档+语义联合搜索 | 向量维度限制、功能有限 | 文档搜索、轻量语义搜索 | 84 | | **PGVector** | 扩展形式 | 是 | 否 | 原生 SQL 接口 | 单机性能有限,写入慢 | 企业集成、轻量向量搜索 | 85 | | **Elasticsearch** | `8.0+`支持 | 是 | 是 | 全文+向量混合检索 | 向量维度低(768 默认)、性能中等 | 多模态搜索、有 ES 基础场景 | 86 | -------------------------------------------------------------------------------- /docs/rag/vectorStore/chroma/README.md: -------------------------------------------------------------------------------- 1 | # Chroma 2 | ::: tip 3 | [Chroma 文档](https://docs.trychroma.com/docs/overview/introduction) 4 | ::: 5 | 6 | ## 安装 7 | 8 | 执行此命令安装`chroma`包: 9 | ```sh 10 | $ pip install chromadb 11 | ``` 12 | 13 | ## 客户端 14 | `Chroma`中的客户端一份分为如下几种类型: 15 | * **临时客户端(Ephemeral Client)**:数据存储在本地内存中,适合快速严重一些特性。 16 | * **持久化客户端(Persistent Client)**:数据存储在本地硬盘中,在`Chroma`其中时自动加载硬盘已经存储的数据。 17 | * **客户端-服务端模式(Client Server Mode)**:服务端和客户端可分离。 18 | 19 | ### 临时客户端 20 | 通过如下代码创建临时客户端: 21 | ```py 22 | import chromadb 23 | 24 | client = chromadb.EphemeralClient() 25 | ``` 26 | 27 | ### 持久化客户端 28 | 通过如下代码创建持久化客户端: 29 | ```py 30 | import chromadb 31 | 32 | client = chromadb.PersistentClient( 33 | path="./data" 34 | ) 35 | ``` 36 | 上述代码执行后会创建一个本地`db`: 37 | ```sh 38 | | - data 39 | | - | - chroma.sqlite3 40 | ``` 41 | 42 | ### 服务端-客户端模式 43 | 通过如下代码启动服务端: 44 | ```sh 45 | # 默认端口和host 46 | $ chroma run --path /db_path 47 | 48 | # 自定义端口和host 49 | $ chroma run --host localhost --port 80000 --path /db_path 50 | ``` 51 | ![Chroma Server](../../../images/rag/rag_chroma_server.png) 52 | 53 | 通过如下代码链接服务端: 54 | ```py 55 | import chromadb 56 | 57 | client = chromadb.HttpClient( 58 | host="localhost", 59 | port=8080, 60 | ) 61 | ``` 62 | 63 | ## 集合(Collection) 64 | ::: tip 65 | `Collection`是向量数据库中存储一组相似数据的逻辑单元,类似于传统数据库中的表`Table` 66 | ::: 67 | 68 | 集合相关操作如下: 69 | ```py 70 | # 创建集合(仅创建) 71 | collection = client.create_collection( 72 | name="test_collection" 73 | ) 74 | # 创建集合(如果存在则返回,如果不存在则创建) 75 | collection = client.get_or_create_collection( 76 | name="test_collection" 77 | ) 78 | 79 | 80 | # 修改集合名称 81 | collection.modify(name="dev") 82 | 83 | # 删除集合(不可逆,谨慎操作) 84 | client.delete_collection( 85 | name="test_collection" 86 | ) 87 | 88 | # 集合其它方法 89 | print(collection.peek()) # 返回一组items列表 90 | print(collection.count()) # 返回items的数量 91 | ``` 92 | 93 | ## 集合数据(Collection Data) 94 | 在操作集合数据时,有如下几个关键参数: 95 | * **documents**: 可选,与`embeddings`不能同时为空,原始文档对象的列表。 96 | * **embeddings**:可选,与`documents`不能同时为空,一组向量列表。 97 | * **metadatas**:可选,元数据列表,需要和`documents` 和 `embeddings`在维度上相同。 98 | * **ids**:必填,一组唯一`id`的列表,需要和`documents` 和 `embeddings`在维度上相同。 99 | 100 | 101 | ### 添加集合数据 102 | ```py 103 | # 添加数据 104 | collection.add( 105 | documents=["Vue.js", "React.js", "Svelte.js"], 106 | metadatas=[ 107 | { "framework": "FE", "version": "2.7" }, 108 | { "framework": "FE", "version": "18.0" }, 109 | { "framework": "FE", "version": "5.0" } 110 | ], 111 | ids=["id1", "id2", "id3"] 112 | ) 113 | print(collection.count()) 114 | ``` 115 | 116 | ### 更新集合数据 117 | ```py 118 | # 同时更新document和metadata 119 | collection.update( 120 | ids=["id1"], 121 | documents=["Vue.js"] 122 | metadatas=[ 123 | { "framework": "FE", "version": "3.0" } 124 | ] 125 | ) 126 | 127 | # 插入数据 128 | collection.upsert( 129 | documents=["Angular.js"], 130 | metadatas=[ 131 | { "framework": "FE", "version": "20.0" } 132 | ], 133 | ids=["id4"] 134 | ) 135 | ``` 136 | 137 | ### 删除集合数据 138 | ```py 139 | # ids可选,如果不提供,则删除满足where条件所有的数据 140 | collection.delete( 141 | ids=["id3"], 142 | where={ 143 | "version": "5.0" 144 | } 145 | ) 146 | ``` 147 | 148 | ## 查询集合(Query Collection) 149 | ::: tip 150 | [Collection Query API 文档](https://docs.trychroma.com/reference/python/collection#query)
151 | [Collection Get API 文档](https://docs.trychroma.com/reference/python/collection#get) 152 | ::: 153 | ```py 154 | # 根据查询内容查询 155 | result = collection.query( 156 | query_texts=["Vue.js"], 157 | n_results=1 # 仅返回最匹配的一项 158 | ) 159 | 160 | # 根据id查询 161 | result = collection.get( 162 | ids=["id1", "id2", "id3"], 163 | where={ 164 | "version": "3.0" 165 | } 166 | ) 167 | ``` 168 | 169 | ## 元数据过滤(Metadata Filter) 170 | 171 | ## 自定义Embedding 172 | 173 | ## 多模态(MultiModal) -------------------------------------------------------------------------------- /docs/rag/vectorStore/milvus/README.md: -------------------------------------------------------------------------------- 1 | # Milvus 2 | ::: tip 3 | [Milvus 文档](https://milvus.io/docs/zh/quickstart.md) 4 | ::: 5 | 撰写中。。。 -------------------------------------------------------------------------------- /docs/rollup/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Rollup介绍 3 | `Rollup`它是一个类似于`Webpack`的打包工具,区别于`Webpack`,它更适合一个库的打包。 -------------------------------------------------------------------------------- /docs/rollup/babel/README.md: -------------------------------------------------------------------------------- 1 | # Babel转义 2 | 3 | 在上一章节,我们提到了`@rollup/plugin-babel`这个插件,它是用来把`ES6`代码在打包的时候转义成`ES5`的。 4 | 5 | 下面详细介绍`Rollup`中如何进行`Babel`转义。 6 | 7 | 首先,需要我们安装几个`npm`包,如下: 8 | ```bash 9 | # 安装rollup 相关插件包 10 | $ npm install @rollup/plugin-commonjs -D 11 | $ npm install @rollup/plugin-node-resolve -D 12 | $ npm install @rollup/plugin-babel -D 13 | 14 | # 安装babel相关包 15 | $ npm install @babel/core @babel/preset-env -D 16 | ``` 17 | 18 | 安装完毕后,需要在`rollup.config.mjs`中使用插件,如下: 19 | ```js 20 | import commonjs from '@rollup/plugin-commonjs' 21 | import nodeResolve from '@rollup/plugin-node-resolve' 22 | import babel from '@rollup/plugin-babel' 23 | 24 | export default { 25 | ...省略其它 26 | plugins: [ 27 | nodeResolve(), 28 | commonjs(), 29 | babel({ 30 | babelHelpers: 'bundled' 31 | }) 32 | ] 33 | } 34 | ``` 35 | 36 | 然后,需要在根目录下新建`.babelrc`文件,并撰写如下内容: 37 | ```json 38 | { 39 | "presets": [ 40 | "@babel/preset-env" 41 | ] 42 | } 43 | ``` 44 | 45 | 为了测试是否正确的处理了`ES6`相关的代码,我们需要改动一下入口文件`src/index.js`,并添加如下两个函数: 46 | ```js 47 | export const add = (a, b) => { 48 | return a + b 49 | } 50 | 51 | export const minus = (a, b) => { 52 | return a - b 53 | } 54 | ``` 55 | 最后,我们再次运行`npm run build`打包命令,查看`dist`目录下`vue.esm.js`文件打包后的代码。 56 | ```js 57 | var add = function add(a, b) { 58 | return a + b; 59 | }; 60 | var minus = function minus(a, b) { 61 | return a - b; 62 | }; 63 | 64 | export { add, minus }; 65 | ``` 66 | 67 | 可以看到,`ES6`相关的代码已经被正确的转义了。 68 | -------------------------------------------------------------------------------- /docs/rollup/base/README.md: -------------------------------------------------------------------------------- 1 | # 基础配置 2 | 3 | 在开始之前,我们需要新建一个项目,并且创建一些必要的文件目录,如下: 4 | 5 | ```bash 6 | |-- rollup-learn 7 | | |-- src 8 | | | |-- index.js # 入口文件 9 | ``` 10 | 接着,在`src/index.js`文件撰写如下代码: 11 | ```js 12 | // src/index.js 13 | export function helloRollup () { 14 | console.log('hello, rollup') 15 | } 16 | ``` 17 | 18 | 然后使用如下命令创建一个`package.json`文件: 19 | ```bash 20 | $ npm init -y 21 | ``` 22 | 创建完毕后,再修改`package.json`,修改后如下: 23 | ```json 24 | { 25 | "name": "rollup-learn", 26 | "version": "1.0.0", 27 | "main": "index.js", 28 | "scripts": { 29 | "dev": "rollup -w -c rollup.config.mjs", 30 | "build": "rollup -c rollup.config.mjs" 31 | }, 32 | "keywords": [], 33 | "author": "", 34 | "license": "ISC" 35 | } 36 | ``` 37 | 38 | 打包参数说明: 39 | * `-w`:全称`--watch`,表示监听代码变化,自动打包。 40 | * `-c`: 全称`--config`,表示指明打包配置文件。 41 | 42 | 接着撰写`rollup.config.mjs`配置文件,如下: 43 | ::: tip 44 | 对于`.mjs`格式的配置文件,`Rollup`直接支持`import/export`语法,不需要额外转义。 45 | ::: 46 | ```js 47 | export default { 48 | input: './src/index.js', 49 | output: [ 50 | { file: 'dist/vue.cjs.js', format: 'cjs' }, 51 | { file: 'dist/vue.esm.js', format: 'es' }, 52 | { file: 'dist/vue.js', format: 'umd', name: 'Vue' } 53 | ] 54 | } 55 | ``` 56 | 最后,安装依赖`Rollup`并执行打包命令: 57 | ```sh 58 | # 安装依赖(rollup@4.x+版本) 59 | $ npm install rollup --save-dev 60 | 61 | # 运行打包命令 62 | $ npm run build 63 | ``` 64 | 运行完毕后,在`dist`目录下,会出现三个打包文件,目录结构如下: 65 | ```sh 66 | |-- dist 67 | | |-- vue.js // umd规范打包产物 68 | | |-- vue.cjs.js // commonjs规范打包产物 69 | | |-- vue.esm.js // esm规范打包产物 70 | ``` 71 | 72 | 这样,我们的基础目录已经有了,在之后的小节中,所有案例均基于这个基础的目录结构。 -------------------------------------------------------------------------------- /docs/rollup/changelog/README.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 撰写中。。。 -------------------------------------------------------------------------------- /docs/rollup/commit/README.md: -------------------------------------------------------------------------------- 1 | # 提交规范 2 | 撰写中。。。 -------------------------------------------------------------------------------- /docs/rollup/concept/README.md: -------------------------------------------------------------------------------- 1 | # 核心概念 2 | 3 | 同`Webpack`一样,`Rollup`也有以下几大核心概念: 4 | * `input`:入口文件,类比于`Webpack`的`entry`,它指明了库文件入口位置。 5 | * `output`:输出位置,它指明了打包后的输出信息,包括:输出目录、打包文件名、输出格式等。 6 | * `plugins`:插件,`Rollup`在构建过程中,插件可提供一些辅助功能,例如:`alias`别名解析、`Babel`进行`ES6`转义等。 7 | * `external`:当库依赖于其它第三方库时,我们不需要把这些第三方库一起打包,而是应该把依赖写在`external`里面。 8 | 9 | `Rollup`同样适合使用配置文件的做法来配置打包的选项,一个配置案例如下: 10 | ```js 11 | // rollup.config.js 12 | import json from '@rollup/plugin-json' 13 | import terser from '@rollup/plugin-terser' 14 | 15 | export default { 16 | input: 'src/main.js', 17 | output: [ 18 | { file: 'dist/vue.js', format: 'umd', name: 'Vue' }, 19 | { file: 'dist/vue.common.js', format: 'cjs', name: 'Vue' }, 20 | { file: 'dist/vue.esm.js', format: 'es', name: 'Vue' } 21 | ], 22 | plugins: [ 23 | json(), 24 | terser() 25 | ], 26 | external: ['lodash'], 27 | } 28 | ``` 29 | 30 | 常用输出构建格式说明: 31 | * `umd`:此选项构建出来的库文件是一个通用模式,可以通过不同的方式去使用:`script`标签引入、`CommonJs`规范引入和`RequireJs`规范引入等。 32 | * `cjs`: 此选项构建出来的库文件主要为`CommonJs`规范,可在`Node`环境中使用。 33 | * `es`:此版本构建出来的库文件主要为`ES Module`规范,可在支持`ES Module`,也就是`import/export`的环境中使用。 34 | -------------------------------------------------------------------------------- /docs/rollup/config/README.md: -------------------------------------------------------------------------------- 1 | # 配置项类型提示 2 | 为了方便在写`Rollup`配置项时,有充足的`ts`类型提示,可使用如下两种方式: 3 | 4 | 第一种:`JSDoc`形式,如下: 5 | ```js 6 | // rollup.config.mjs 7 | /** 8 | * @type {import('rollup').RollupOptions} 9 | */ 10 | export default { 11 | ...省略 12 | } 13 | ``` 14 | 15 | 第二种,使用`Rollup`提供的`defineConfig`方法,如下: 16 | ```js 17 | // rollup.config.mjs 18 | import { defineConfig } from 'rollup' 19 | export default defineConfig({ 20 | ...省略 21 | }) 22 | ``` 23 | 24 | 以上仅列举官方提供的两种方式,你可以点击[Rollup配置智能提示](https://cn.rollupjs.org/command-line-interface/#config-intellisense)了解更多。 -------------------------------------------------------------------------------- /docs/rollup/environment/README.md: -------------------------------------------------------------------------------- 1 | # 环境区分 2 | 3 | 在`Rollup`中,区分开发环境和生产环境配置十分简单,其中一个方法是可以使用不同的配置文件进行区分即可。 4 | 5 | 对于配置文件,我们做如下规定: 6 | * `rollup.base.config.mjs`: 公共配置。 7 | * `rollup.dev.config.mjs`: 开发环境配置。 8 | * `rollup.prod.config.mjs`: 生产环境配置。 9 | 10 | 在根目录下新建`build`文件夹,然后分别新建以上三个文件: 11 | ```sh 12 | |-- build 13 | | |-- rollup.base.config.mjs 14 | | |-- rollup.dev.config.mjs 15 | | |-- rollup.prod.config.mjs 16 | ``` 17 | 18 | `rollup.base.config.mjs`完整代码如下: 19 | ```js 20 | import commonjs from '@rollup/plugin-commonjs' 21 | import nodeResolve from '@rollup/plugin-node-resolve' 22 | import babel from '@rollup/plugin-babel' 23 | import typescript from '@rollup/plugin-typescript' 24 | 25 | export default { 26 | input: 'src/index.ts', 27 | plugins: [ 28 | commonjs(), 29 | nodeResolve(), 30 | typescript(), 31 | babel({ 32 | babelHelpers: 'bundled' 33 | }) 34 | ] 35 | } 36 | ``` 37 | 38 | `rollup.dev.config.mjs`完整代码如下: 39 | ```js 40 | import baseConfig from './rollup.base.config' 41 | 42 | const devConfig = { 43 | ...baseConfig, 44 | output: [ 45 | { file: 'dist/vue.cjs.js', format: 'cjs' }, 46 | { file: 'dist/vue.esm.js', format: 'es' }, 47 | { file: 'dist/vue.js', format: 'umd', name: 'Vue' } 48 | ] 49 | } 50 | export default devConfig 51 | ``` 52 | 53 | `prod`环境下,区分与开发环境,我们需要对代码进行代码。需要安装`Rollup`压缩代码的相关`npm`包: 54 | ```sh 55 | # 安装rollup相关包 56 | $ npm install @rollup/plugin-terser -D 57 | ``` 58 | 59 | `rollup.prod.config.mjs`完整代码如下: 60 | ```js 61 | import terser from '@rollup/plugin-terser' 62 | import baseConfig from './rollup.base.config.mjs' 63 | 64 | /** 65 | * @type { import('rollup').RollupOptions } 66 | */ 67 | export default { 68 | ...baseConfig, 69 | output: [ 70 | { file: 'dist/vue.cjs.min.js', format: 'cjs' }, 71 | { file: 'dist/vue.esm.min.js', format: 'es' }, 72 | { file: 'dist/vue.min.js', format: 'umd', name: 'Vue' } 73 | ], 74 | plugins: [ 75 | ...baseConfig.plugins, 76 | terser() 77 | ] 78 | } 79 | ``` 80 | 接着,我们需要在`package.json`文件中修改打包命令: 81 | ```json 82 | "scripts": { 83 | "dev": "rollup -w -c ./build/rollup.dev.config.mjs", 84 | "build": "rollup -c ./build/rollup.prod.config.mjs" 85 | } 86 | ``` 87 | 最后,我们尝试使用`npm run build`命令打包生产环境代码,执行后会在`dist`目录下生成三个`.min.js`文件且代码是经过压缩的。 88 | ```js 89 | |-- dist 90 | | |-- vue.cjs.min.js 91 | | |-- vue.esm.min.js 92 | | |-- vue.min.js 93 | ``` -------------------------------------------------------------------------------- /docs/rollup/eslint/README.md: -------------------------------------------------------------------------------- 1 | # Eslint 2 | 撰写中。。。 -------------------------------------------------------------------------------- /docs/rollup/jest/README.md: -------------------------------------------------------------------------------- 1 | # 支持Jest自动化测试 2 | 如果需要支持`Jest`自动化测试,需要我们安装额外的`npm`包: 3 | ```bash 4 | # 安装jest 5 | $ npm install jest -D 6 | ``` 7 | 因为要测试的文件是包含`ts`代码,因此我们需要再安装其它的包: 8 | ```bash 9 | $ npm install babel-jest ts-jest -D 10 | ``` 11 | 安装完毕后,在根目录下新建`jest.config.js`文件,并填写配置: 12 | ```js 13 | module.exports = { 14 | preset: 'ts-jest', 15 | testMatch: [ 16 | "**/tests/**/*.(spec|test).(js|jsx|ts|tsx)" 17 | ], 18 | collectCoverage: true, 19 | coverageDirectory: '/tests/coverage', 20 | collectCoverageFrom: [ 21 | 'src/**/*.(js|jsx|ts|tsx)' 22 | ] 23 | } 24 | ``` 25 | 配置说明: 26 | * `preset`:要测试的代码,包含`ts`的内容,使用`ts-jest`来处理。 27 | * `testMatch`:测试哪些文件,以上配置表明我们要测试`tests`目录下所有`.(spce|test).(js|jsx|ts|tsx)`。 28 | * `collectCoverage`:生成测试报告。 29 | * `coverageDirectory`: 测试报告存放位置。 30 | * `collectCoverageFrom`:测试报告收集范围。 31 | 32 | 配置文件撰写完毕后,我们在根目录下新建一个`tests`目录,并添加一个测试文件`index.test.js`。 33 | ```js 34 | // 如果需要使用import,需要自己额外的配置 35 | const { add } = require('../src/index') 36 | 37 | describe('index.ts', () => { 38 | it('test add func', () => { 39 | expect(add(1, 2)).toBe(3) 40 | }) 41 | }) 42 | ``` 43 | 最后,需要在`package.json`文件中添加一条测试命令: 44 | ```json 45 | "scripts": { 46 | "dev": "rollup -w -c rollup.dev.config.js", 47 | "build": "rollup -c rollup.prod.config.js", 48 | "test": "jest" 49 | } 50 | ``` 51 | 运行`npm run jest`命令,它会在控制台输出一些测试覆盖率的信息。 52 | ``` 53 | PASS tests/index.test.js 54 | index.ts 55 | √ test add func (2 ms) 56 | 57 | ----------|---------|----------|---------|---------|------------------- 58 | File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 59 | ----------|---------|----------|---------|---------|------------------- 60 | All files | 83.33 | 100 | 50 | 75 | 61 | index.ts | 83.33 | 100 | 50 | 75 | 6 62 | ----------|---------|----------|---------|---------|------------------- 63 | Test Suites: 1 passed, 1 total 64 | Tests: 1 passed, 1 total 65 | Snapshots: 0 total 66 | Time: 2.345 s 67 | Ran all test suites. 68 | ``` 69 | -------------------------------------------------------------------------------- /docs/rollup/package/README.md: -------------------------------------------------------------------------------- 1 | # 配置package.json 2 | 我们需要在`package.json`中配置如下信息: 3 | ```json 4 | // package.json文件 5 | { 6 | "main": "dist/vue.cjs.js", // commonjs规范引入 7 | "module": "dist/vue.esm.js", // esm规范引入 8 | "browser": "dist/vue.js", // script引入 9 | "types": "dist/vue.d.ts", // ts类型定义文件 10 | "files": [ 11 | "dist" 12 | ] 13 | } 14 | ``` 15 | 以上配置具体含义如下: 16 | * `main`: 指明`commonjs`规范引入时的入口文件,例如:`require(xxx)`。 17 | * `module`: 指明`esm`规范引入时的入口文件,例如:`import xxx from 'xxx'`。 18 | * `browser`: 指明浏览器`script`脚本引入时的入口文件,例如`` 19 | * `types`: 如果库提供了`ts`类型定义,一般需要配置`types`选项。 20 | * `files`: 配置`npm install`时,拉取的文件。以上配置后,在`node_modules`文件下,其安装文件目录如下: 21 | ```sh 22 | |-- node_modules 23 | | |-- vue 24 | | | | -- dist 25 | | | | |-- vue.cjs.js 26 | | | | |-- vue.esm.js 27 | | | | |-- vue.c.js 28 | | | | |-- index.d.ts 29 | | | | -- package.json 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/rollup/plugins/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 常用插件 3 | ::: warning 4 | 注意,`Rollup`中插件的顺序是有要求的,一般会把解析和转换相关的插件写在前面。 5 | ::: 6 | 7 | `Rollup`并不像`webpack`那样强大,它需要和其它插件配合使用才能完成特定的功能,常用的插件有: 8 | * `@rollup/plugin-commonjs`:将`CommonJs`规范的模块转换为`ESM`规范,提供`Rollup`使用。 9 | * `@rollup/plugin-node-resolve`:与`@rollup/plugin-commonjs`插件一起使用,配合以后就可以使用`node_modules`下的第三方模块代码了。 10 | * `@rollup/plugin-babel`:把`ES6`代码转义成`ES5`代码,需要同时安装`@babel/core`和`@babel/preset-env`插件。注意:如果使用了高于`ES6`标准的语法,例如`async/await`,则需要进行额外的配置。 11 | * `@rollup/plugin-terser`:代码压缩插件。 12 | * `@rollup/plugin-json`: 支持从`.json`读取信息,配合`Rollup`的`Tree Shaking`可只打包`.json`文件中我们真正用到的部分。 13 | 14 | 以上插件使用案例如下: 15 | ```js 16 | // rollup.config.mjs 17 | import commonjs from '@rollup/plugin-commonjs' 18 | import nodeResolve from '@rollup/plugin-node-resolve' 19 | import babel from '@rollup/plugin-babel' 20 | import json from '@rollup/plugin-json' 21 | import typescript from '@rollup/plugin-typescript' 22 | import terser from '@rollup/plugin-terser' 23 | 24 | const config = { 25 | ...省略其它 26 | plugins: [ 27 | resolve(), 28 | commonjs(), 29 | typescript(), 30 | babel(), 31 | json(), 32 | terser() 33 | ] 34 | } 35 | 36 | export default config 37 | ``` 38 | 39 | 以上仅列举最常见的插件,`Rollup`维护了很多其它`plugins`,你可点击[Rollup官方插件列表](https://github.com/rollup/plugins)查看更多内容。 -------------------------------------------------------------------------------- /docs/rollup/typescript/README.md: -------------------------------------------------------------------------------- 1 | # 支持TypeScript 2 | 如果要支持`TypeScript`,需要安装几个`npm`包,如下: 3 | ```bash 4 | # 安装rollup插件和其依赖包 5 | $ npm install @rollup/plugin-typescript tslib -D 6 | ``` 7 | 8 | 安装完毕后,把`rollup.config.mjs`配置文件中,把入口文件改成改为`.ts`后缀并引入`typescript`插件: 9 | ```ts 10 | // rollup.config.mjs 11 | import typescript from '@rollup/plugin-typescript' 12 | 13 | export default { 14 | ...省略其它 15 | input: './src/index.ts', 16 | plugins: [ 17 | typescript() 18 | ] 19 | } 20 | ``` 21 | 接着,在`src`目录下新建`math.ts`文件,将`add`和`minus`方法移动过去并填写相关类型: 22 | ```ts 23 | export const add = (a: number, b: number): number => { 24 | return a + b 25 | } 26 | 27 | export const minus = (a: number, b: number): number => { 28 | return a - b 29 | } 30 | ``` 31 | 32 | 最后,入口文件`src/index.js`改成`src/index.js`,并在其中引用`add和minus方法`: 33 | ```ts 34 | // src/index.ts 35 | 36 | import { add, minus } from './math' 37 | 38 | export const helloRollup = (): void => { 39 | console.log(add(1, 2)) 40 | console.log(minus(3, 4)) 41 | console.log('hello, rollup') 42 | } 43 | ``` 44 | 45 | 运行`npm run build`命令,在`dist`目录下打包出来的`vue.esm.js`文件代码如下: 46 | ```js 47 | var add = function (a, b) { 48 | return a + b; 49 | }; 50 | var minus = function (a, b) { 51 | return a - b; 52 | }; 53 | 54 | var helloRollup = function () { 55 | console.log(add(1, 2)); 56 | console.log(minus(3, 4)); 57 | console.log('hello, rollup'); 58 | }; 59 | 60 | export { helloRollup }; 61 | ``` -------------------------------------------------------------------------------- /docs/vite/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: heading 3 | --- 4 | 5 | # Vite 6 | 撰写中 -------------------------------------------------------------------------------- /docs/vueAnalysis/compile/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 在之前我们提到过,`Vue`根据不同的使用场景,提供了不同版本`Vue.js`打包文件,其中`runtime + compiler`版本允许我们撰写带`template`选项的组件,它能够对`template`进行编译。而`runtime + only`版本则不允许我们这样做,我们使用`Vue-Cli3.0`以上版本的脚手架默认创建的项目都是`runtime + only`版本,其中对于组件的`template`模板,它依赖于`vue-loader`来编译成`render`渲染函数,不再依赖`Vue.js`。 3 | 4 | 在编译原理这个大章节,我们为了深入了解其内部实现原理,主要分析`runtime + compiler`版本的`Vue.js`。这个版本它的入口文件在`src/platforms/web/entry-runtime-with-compiler.js`,在这个入口文件我们可以发现,它不仅重新定义了`$mount`方法,还挂载了一个`compile`全局`API`。 5 | ```js 6 | import { compileToFunctions } from './compiler/index' 7 | const mount = Vue.prototype.$mount 8 | Vue.prototype.$mount = function ( 9 | el?: string | Element, 10 | hydrating?: boolean 11 | ): Component { 12 | el = el && query(el) 13 | 14 | /* istanbul ignore if */ 15 | if (el === document.body || el === document.documentElement) { 16 | process.env.NODE_ENV !== 'production' && warn( 17 | `Do not mount Vue to or - mount to normal elements instead.` 18 | ) 19 | return this 20 | } 21 | 22 | const options = this.$options 23 | // resolve template/el and convert to render function 24 | if (!options.render) { 25 | let template = options.template 26 | if (template) { 27 | if (typeof template === 'string') { 28 | if (template.charAt(0) === '#') { 29 | template = idToTemplate(template) 30 | /* istanbul ignore if */ 31 | if (process.env.NODE_ENV !== 'production' && !template) { 32 | warn( 33 | `Template element not found or is empty: ${options.template}`, 34 | this 35 | ) 36 | } 37 | } 38 | } else if (template.nodeType) { 39 | template = template.innerHTML 40 | } else { 41 | if (process.env.NODE_ENV !== 'production') { 42 | warn('invalid template option:' + template, this) 43 | } 44 | return this 45 | } 46 | } else if (el) { 47 | template = getOuterHTML(el) 48 | } 49 | if (template) { 50 | /* istanbul ignore if */ 51 | if (process.env.NODE_ENV !== 'production' && config.performance && mark) { 52 | mark('compile') 53 | } 54 | 55 | const { render, staticRenderFns } = compileToFunctions(template, { 56 | outputSourceRange: process.env.NODE_ENV !== 'production', 57 | shouldDecodeNewlines, 58 | shouldDecodeNewlinesForHref, 59 | delimiters: options.delimiters, 60 | comments: options.comments 61 | }, this) 62 | options.render = render 63 | options.staticRenderFns = staticRenderFns 64 | 65 | /* istanbul ignore if */ 66 | if (process.env.NODE_ENV !== 'production' && config.performance && mark) { 67 | mark('compile end') 68 | measure(`vue ${this._name} compile`, 'compile', 'compile end') 69 | } 70 | } 71 | } 72 | return mount.call(this, el, hydrating) 73 | } 74 | 75 | Vue.compile = compileToFunctions 76 | ``` 77 | 其中,`$mount`方法我们在组件化章节中已经单独介绍过了,在编译原理这一章节,我们将其分为**parse模板解析**、**optimize优化**和**codegen代码生成**这三个大步骤来深入学习其实现原理,也就是`compileToFunctions`方法的实现逻辑。 -------------------------------------------------------------------------------- /docs/vueAnalysis/component/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 在之前几个章节中,我们提到过很多次组件的概念,组件在我们日常的开发过程中出现频率是非常高的,它也是`Vue`的两大核心之一:**数据驱动**和**组件化**。 3 | 4 | 在前面章节我们已经介绍完了**数据驱动**,在这个章节我们会着重介绍与**组件化**相关的知识,我们将从入口文件`main.js`开始探索组件化的奥秘。 5 | ```js 6 | import Vue from 'vue' 7 | import App from './App.vue' 8 | import router from './router' 9 | import store from './store' 10 | 11 | Vue.config.productionTip = false 12 | 13 | new Vue({ 14 | router, 15 | store, 16 | render: h => h(App) 17 | }).$mount('#app') 18 | ``` -------------------------------------------------------------------------------- /docs/vueAnalysis/component/async.md: -------------------------------------------------------------------------------- 1 | # 异步组件 2 | 异步组件 -------------------------------------------------------------------------------- /docs/vueAnalysis/design/README.md: -------------------------------------------------------------------------------- 1 | # 设计 2 | 3 | ## 源码目录设计 4 | `Vue.js`源码目录设计如下: 5 | ```sh 6 | |-- dist # 构建目录 7 | |-- flow # flow的类型声明,类似于TypeScipt 8 | |-- packages # 衍生的npm包,例如vue-server-renderer和vue-template-compiler 9 | |-- scripts # 构建配置和构建脚本 10 | |-- test # 端到端测试和单元测试用例 11 | |-- src # 源代码 12 | | |-- compiler # 编译相关代码 13 | | |-- core # 核心代码 14 | | |-- platforms # 跨平台 15 | | |-- server # 服务端渲染 16 | | |-- sfc # .vue文件解析逻辑 17 | | |-- shared # 工具函数/共享代码 18 | ``` 19 | 对以上目录简要做如下介绍: 20 | * `dist`:`rollup`构建目录,里面存放了所有`Vue`构建后不同版本的文件。 21 | * `flow`:它是Facebook出品的`JavaScript`静态类型检查工具,早期`Vue.js`选择了`flow`而不是现在的`TypeScript`来做静态类型检查,而在最新的`Vue3.0`版本则选择使用`TypeScript`来重写。 22 | * `packages`:`Vue.js`衍生的其它`npm`包,它们在`Vue`构建时自动从源码中生成并且始终和`Vue.js`保持相同的版本,主要是`vue-server-renderer`和`vue-template-compiler`这两个包,其中最后一个包在我们使用脚手架生成项目,也就是使用`.vue`文件开发`Vue`项目时会使用到这个包(`vue-loader`)。 23 | * `scripts`:`rollup`构建配置和构建脚本,`Vue.js`能够通过不同的环境构建不同的版本的秘密都在这个目录下。 24 | * `test`:`Vue.js`测试目录,自动化测试对于一个开源库来说是至关重要的,测试覆盖率在一定程度上是衡量一个库质量的一个重要指标。测试用例无论对于开发还是阅读源码,都是有很大益处的,其中通过测试用例去阅读`Vue`源码是普遍认为可行的一种方式。 25 | 26 | * `src/compiler`:此目录包含了与`Vue.js`编译相关的代码,它包括:模板编译成 AST 抽象语法树、AST 抽象语法树优化和代码生成相关代码。编译的工作可以在构建时用`runtime-only`版本,借助`webpack`和`vue-loader`等工具或插件来进行编译。也可以在运行时,使用包含构建功能的`runtime + compiler`版本。显然,编译是一项比较消耗性能的工作,所以我们日常的开发中,更推荐使用`runtime-only`的版本开发(体积也更小),也就是通过`.vue`文件的形式开发。 27 | 28 | ```js 29 | // 需要使用带编译的版本 30 | new Vue({ 31 | data: { 32 | msg: 'hello,world' 33 | } 34 | template: '
{{msg}}
' 35 | }) 36 | 37 | // 不需要使用带编译的版本 38 | new Vue({ 39 | data: { 40 | msg: 'hello,world' 41 | }, 42 | render (h) { 43 | return h('div', this.msg) 44 | } 45 | }) 46 | ``` 47 | * `src/core`:此目录包含了`Vue.js`的核心代码,包括:内置组件`keep-alive`、全局 API(`Vue.use`、`Vue.mixin`和`Vue.extend`等)、实例化、响应式相关、虚拟 DOM 和工具函数等。 48 | 49 | ```sh 50 | |-- core 51 | | |-- components # 内助组件 52 | | |-- global-api # 全局API 53 | | |-- instance # 实例化 54 | | |-- observer # 响应式 55 | | |-- util # 工具函数 56 | | |-- vdom # 虚拟DOM 57 | ``` 58 | * `src/platform`:`Vue2.0`提供了跨平台的能力,在`React`中有`React Native`跨平台客户端,而在`Vue2.0`中其对应的跨平台就是`Weex`。 59 | 60 | ```js 61 | |-- platform 62 | | |-- web # web浏览器端 63 | | |-- weex # native客户端 64 | ``` 65 | 66 | * `src/server`: `Vue2.0`提供服务端渲染的能力,所有跟服务端渲染相关的代码都在`server`目录下,此部分代码是运行在服务端,而非 Web 浏览器端。 67 | 68 | * `src/sfc`:此目录的主要作用是如何把`.vue`文件解析成一个`JavaScript`对象。 69 | 70 | * `src/shared`:此目录下存放了一些在 Web 浏览器端和服务端都会用到的共享代码。 71 | 72 | 73 | ## 架构设计 74 | 我们通过以上目录结构可以很容易的发现,`Vue.js`整体分为三个部分:**核心代码**、**跨平台相关**和**公共工具函数**。 75 | 76 | 同时其架构是分层的,最底层是一个构造函数(普通的函数),最上层是一个入口,也就是将一个完整的构造函数导出给用户使用。在中间层,我们需要逐渐添加一些方法和属性,主要是原型`prototype`相关和全局API相关。 77 | 78 | ![Vue架构设计](../../images/vueAnalysis/composition.png) 79 | -------------------------------------------------------------------------------- /docs/vueAnalysis/dom/README.md: -------------------------------------------------------------------------------- 1 | # 虚拟DOM 2 | 3 | ## 虚拟DOM介绍 4 | 我们在最开始提到过,`Vue`从`2.0+`版本开始就引入了虚拟`DOM`,也知道`Vue`中的虚拟DOM借鉴了开源库[snabbdom](https://github.com/snabbdom/snabbdom)的实现,并根据自身特色添加了许多特性。 5 | 6 | `Vue`在`1.0+`版本还没有引入虚拟`DOM`的时候,当某一个状态发生变化时,它在一定程度上是知道哪些节点使用到了这个状态,从而可以准确的针对这些节点进行更新操作,不需要进行对比。但这种做法是有一定的代价的,因为更新的粒度太细,每一次节点的绑定都需要一个`Watcher`去观察状态的变化,这样会增加更多的内存开销。当一个状态被越多的节点使用,它的内存开销就越大。 7 | 8 | 因此在`Vue`的`2.0+`版本中,引入了虚拟`DOM`将更新粒度调整为组件级别,当状态发生变化的时候,只派发更新到组件级别,然后组件内部再进行对比和渲染。这样做以后,当一个状态在同一个组件内被引用多次的时候,它们只需要一个`render watcher`去观察状态的变化即可。 9 | 10 | ## Vue中的虚拟DOM 11 | 12 | 虚拟`DOM`解决`DOM`更新的方式是:通过状态生成一个虚拟节点树,然后使用虚拟节点树进行渲染,在渲染之前会使用新生成的虚拟节点树和上一次生成的虚拟节点树进行对比,然后只渲染其不相同的部分(包括新增和删除的)。 13 | 14 | 在`Vue`中,根实例就是虚拟节点树的根节点,各种组件就是`children`孩子节点,树节点使用`VNode`类来表示。它使用`template`模板来描述状态与`DOM`之间的映射关系,然后通过`parse`编译将`template`模板转换成渲染函数`render`,执行渲染函数`render`就可以得到一个虚拟节点树,最后使用这个虚拟节点树渲染到视图上。 15 | 16 | 因此根据上面这段话,我们可以得到`Vue`使用虚拟`DOM`进行模板转视图的一个流程。 17 | 18 |
19 | 虚拟dom 20 |
-------------------------------------------------------------------------------- /docs/vueAnalysis/dom/diff.md: -------------------------------------------------------------------------------- 1 | # Diff算法 2 | Diff算法介绍 -------------------------------------------------------------------------------- /docs/vueAnalysis/entry/README.md: -------------------------------------------------------------------------------- 1 | # 整体流程 2 | 3 | 在之前的介绍中,我们知道`Vue.js`内部会根据`Web`浏览器、`Weex`跨平台和`SSR`服务端渲染,不同的环境寻找不同的入口文件,但其核心代码是在`src/core`目录下,我们这一节的主要目标是为了搞清楚从入口文件到`Vue`构造函数执行,这期间的整体流程。 4 | 5 | 在分析完从入口到构造函数的各个部分的流程后,我们可以得到一份大的流程图: 6 |
7 | 8 |
-------------------------------------------------------------------------------- /docs/vueAnalysis/entry/global.md: -------------------------------------------------------------------------------- 1 | # initGlobalAPI流程 2 | 我们会在`src/core/index.js`文件中看到如下精简代码: 3 | ```js 4 | import Vue from './instance/index' 5 | import { initGlobalAPI } from './global-api/index' 6 | initGlobalAPI(Vue) 7 | 8 | export default Vue 9 | ``` 10 | 在以上代码中,我们发现它引入了`Vue`随后调用了`initGlobalAPI()`函数,此函数的作用是挂载一些全局`API`方法。 11 | 12 | ![initGlobalAPI](../../images/vueAnalysis/initGlobalAPI.png) 13 | 14 | 我们首先能在`src/core/global-api`文件夹下看到如下目录结构: 15 | ```sh 16 | |-- global-api 17 | | |-- index.js # 入口文件 18 | | |-- assets.js # 挂载filter、component和directive 19 | | |-- extend.js # 挂载extend方法 20 | | |-- mixin.js # 挂载mixin方法 21 | | |-- use.js # 挂载use方法 22 | ``` 23 | 24 | 随后在`index.js`入口文件中,我们能看到如下精简代码: 25 | ```js 26 | import { initUse } from './use' 27 | import { initMixin } from './mixin' 28 | import { initExtend } from './extend' 29 | import { initAssetRegisters } from './assets' 30 | import { set, del } from '../observer/index' 31 | import { observe } from 'core/observer/index' 32 | import { extend, nextTick } from '../util/index' 33 | 34 | export function initGlobalAPI (Vue: GlobalAPI) { 35 | Vue.set = set 36 | Vue.delete = del 37 | Vue.nextTick = nextTick 38 | 39 | Vue.observable = (obj) => { 40 | observe(obj) 41 | return obj 42 | } 43 | 44 | initUse(Vue) 45 | initMixin(Vue) 46 | initExtend(Vue) 47 | initAssetRegisters(Vue) 48 | } 49 | ``` 50 | 从以上代码能够很清晰的看到在`index.js`入口文件中,会在`Vue`构造函数上挂载各种全局`API`函数,其中`set`、`delete`、`nextTick`和`observable`直接赋值为一个函数,而其他几种`API`则是调用了一个以`init`开头的方法,我们以`initAssetRegisters()`方法为例,它的精简代码如下: 51 | ```js 52 | // ['component','directive', 'filter'] 53 | import { ASSET_TYPES } from 'shared/constants' 54 | 55 | export function initAssetRegisters (Vue: GlobalAPI) { 56 | ASSET_TYPES.forEach(type => { 57 | Vue[type] = function () { 58 | // 省略了函数的参数和函数实现代码 59 | } 60 | }) 61 | } 62 | ``` 63 | 其中`ASSET_TYPES`是一个定义在`src/shared/constants.js`中的一个数组,然后在`initAssetRegisters()`方法中遍历这个数组,依次在`Vue`构造函数上挂载`Vue.component()`、`Vue.directive()`和`Vue.filter()`方法,另外三种`init`开头的方法挂载对应的全局`API`是一样的道理: 64 | ```js 65 | // initUse 66 | export function initUse(Vue) { 67 | Vue.use = function () {} 68 | } 69 | 70 | // initMixin 71 | export function initMixin(Vue) { 72 | Vue.mixin = function () {} 73 | } 74 | 75 | // initExtend 76 | export function initExtend(Vue) { 77 | Vue.extend = function () {} 78 | } 79 | ``` 80 | 81 | 最后,我们发现还差一个`Vue.compile()`方法,它其实是在`runtime+compile`版本才会有的一个全局方法,因此它在`src/platforms/web/entry-runtime-with-compile.js`中被定义: 82 | ```js 83 | import Vue from './runtime/index' 84 | import { compileToFunctions } from './compiler/index' 85 | Vue.compile = compileToFunctions 86 | export default Vue 87 | ``` 88 | 89 | 根据`initGlobalAPI()`方法的逻辑,可以得到如下流程图: 90 | ![initGlobalAPI流程图](../../images/vueAnalysis/initGlobalAPIProcess.png) 91 | -------------------------------------------------------------------------------- /docs/vueAnalysis/entry/lifecycle.md: -------------------------------------------------------------------------------- 1 | # lifecycleMixin流程 2 | 和以上其它几种方法一样,`lifecycleMixin`主要是定义实例方法和生命周期,例如:`$forceUpdate()`、`$destroy`,另外它还定义一个`_update`的私有方法,其中当调用`$forceUpdate()`方法强制组件重新渲染时会调用这个方法,`lifecycleMixin`精简代码如下: 3 | ```js 4 | export function lifecycleMixin (Vue) { 5 | // 私有方法 6 | Vue.prototype._update = function () {} 7 | 8 | // 实例方法 9 | Vue.prototype.$forceUpdate = function () { 10 | if (this._watcher) { 11 | this._watcher.update() 12 | } 13 | } 14 | Vue.prototype.$destroy = function () {} 15 | } 16 | ``` 17 | 代码分析: 18 | * `_update()`会在组件渲染的时候调用,其具体的实现我们会在组件章节详细介绍。 19 | * `$forceUpdate()`为一个强制`Vue`实例重新渲染的方法,它的内部调用了`_update`,也就是强制组件重新编译渲染。 20 | * `$destroy()`为组件销毁方法,在其具体的实现中,会处理父子组件的关系,事件监听,触发生命周期等操作。 21 | 22 | `lifecycleMixin()`方法的代码不是很多,我们也能很容易的得到如下流程图: 23 |
24 | 25 |
-------------------------------------------------------------------------------- /docs/vueAnalysis/entry/render.md: -------------------------------------------------------------------------------- 1 | # renderMixin流程 2 | 相比于以上几种方法,`renderMixin`是最简单的,它主要在`Vue.prototype`上定义各种私有方法和一个非常重要的实例方法:`$nextTick`,其精简代码如下: 3 | ```js 4 | export function renderMixin (Vue) { 5 | // 挂载各种私有方法,例如this._c,this._v等 6 | installRenderHelpers(Vue.prototype) 7 | Vue.prototype._render = function () {} 8 | 9 | // 实例方法 10 | Vue.prototype.$nextTick = function (fn) { 11 | return nextTick(fn, this) 12 | } 13 | } 14 | ``` 15 | 代码分析: 16 | * `installRenderHelpers`:它会在`Vue.prototype`上挂载各种私有方法,例如`this._n = toNumber`、`this._s = toString`、`this._v = createTextVNode`和`this._e = createEmptyVNode`。 17 | * `_render()`:`_render()`方法会把模板编译成`VNode`,我们会在其后的编译章节详细介绍。 18 | * `nextTick`:就像我们之前介绍过的,`nextTick`会在`Vue`构造函数上挂载一个全局的`nextTick()`方法,而此处为实例方法,本质上引用的是同一个`nextTick`。 19 | 20 | 在以上代码分析完毕后,我们可以得到`renderMixin`如下流程图: 21 |
22 | 23 |
-------------------------------------------------------------------------------- /docs/vueAnalysis/entry/state.md: -------------------------------------------------------------------------------- 1 | # stateMixin流程 2 | `stateMixin`主要是处理跟实例相关的属性和方法,它会在`Vue.prototype`上定义实例会使用到的属性或者方法,这一节我们主要任务是弄清楚`stateMixin`的主要流程。在`src/core/instance/state.js`代码中,它精简后如下所示: 3 | ```js 4 | import { set, del } from '../observer/index' 5 | export function stateMixin (Vue) { 6 | // 定义$data, $props 7 | const dataDef = {} 8 | dataDef.get = function () { return this._data } 9 | const propsDef = {} 10 | propsDef.get = function () { return this._props } 11 | Object.defineProperty(Vue.prototype, '$data', dataDef) 12 | Object.defineProperty(Vue.prototype, '$props', propsDef) 13 | 14 | // 定义$set, $delete, $watch 15 | Vue.prototype.$set = set 16 | Vue.prototype.$delete = del 17 | Vue.prototype.$watch = function() {} 18 | } 19 | ``` 20 | 我们可以从上面代码中发现,`stateMixin()`方法中在`Vue.prototype`上定义的几个属性或者方法,全部都是和响应式相关的,我们来简要分析一下以上代码: 21 | * `$data和$props`:根据以上代码,我们发现`$data`和`$props`分别是`_data`和`_props`的访问代理,从命名中我们可以推测,以下划线开头的变量,我们一般认为是私有变量,然后通过`$data`和`$props`来提供一个对外的访问接口,虽然可以通过属性的`get()`方法去取,但对于这两个私有变量来说是并不能随意`set`,对于`data`来说不能替换根实例,而对于`props`来说它是只读的。因此在原版源码中,还劫持了`set()`方法,当设置`$data`或者`$props`时会报错: 22 | ```js 23 | if (process.env.NODE_ENV !== 'production') { 24 | dataDef.set = function () { 25 | warn( 26 | 'Avoid replacing instance root $data. ' + 27 | 'Use nested data properties instead.', 28 | this 29 | ) 30 | } 31 | propsDef.set = function () { 32 | warn(`$props is readonly.`, this) 33 | } 34 | } 35 | ``` 36 | * `$set`和`$delete`:`set`和`delete`这两个方法被定义在跟`instance`目录平级的`observer`目录下,在`stateMixin()`中,它们分别赋值给了`$set`和`$delete`方法,而在`initGlobalAPI`中,也同样使用到了这两个方法,只不过一个是全局方法,一个是实例方法。 37 | 38 | * `$watch`:在`stateMixin()`方法中,详细实现了`$watch()`方法,此方法实现的核心是通过一个`watcher`实例来监听。当取消监听时,同样是使用`watcher`实例相关的方法,关于`watcher`我们会在后续响应式章节详细介绍。 39 | ```js 40 | Vue.prototype.$watch = function ( 41 | expOrFn: string | Function, 42 | cb: any, 43 | options?: Object 44 | ): Function { 45 | const vm: Component = this 46 | if (isPlainObject(cb)) { 47 | return createWatcher(vm, expOrFn, cb, options) 48 | } 49 | options = options || {} 50 | options.user = true 51 | const watcher = new Watcher(vm, expOrFn, cb, options) 52 | if (options.immediate) { 53 | try { 54 | cb.call(vm, watcher.value) 55 | } catch (error) { 56 | handleError(error, vm, `callback for immediate watcher "${watcher.expression}"`) 57 | } 58 | } 59 | return function () { 60 | watcher.teardownunwatchFn() 61 | } 62 | } 63 | ``` 64 | 在以上代码分析完毕后,我们可以得到`stateMixin`如下流程图: 65 |
66 | 67 |
-------------------------------------------------------------------------------- /docs/vueAnalysis/expand/README.md: -------------------------------------------------------------------------------- 1 | # 扩展 2 | 在前面的几个章节中,我们介绍了响应式原理、虚拟DOM、组件化以及编译原理等相关知识,这几章里面的内容几乎涵盖了`Vue`大部分核心知识。但依然有一些知识,我们在前面几个章节中没有提到的:包括指令、过滤器、内置组件,事件处理,`v-model`以及插槽等。 3 | 4 | 在扩展这个大章节中,我们将对这些概念一一进行详细的解读,以便更好的理解`Vue`原理。 -------------------------------------------------------------------------------- /docs/vueAnalysis/expand/plugin.md: -------------------------------------------------------------------------------- 1 | # Vue.use插件机制 2 | 3 | 在使用`Vue`开发应用程序的时候,我们经常使用第三方插件库来方便我们开发,例如:`Vue-Router`、`Vuex`和`element-ui`等等。 4 | 5 | ```js 6 | // main.js 7 | import Vue from 'vue' 8 | import Router from 'vue-router' 9 | import Vuex from 'vuex' 10 | import ElementUI from 'element-ui' 11 | 12 | Vue.use(Router) 13 | Vue.use(Vuex) 14 | Vue.use(ElementUI) 15 | 16 | new Vue({}) 17 | ``` 18 | 19 | 在`new Vue`之前,我们使用`Vue.use`方法来注册这些插件。其中,`Vue.use`作为一个全局方法,它是在`initGlobalAPI`方法内部通过调用`initUse`来注册这个全局方法的。 20 | ```js 21 | import { initUse } from './use' 22 | export function initGlobalAPI (Vue: GlobalAPI) { 23 | // ...省略代码 24 | initUse(Vue) 25 | // ...省略代码 26 | } 27 | ``` 28 | `initUse`方法的代码并不复杂,如下: 29 | ```js 30 | import { toArray } from '../util/index' 31 | export function initUse (Vue: GlobalAPI) { 32 | Vue.use = function (plugin: Function | Object) { 33 | // 1.检测是否已经注册了插件 34 | const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) 35 | if (installedPlugins.indexOf(plugin) > -1) { 36 | return this 37 | } 38 | 39 | // 2.处理参数 40 | const args = toArray(arguments, 1) 41 | args.unshift(this) 42 | 43 | // 3.调用install方法 44 | if (typeof plugin.install === 'function') { 45 | plugin.install.apply(plugin, args) 46 | } else if (typeof plugin === 'function') { 47 | plugin.apply(null, args) 48 | } 49 | installedPlugins.push(plugin) 50 | return this 51 | } 52 | } 53 | ``` 54 | 我们可以从以上代码中看出,当调用`Vue.use`时,它只要做三件事情:**检查插件是否重复注册**、**处理插件参数**和**调用插件的install方法**。 55 | 56 | 代码分析: 57 | * **检查插件是否重复注册**:首先通过判断大`Vue`上的`_installedPlugins`属性是否已经存在当前插件,如果已经存在则直接返回;如果不存在才会执行后面的逻辑,假如我们有如下案例: 58 | ```js 59 | import Vue from 'vue' 60 | import Router from 'vue-router' 61 | 62 | Vue.use(Router) 63 | Vue.use(Router) 64 | ``` 65 | 多次调用`Vue.use()`方法注册同一个组件,只有第一个生效。 66 | 67 | * **处理插件参数**:有些插件在注册的时候,可能需要我们额外的传递一些参数,例如`element-ui`。 68 | ```js 69 | import Vue from 'vue' 70 | import ElementUI from 'element-ui' 71 | Vue.use(ElementUI, { 72 | size: 'small', 73 | zIndex: 3000 74 | }) 75 | ``` 76 | 按照上面的例子,`Vue.use()`方法的`arguments`数组的第一项为我们传递的插件,剩下的参数才是我们需要的,因此通过`toArray`方法把`arguments`类数组转成一个真正的数组。注意,此时`args`变量不包含插件这个元素,随后再把当前`this`也就是大`Vue`也传递进数组中。 77 | ```js 78 | // 演示使用,实际为大Vue的构造函数 79 | const args = ['Vue', { size: 'small', zIndex: 3000}] 80 | ``` 81 | 82 | * **调用插件的install方法**:从官网[插件](https://cn.vuejs.org/v2/guide/plugins.html)我们知道,如果我们在开发一个`Vue`插件,必须为这个插件提供一个`install`方法,当调用`Vue.use()`方法的时候会自动调用此插件的`install`方法,并把第二步处理好的参数传递进去。假如,我们有如下插件代码: 83 | ```js 84 | // plugins.js 85 | const plugin = { 86 | install (Vue, options) { 87 | console.log(options) // {msg: 'test use plugin'} 88 | 89 | // 其它逻辑 90 | } 91 | } 92 | 93 | 94 | // main.js 95 | import Vue from 'vue' 96 | import MyPlugin from './plugins.js' 97 | Vue.use(MyPlugin, { msg: 'test use plugin' }) 98 | ``` 99 | 在`install`方法中,我们成功获取到了大`Vue`构造函数以及我们传递的参数,在随后我们就可以做一些其它事情,例如:注册公共组件、注册指令、添加公共方法以及全局`Mixin`混入等等。 100 | -------------------------------------------------------------------------------- /docs/vueAnalysis/expand/transition-group.md: -------------------------------------------------------------------------------- 1 | # Transition-Group 2 | 3 | Transition-Group介绍 -------------------------------------------------------------------------------- /docs/vueAnalysis/expand/transition.md: -------------------------------------------------------------------------------- 1 | # Transition 2 | 3 | Transition介绍 -------------------------------------------------------------------------------- /docs/vueAnalysis/introduction/README.md: -------------------------------------------------------------------------------- 1 | # 介绍和参考 2 | 本篇`Vue2.6.11`源码分析文章由观看[Vue.js源码全方位深入解析](https://coding.imooc.com/class/228.html)视频,阅读[深入浅出Vue.js](https://www.ituring.com.cn/book/2675)书籍以及参考其他`Vue`源码分析博客而来,阅读视频和书籍请支持正版。 3 | 4 | ## Vue发展简史 5 | * 2013年7月,`Vue.js`在`Github`上第一次提交,此时名字叫做`Element`,后来被改名为`Seed.js`,到现在的`Vue.js`。 6 | * 2013年12月,`Github`发布`0.6`版本,并正式更名为`Vue.js`。 7 | * 2014年2月,在`Hacker News`网站上时候首次公开。 8 | * 2015年10月,`Vue.js`发布`1.0.0`版本。 9 | * 2016年10月,`Vue.js`发布`2.0`版本。 10 | * 2020年9月18日,`Vue.js`发布`3.0`版本。 11 | 12 | ## Vue版本变化 13 | `Vue2.0`版本和`Vue1.0`版本之间虽然内部变化非常大,整个渲染层都重写了,但`API`层面的变化却很小,对开发者来说非常友好,另外`Vue2.0`版本还引入了很多特性: 14 | * `Virtual DOM`虚拟DOM。 15 | * 支持`JSX`语法。 16 | * 支持`TypeScript`。 17 | * 支持服务端渲染`ssr`。 18 | * 提供跨平台能力`weex`。 19 | 20 | **正确理解虚拟DOM**:`Vue`中的虚拟DOM借鉴了开源库[snabbdom](https://github.com/snabbdom/snabbdom)的实现,并根据自身特色添加了许多特性。引入虚拟DOM的一个很重要的好处是:绝大部分情况下,组件渲染变得更快了,而少部分情况下反而变慢了。引入虚拟DOM这项技术通常都是在解决一些问题,然而解决一个问题的同时也可能会引入其它问题,这种情况更多的是如何做权衡、如何做取舍。因此,一味的强调虚拟DOM在任何时候都能提高性能这种说法需要正确对待和理解。 21 | 22 | **核心思想**:`Vue`两大核心思想是**数据驱动**和**组件化**,因此我们在介绍完源码目录设计和整体流程后,会先介绍这两方面。 -------------------------------------------------------------------------------- /docs/vueAnalysis/reactive/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 在上一章节,我们分析过`initState()`方法的整体流程,知道它会处理`props`、`methods`和`data`等等相关的内容: 3 | ```js 4 | export function initState (vm: Component) { 5 | vm._watchers = [] 6 | const opts = vm.$options 7 | if (opts.props) initProps(vm, opts.props) 8 | if (opts.methods) initMethods(vm, opts.methods) 9 | if (opts.data) { 10 | initData(vm) 11 | } else { 12 | observe(vm._data = {}, true /* asRootData */) 13 | } 14 | if (opts.computed) initComputed(vm, opts.computed) 15 | if (opts.watch && opts.watch !== nativeWatch) { 16 | initWatch(vm, opts.watch) 17 | } 18 | } 19 | ``` 20 | 那么我们的深入响应式原理介绍会以`initState()`方法开始,逐步分析`Vue`中响应式的原理,下面这张图可以很好的展示响应式的原理。 21 | 22 |
23 | 响应式原理图 24 |
-------------------------------------------------------------------------------- /docs/vueAnalysis/reactive/methods.md: -------------------------------------------------------------------------------- 1 | # methods处理 2 | 在分析完`props`相关逻辑后,我们接下来分析与`methods`相关的逻辑,这部分相比于`props`要简单得多。 3 | ```js 4 | export function initState (vm: Component) { 5 | // 省略代码 6 | const opts = vm.$options 7 | if (opts.methods) initMethods(vm, opts.methods) 8 | } 9 | ``` 10 | 在`initState()`方法中,调用了`initMethods()`并传入了当前实例`vm`和我们撰写的`methods`。接下来,我们看一下`initMethods`方法具体的实现: 11 | ```js 12 | function initMethods (vm: Component, methods: Object) { 13 | const props = vm.$options.props 14 | for (const key in methods) { 15 | if (process.env.NODE_ENV !== 'production') { 16 | if (typeof methods[key] !== 'function') { 17 | warn( 18 | `Method "${key}" has type "${typeof methods[key]}" in the component definition. ` + 19 | `Did you reference the function correctly?`, 20 | vm 21 | ) 22 | } 23 | if (props && hasOwn(props, key)) { 24 | warn( 25 | `Method "${key}" has already been defined as a prop.`, 26 | vm 27 | ) 28 | } 29 | if ((key in vm) && isReserved(key)) { 30 | warn( 31 | `Method "${key}" conflicts with an existing Vue instance method. ` + 32 | `Avoid defining component methods that start with _ or $.` 33 | ) 34 | } 35 | } 36 | vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm) 37 | } 38 | } 39 | ``` 40 | 在以上代码中可以看到,`initMethods()`方法实现中最重要的一段代码就是: 41 | ```js 42 | // 空函数 43 | function noop () {} 44 | 45 | vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm) 46 | ``` 47 | 它首先判断了我们定义的`methods`是不是`function`类型,如果不是则赋值为一个`noop`空函数,如果是则把这个方法进行`bind`绑定,其中传入的`vm`为当前实例。这样做的目的是为了把`methods`方法中的`this`指向当前实例,使得我们能在`methods`方法中通过`this.xxx`的形式,很方便的访问到`props`、`data`以及`computed`等与实例相关的属性或方法。 48 | 49 | 在开发环境下,它还做了如下几种判断: 50 | * 必须为`function`类型。 51 | ```js 52 | // 抛出错误:Method sayHello has type null in the component definition. 53 | // Did you reference the function correctly? 54 | export default { 55 | methods: { 56 | sayHello: null 57 | } 58 | } 59 | ``` 60 | * 命名不能和`props`冲突。 61 | ```js 62 | // 抛出错误:Method name has already been defined as a prop. 63 | export default { 64 | props: ['name'] 65 | methods: { 66 | name () { 67 | console.log('name') 68 | } 69 | } 70 | } 71 | ``` 72 | * 命名不能和已有的实例方法冲突。 73 | ```js 74 | // 抛出错误:Method $set conflicts with an existing Vue instance method. 75 | // Avoid defining component methods that start with _ or $. 76 | export default { 77 | methods: { 78 | $set () { 79 | console.log('$set') 80 | } 81 | } 82 | } 83 | ``` 84 | 85 | 在分析完以上`initMethods`流程后,我们能得到如下流程图: 86 |
87 | 88 |
-------------------------------------------------------------------------------- /docs/vueAnalysis/reactive/prepare.md: -------------------------------------------------------------------------------- 1 | # 前置核心概念 2 | 3 | ## Object.defineProperty介绍 4 | 也许你已经从很多地方了解到,`Vue.js`利用了`Object.defineProperty(obj, key, descriptor)`方法来实现响应式,其中`Object.defineProperty()`方法的参数介绍如下: 5 | * `obj`:要定义其属性的对象。 6 | * `key`:要定义或修改属性的名称。 7 | * `descriptor`:要定义或修改属性的描述符。 8 | 9 | 其中`descriptor`有很多可选的键值, 然而对`Vue`响应式来说最重要的是`get`和`set`方法,它们分别会在获取属性值的时候触发`getter`,设置属性值的时候触发`setter`。在介绍原理之前,我们使用`Object.defineProperty()`来实现一个简单的响应式例子: 10 | ```js 11 | function defineReactive (obj, key, val) { 12 | Object.defineProperty(obj, key, { 13 | enumerable: true, 14 | configurable: true, 15 | get: function reactiveGetter () { 16 | console.log('get msg') 17 | return val 18 | }, 19 | set: function reactiveSetter (newVal) { 20 | console.log('set msg') 21 | val = newVal 22 | } 23 | }) 24 | } 25 | const vm = { 26 | msg: 'hello, Vue.js' 27 | } 28 | let msg = '' 29 | defineReactive(vm, 'msg', vm.msg) 30 | msg = vm.msg // get msg 31 | vm.msg = 'Hello, Msg' // set msg 32 | msg = vm.msg // get msg 33 | ``` 34 | 为了在别的地方方便的使用`Object.defineProperty()`方法,因此我们把其封装成一个`defineReactive`函数。 35 | 36 | ## proxy代理 37 | 在开发过程中,我们经常会使用`this.xxx`的形式直接访问`props`或者`data`中的值,这是因为`Vue`为`props`和`data`默认做了`proxy`代理。关于什么是`proxy`代理,请先看一个简单的例子: 38 | ```js 39 | this._data = { 40 | name: 'AAA', 41 | age: 23 42 | } 43 | // 代理前 44 | console.log(this._data.name) // AAA 45 | proxy(vm, '_data', 'name') 46 | // 代理后 47 | console.log(this.name) // AAA 48 | ``` 49 | 接下来我们详细介绍`proxy()`方法是如何实现的,在`instance/state.js`文件中定义了`proxy`方法,它的代码也很简单: 50 | ```js 51 | const sharedPropertyDefinition = { 52 | enumerable: true, 53 | configurable: true, 54 | get: noop, 55 | set: noop 56 | } 57 | export function proxy (target: Object, sourceKey: string, key: string) { 58 | sharedPropertyDefinition.get = function proxyGetter () { 59 | return this[sourceKey][key] 60 | } 61 | sharedPropertyDefinition.set = function proxySetter (val) { 62 | this[sourceKey][key] = val 63 | } 64 | Object.defineProperty(target, key, sharedPropertyDefinition) 65 | } 66 | ``` 67 | 我们可以从上面的代码中发现,`proxy`方法主要是做了属性的`get`和`set`方法劫持。 68 | ```js 69 | const name = this.name 70 | this.name = 'BBB' 71 | // 等价于 72 | const name = this._data.name 73 | this._data.name = 'BBB' 74 | ``` 75 | ## $options属性 76 | 在之前的介绍中,我们知道当初始化`Vue`实例的时候,传递的`options`会根据不同的情况进行配置合并,关于详细的`options`合并策略我们会在之后的章节详细介绍,现阶段我们只需要知道`$options`可以拿到合并后的所有属性,例如`props`、`methods`以及`data`等等。 77 | 78 | 假设我们定义了如下实例: 79 | ```js 80 | const vm = new Vue({ 81 | el: '#app', 82 | props: { 83 | msg: '' 84 | }, 85 | data () { 86 | return { 87 | firstName: 'AAA', 88 | lastName: 'BBB', 89 | age: 23 90 | } 91 | }, 92 | methods: { 93 | sayHello () { 94 | console.log('Hello, Vue.js') 95 | } 96 | }, 97 | computed: { 98 | fullName () { 99 | return this.firstName + this.lastName 100 | } 101 | } 102 | }) 103 | ``` 104 | 那么我们在之后可以通过下面的方式来取这些属性。 105 | ```js 106 | const opts = this.$options 107 | const props = opts.props 108 | const methods = opts.methods 109 | const data = opts.data 110 | const computed = opts.computed 111 | const watch = opts.watch 112 | // ...等等 113 | ``` -------------------------------------------------------------------------------- /docs/vueAnalysis/reactive/problem.md: -------------------------------------------------------------------------------- 1 | # 变化侦测注意事项 2 | 虽然`Object.defineProperty()`方法很好用,但也会存在一些例外情况,这些例外情况的变动不能触发`setter`。这种情况,我们分为对象和数组两类来分析。 3 | 4 | ## 对象 5 | 假设我们有如下例子: 6 | ```js 7 | export default { 8 | data () { 9 | return { 10 | obj: { 11 | a: 'a' 12 | } 13 | } 14 | }, 15 | created () { 16 | // 1.新增属性b,属性b不是响应式的,不会触发obj的setter 17 | this.obj.b = 'b' 18 | // 2.delete删除已有属性,无法触发obj的setter 19 | delete this.obj.a 20 | } 21 | } 22 | ``` 23 | 从以上例子我们可以看到: 24 | * 当为一个响应式对象新增一个属性的时候,新增的属性不是响应式的,后续对于这个新增属性的任何修改,都无法触发其`setter`。为了解决这种问题,`Vue.js`提供了一个全局的`Vue.set()`方法和实例`vm.$set()`方法,它们实际上都是同一个`set`方法,我们会在后续的章节中介绍与响应式相关的全局`API`的实现。 25 | * 当一个响应式对象删除一个已有属性的时候,不会触发`setter`。为了解决这个问题,`Vue.js`提供了一个全局的`vue.delete()`方法和实例`vm.$delete()`方法,它们实际上都是同一个`del`方法,我们会在后续的章节中介绍与响应式相关的全局`API`的实现。 26 | 27 | ## 数组 28 | 假设我们有如下例子: 29 | ```js 30 | export default { 31 | data () { 32 | return { 33 | arr: [1, 2, 3] 34 | } 35 | }, 36 | created () { 37 | // 1.通过索引进行修改,无法捕获到数组的变动。 38 | this.arr[0] = 11 39 | // 2.通过修改数组长度,无法捕获到数组的变动。 40 | this.arr.length = 0 41 | } 42 | } 43 | ``` 44 | 从以上例子我们可以看到: 45 | * 通过索引直接修改数组,无法捕捉到数组的变动。 46 | * 通过修改数组长度,无法捕获到数组的变动。 47 | 48 | 对于第一种情况,我们可以使用前面提到过的`Vue.set`或者`vm.$set`来解决,对于第二种方法,我们可以使用数组的`splice()`方法解决。 49 | 50 | 在最新版`Vue3.0`中,使用到了`Proxy`来代替`Object.defineProperty()`实现响应式,使用`Proxy`后以上问题全部可以解决,然而`Proxy`属于`ES6`的内容,因此对于浏览器兼容性方面有一定的要求。 -------------------------------------------------------------------------------- /docs/vueAnalysis/router/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | Vue-Router介绍 -------------------------------------------------------------------------------- /docs/vueAnalysis/router/change.md: -------------------------------------------------------------------------------- 1 | # 路由切换 2 | 路由切换 -------------------------------------------------------------------------------- /docs/vueAnalysis/router/components.md: -------------------------------------------------------------------------------- 1 | # 内置组件 2 | 3 | ## RouterView 4 | 5 | ## RouterLink 6 | -------------------------------------------------------------------------------- /docs/vueAnalysis/router/hooks.md: -------------------------------------------------------------------------------- 1 | # 路由hooks钩子函数 2 | 路由hooks钩子函数 -------------------------------------------------------------------------------- /docs/vueAnalysis/router/install.md: -------------------------------------------------------------------------------- 1 | # 路由安装 2 | 3 | 路由安装 -------------------------------------------------------------------------------- /docs/vueAnalysis/router/matcher.md: -------------------------------------------------------------------------------- 1 | # matcher介绍 2 | matcher介绍 3 | -------------------------------------------------------------------------------- /docs/vueAnalysis/vuex/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | 在`Vuex`官网中它有这样一段话:**Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。** 4 | 5 | 借用一张`Vuex`官网中一张关于其状态管理的流程图: 6 | 7 |
8 | Vuex数据状态管理流程图 9 |
10 | 11 | 12 | 在分析`Vuex`源码章节,我们会按照`Vuex`的安装、`Vuex`的初始化、`Vuex`提供的辅助`API`以及`Store`实例`API`这几个模块来进行说明,其中最后几个模块是重点。 13 | 14 | **Vuex初始化**: 15 | 1. `State`初始化。 16 | 2. `Mutations`初始化。 17 | 3. `Actions`初始化。 18 | 4. `Getters`初始化和响应式。 19 | 5. `Modules`初始化。 20 | 21 | 22 | **Vuex**辅助`API`设计: 23 | 1. `createNamespacedHelpers`设计原理。 24 | 2. `mapState`设计原理。 25 | 3. `mapMutations`设计思想。 26 | 4. `mapActions`设计思想。 27 | 28 | **Store**实例`API`设计: 29 | 1. `commit`设计思想。 30 | 1. `dispatch`设计思想。 31 | 1. `subscribe`设计思想。 32 | 1. `subscribeAction`设计思想。 33 | 1. `registerModule`设计思想。 34 | 1. `unregisterModule`设计思想。 -------------------------------------------------------------------------------- /docs/vueAnalysis/vuex/install.md: -------------------------------------------------------------------------------- 1 | # Vuex安装 2 | 3 | 由于`Vuex`也属于`Vue`的插件,因此我们在使用`Vuex`的时候,需要使用`Vue.use()`方法进行注册。 4 | 5 | 在`store.js`中其代码如下: 6 | ```js 7 | // store.js 8 | import Vue from 'vue' 9 | import Vuex from 'vuex' 10 | Vue.use(Vuex) 11 | ``` 12 | 根据`Vue`插件机制原理,插件需要提供一个`install`方法,在`Vuex`源码中,`install`的代码路径为`src/store.js`,其实现代码如下: 13 | ```js 14 | import applyMixin from './mixin' 15 | 16 | let Vue 17 | export function install (_Vue) { 18 | if (Vue && _Vue === Vue) { 19 | if (__DEV__) { 20 | console.error( 21 | '[vuex] already installed. Vue.use(Vuex) should be called only once.' 22 | ) 23 | } 24 | return 25 | } 26 | Vue = _Vue 27 | applyMixin(Vue) 28 | } 29 | ``` 30 | 31 | 在这个方法中,它所做的事情很简单,第一个就是把我们传递的`Vue`实例缓存起来,以方便后续实例化`Store`的时候使用。第二件事情就是调用`applyMixin`方法,此方法代码路径为`src/mixin.js`。 32 | ```js 33 | // mixin.js文件 34 | export default function (Vue) { 35 | const version = Number(Vue.version.split('.')[0]) 36 | if (version >= 2) { 37 | Vue.mixin({ beforeCreate: vuexInit }) 38 | } else { 39 | // 省略Vue1.0+版本逻辑 40 | } 41 | } 42 | ``` 43 | 因为我们`Vue`源码分析是基于`Vue2.6.11`,因此我们省略关于`else`分支的逻辑。 44 | 45 | 当`Vue`的版本高于`2.0`时,它会调用`Vue.mixin()`方法全局混入一个`beforeCreate`生命周期,当`beforeCreate`生命周期执行的时候,会调用`vuexInit`,其代码如下: 46 | ```js 47 | // vuexInit中的this代表当前Vue实例 48 | function vuexInit () { 49 | const options = this.$options 50 | // store injection 51 | if (options.store) { 52 | this.$store = typeof options.store === 'function' 53 | ? options.store() 54 | : options.store 55 | } else if (options.parent && options.parent.$store) { 56 | this.$store = options.parent.$store 57 | } 58 | } 59 | ``` 60 | 61 | 在入口`main.js`文件中,我们有这样一段代码: 62 | ```js 63 | // main.js 64 | import store from './store' 65 | 66 | new Vue({ 67 | el: '#app', 68 | store 69 | }) 70 | ``` 71 | 我们在`vuexInit`方法中拿到的`options.store`就是我们传入的`store`,我们再来把目光跳转到`store.js`文件中,其代码如下: 72 | ```js 73 | // store.js 74 | import Vuex from 'vuex' 75 | 76 | export default new Vuex.Store({}) 77 | ``` 78 | 原来我们在根实例中传递的是一个`Store`实例,这样我们就明白了`vuexInit`方法的主要作用了:**给每一个Vue实例都赋值一个$store属性。** 79 | 80 | 这样,我们在组件中就不用去手动引入`store`了,而是可以直接使用`$store`,例如: 81 | ```html 82 | 85 | ``` -------------------------------------------------------------------------------- /docs/vueNextAnalysis/catalog/README.md: -------------------------------------------------------------------------------- 1 | # 源码目录 2 | 因为`Vue3`采用`Monorepo`进行项目代码管理,所以我们着重关注`packages`目录,其中比较关键的几个`package`如下: 3 | ```sh 4 | |-- packages 5 | | |-- compiler-core 6 | | |-- compiler-dom 7 | | |-- compiler-sfc 8 | | |-- compiler-ssr 9 | | |-- reactivity 10 | | |-- runtime-core 11 | | |-- runtime-dom 12 | | |-- vue 13 | ``` 14 | `package`功能介绍: 15 | * `compiler-core`:跟环境无关的公共编译模块。 16 | * `compiler-dom`:针对`web`浏览器端编译模块。 17 | * `compiler-sfc`:`.vue`单文件解析模块,我们比较熟悉的`vue-loader`打包插件会使用到它。 18 | * `compiler-ssr`: 服务端渲染相关的编译模块。 19 | * `reactivity`:响应式模块,例如`ref`和`reactive`都定义在此模块中。 20 | * `runtime-core`:跟环境无关的公共运行时模块。 21 | * `runtime-dom`:针对`web`浏览器端的运行时模块。 22 | * `vue`: 集合几乎所有模块为一身的完整包。 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/component/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 组件化介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/component/createApp.md: -------------------------------------------------------------------------------- 1 | # createApp 2 | createApp介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/component/lifecycle.md: -------------------------------------------------------------------------------- 1 | # 组件生命周期 2 | 组件生命周期介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/component/mount.md: -------------------------------------------------------------------------------- 1 | # $mount 2 | $mount方法介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/component/register.md: -------------------------------------------------------------------------------- 1 | # 组件注册 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/component/render.md: -------------------------------------------------------------------------------- 1 | # render 2 | render介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/component/setup.md: -------------------------------------------------------------------------------- 1 | # setup 2 | setup介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/introduction/README.md: -------------------------------------------------------------------------------- 1 | # 参考和历史 2 | 3 | ## 参考 4 | 本篇`Vue3.4.33`源码分析文章由学习[Vue.js 3.0 核心源码解析](https://kaiwu.lagou.com/course/courseInfo.htm?courseId=326&sid=20-h5Url-0#/sale)课程以及参考其它学习视频、博客而来,阅读视频、书籍请支持正版。 5 | 6 | ## 发展历史 7 | * 2013年7月,`Vue.js`在`Github`上第一次提交,此时名字叫做`Element`,后来被改名为`Seed.js`,到现在的`Vue.js`。 8 | * 2013年12月,`Github`发布`0.6`版本,并正式更名为`Vue.js`。 9 | * 2014年2月,在`Hacker News`网站上时候首次公开。 10 | * 2015年10月,`Vue.js`发布`1.0.0`版本。 11 | * 2016年10月,`Vue.js`发布`2.0`版本。 12 | * 2020年9月18日,`Vue.js`发布`3.0`版本。 13 | -------------------------------------------------------------------------------- /docs/vueNextAnalysis/reactivity/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 在`Vue3`中,[@vue/reactivity](https://www.npmjs.com/package/@vue/reactivity)作为独立的`package`子包,可以脱离`Vue`在其他工具和库中进行使用,你甚至可以在`React`中使用。 3 | 4 | 之所以`Vue3`能够这样,而`Vue2`不行,这是因为`Vue3`采用`Monorepo`进行项目代码管理,它让各个模块之间,能够相互独立进行发包。 5 | 6 | 如果你对`Monorepo`还不是特别了解的话,你可以点击[Monorepo + Rollup](/vueNextAnalysis/monorepo/)这个章节去了解更多内容。 7 | 8 | 在这一章节,我们重点分析`reactivity`模块中各个`API`是如何实现的,包括:`ref`、`reactive`、`computed`以及`readonly`等等。 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/reactivity/base.md: -------------------------------------------------------------------------------- 1 | # 基础概念 2 | 3 | ## Proxy 4 | Proxy介绍 5 | 6 | ## WeakSet 7 | WeakSet介绍 8 | 9 | ## WeakMap 10 | WeakMap介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/reactivity/computed.md: -------------------------------------------------------------------------------- 1 | # computed 2 | computed介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/reactivity/reactive.md: -------------------------------------------------------------------------------- 1 | # reactive 2 | reactive介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/reactivity/readonly.md: -------------------------------------------------------------------------------- 1 | # readonly 2 | readonly介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/reactivity/ref.md: -------------------------------------------------------------------------------- 1 | # ref 2 | 3 | ## ref和shallowRef 4 | 5 | ### 用法 6 | 7 | ### 实现方式 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/reactivity/track.md: -------------------------------------------------------------------------------- 1 | # Track依赖收集 2 | Track依赖收集介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/reactivity/trigger.md: -------------------------------------------------------------------------------- 1 | # Trigger派发更新 2 | Trigger派发更新介绍 -------------------------------------------------------------------------------- /docs/vueNextAnalysis/reactivity/watch.md: -------------------------------------------------------------------------------- 1 | # Watch 2 | Watch介绍 -------------------------------------------------------------------------------- /docs/webpack/tapable/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: heading 3 | --- 4 | 5 | # Tapable事件流插件 6 | 7 | Tapable事件流插件 -------------------------------------------------------------------------------- /docs/webpack/webpack/README.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 3 | ## 版本和参考说明 4 | ::: tip 说明 5 | 本篇博客由学习[从基础到实战手把手带你掌握新版Webpack4.0](https://coding.imooc.com/class/316.html)视频整理而来,观看视频请支持正版。 6 | ::: 7 | ::: warning 注意 8 | 本篇博客 Webpack 版本是`4.0+`,请确保你安装了`Node.js`最新版本。 9 | ::: 10 | 11 | ## Webpack概念 12 | Webpack 的核心概念是一个 **模块打包工具** ,它的主要目标是将`js`文件打包在一起,打包后的文件用于在目标环境中使用,但它也能胜任 **转换`transform`** 、**打包`bundle`** 或 **包裹`package`** 任何其他资源。 -------------------------------------------------------------------------------- /docs/webpack/webpack/install.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 3 | ## 全局安装 4 | ::: warning 注意 5 | 如果你只是想做一个 Webpack 的 Demo 案例,那么全局安装方法可能会比较适合你。如果你是在实际生产开发中使用,那么推荐你使用本地安装方法。 6 | ::: 7 | ### 全局安装命令 8 | :::tip 参数说明 9 | `webpack4.0+`的版本,必须安装`webpack-cli`,`-g`命令代表全局安装的意思 10 | ::: 11 | ``` sh 12 | $ npm install webpack webpack-cli -g 13 | ``` 14 | 15 | ## 卸载 16 | ::: tip 参数说明 17 | 通过`npm install`安装的模块,对应的可通过`npm uninstall`进行卸载 18 | ::: 19 | ```sh 20 | $ npm uninstall webpack webpack-cli -g 21 | ``` 22 | 23 | ## 本地安装(推荐) 24 | ::: tip 参数说明 25 | 本地安装的`Webpack`意思是,只在你当前项目下有效,而通过全局安装的`Webpack`,如果两个项目的`Webpack`主版本不一致,则可能会造成其中一个项目无法正常打包。本地安装方式也是实际开发中推荐的一种`Webpack`安装方式。 26 | ::: 27 | ```sh 28 | $ npm install webpack webpack-cli -D 29 | # 等价于 30 | $ npm install webpack webpack-cli --save-dev 31 | ``` 32 | 33 | ## 版本号安装 34 | ::: tip 参数说明 35 | 如果你对`Webpack`的具体版本有严格要求,那么可以先去Github的`Webpack`仓库查看历史版本记录或者使用`npm view webpack versions`查看`Webpack`的`npm`包历史版本记录 36 | ::: 37 | ```sh 38 | # 查看webpack的历史版本记录 39 | $ npm view webpack versions 40 | 41 | # 按版本号安装 42 | $ npm install webpack@4.25.0 -D 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/webpack/webpack/plugin.md: -------------------------------------------------------------------------------- 1 | 2 | # 编写自己的Plugin 3 | 与`loader`一样,我们在使用 Webpack 的过程中,也经常使用`plugin`,那么我们学习如何编写自己的`plugin`是十分有必要的。 4 | ::: tip 场景 5 | 编写我们自己的`plugin`的场景是在打包后的`dist`目录下生成一个`copyright.txt`文件 6 | ::: 7 | ## plugin基础 8 | `plugin`基础讲述了怎么编写自己的`plugin`以及如何使用,与创建自己的`loader`相似,我们需要创建如下的项目目录结构: 9 | ```js 10 | |-- plugins 11 | | -- copyWebpackPlugin.js 12 | |-- src 13 | | -- index.js 14 | |-- webpack.config.js 15 | |-- package.json 16 | ``` 17 | `copyWebpackPlugins.js`中的代码:使用`npm run build`进行打包时,我们会看到控制台会输出`hello, my plugin`这段话。 18 | ::: tip 说明 19 | `plugin`与`loader`不同,`plugin`需要我们提供的是一个类,这也就解释了我们必须在使用插件时,为什么要进行`new`操作了。 20 | ::: 21 | ```js 22 | class copyWebpackPlugin { 23 | constructor() { 24 | console.log('hello, my plugin'); 25 | } 26 | apply(compiler) { 27 | 28 | } 29 | } 30 | module.exports = copyWebpackPlugin; 31 | ``` 32 | 33 | `webpack.config.js`中的代码: 34 | ```js 35 | const path = require('path'); 36 | // 引用自己的插件 37 | const copyWebpackPlugin = require('./plugins/copyWebpackPlugin.js'); 38 | module.exports = { 39 | mode: 'development', 40 | entry: './src/index.js', 41 | output: { 42 | filename: '[name].js', 43 | path: path.resolve(__dirname, 'dist') 44 | }, 45 | plugins: [ 46 | // new自己的插件 47 | new copyWebpackPlugin() 48 | ] 49 | } 50 | ``` 51 | 52 | ## 如何传递参数 53 | 在使用其他`plugin`插件时,我们经常需要传递一些参数进去,那么我们如何在自己的插件中传递参数呢?在哪里接受呢?
54 | 其实,插件传参跟其他插件传参是一样的,都是在构造函数中传递一个对象,插件传参如下所示: 55 | ```js {13} 56 | const path = require('path'); 57 | const copyWebpackPlugin = require('./plugins/copyWebpackPlugin.js'); 58 | module.exports = { 59 | mode: 'development', 60 | entry: './src/index.js', 61 | output: { 62 | filename: '[name].js', 63 | path: path.resolve(__dirname, 'dist') 64 | }, 65 | plugins: [ 66 | // 向我们的插件传递参数 67 | new copyWebpackPlugin({ 68 | name: 'why' 69 | }) 70 | ] 71 | } 72 | ``` 73 | 在`plugin`的构造函数中调用:使用`npm run build`进行打包,在控制台可以打印出我们传递的参数值`why` 74 | ```js {3} 75 | class copyWebpackPlugin { 76 | constructor(options) { 77 | console.log(options.name); 78 | } 79 | apply(compiler) { 80 | 81 | } 82 | } 83 | module.exports = copyWebpackPlugin; 84 | ``` 85 | 86 | ## 如何编写及使用自己的Plugin 87 | ::: tip 说明 88 | * `apply`函数是我们插件在调用时,需要执行的函数 89 | * `apply`的参数,指的是 Webpack 的实例 90 | * `compilation.assets`打包的文件信息 91 | ::: 92 | 我们现在有这样一个需求:使用自己的插件,在打包目录下生成一个`copyright.txt`版权文件,那么该如何编写这样的插件呢? 93 | 首先我们需要知道`plugin`的钩子函数,符合我们规则钩子函数叫:`emit`,它的用法如下: 94 | ```js 95 | class CopyWebpackPlugin { 96 | constructor() { 97 | } 98 | apply(compiler) { 99 | compiler.hooks.emit.tapAsync('CopyWebpackPlugin', (compilation, cb) => { 100 | var copyrightText = 'copyright by why'; 101 | compilation.assets['copyright.txt'] = { 102 | source: function() { 103 | return copyrightText 104 | }, 105 | size: function() { 106 | return copyrightText.length; 107 | } 108 | } 109 | cb(); 110 | }) 111 | } 112 | } 113 | module.exports = CopyWebpackPlugin; 114 | ``` 115 | 使用`npm run build`命名打包后,我们可以看到`dist`目录下,确实生成了我们的`copyright.txt`文件。 116 | ```js 117 | |-- dist 118 | | |-- copyright.txt 119 | | |-- main.js 120 | |-- plugins 121 | | |-- copyWebpackPlugin.js 122 | |-- src 123 | | |-- index.js 124 | |-- webpack.config.js 125 | |-- package.json 126 | ``` 127 | 我们打开`copyright.txt`文件,它的内容如下: 128 | ``` html 129 | copyright by why 130 | ``` -------------------------------------------------------------------------------- /donate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangtunan/blog/4cae81a7be7882437e8f42d6762dbb92aa7d76e8/donate.jpg -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "dev": "vuepress dev docs", 5 | "build": "vuepress build docs", 6 | "depoly": "depoly.sh" 7 | }, 8 | "keywords": [ 9 | "vue", 10 | "vue源码分析", 11 | "wangtunan", 12 | "汪图南的博客", 13 | "汪图南" 14 | ], 15 | "dependencies": { 16 | "vuepress": "^2.0.0-rc.21" 17 | }, 18 | "devDependencies": { 19 | "@vuepress/bundler-vite": "^2.0.0-rc.21", 20 | "@vuepress/plugin-baidu-analytics": "^2.0.0-rc.94", 21 | "@vuepress/plugin-comment": "^2.0.0-rc.94", 22 | "@vuepress/plugin-markdown-math": "^2.0.0-rc.94", 23 | "@vuepress/plugin-register-components": "^2.0.0-rc.94", 24 | "@vuepress/plugin-prismjs": "^2.0.0-rc.94", 25 | "@vuepress/theme-default": "^2.0.0-rc.94", 26 | "katex": "^0.16.22", 27 | "sass-embedded": "^1.86.3" 28 | } 29 | } --------------------------------------------------------------------------------