只会笑的提莫 - 前端框架
type: channel
link: http://www.gongpengji.com/index.php/category/前端框架
items: Vue全家桶之vue-router原理
items: Vue全家桶之vuex原理
items: SEO基座篇-next-react
items: SEO基座篇-nuxt-vue
items: Redux
items: React-router
items: React-Hook
items: React-4
items: React-3
items: React-2

Vue全家桶之vue-router原理
type: item
date: 2022-03-22T16:44:00+08:00
description: 一、前提思考我们如何给vue写插件，router其实也是一个插件，一个全局插件。相信大家对于vue.use(xxx)很眼熟了，这个时候让我们来看vue-router是如何使用的吧，最后自己写一个router替换掉vue-router。vue-router源码地址：https://github.com/vuejs/vue-router1.1）搭建项目我们使用vue-cli脚手架搭建项目，你可以在自定义中勾选vue-router，或者自己下载yarn add vue-routervue create my-vue-router yarn add vue-router / npm install vue-router1.2）vue-router使用方式如果是自定义勾选router后的项目，我们会发现vue-router已经引入项目中使用了，我们来看看它的使用方式。引入vue-router插件// 在main只是一个文件的应用，不是插件的引用 import router from './router' // 真正的引用在router/index.js 并思考use方法，做了什么事情 import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter)创建router插件const router = new VueRouter({ mode: 'xxx', base: process.env.BASE_URL, routes }) export default router挂载router插件import router from './router' new Vue({ router, render: h => h(App) }).$mount('#app')使用router插件跳转路由并渲染dom<router-link to='xiaojuzi'></router-link> <router-view></router-view> this.$router.push('xx')1.3）vue-router的功能分析实现spa单页面应用的路由更新且不刷新页面【我们要实现hash路由和history路由】一个路由地址对应一个页面的渲染地址【我们要实现监听和渲染页面，时时render页面】1.4）写vue插件的思想1. 实现一个router功能类【你需要完成的功能】处理路由的类型监听router的变化响应router的事件2. 实现一个初始化插件的方法【你需要完成的功能】$ruoter的组册完成两个全局组件，即router-view和router-link二、手写自己的router【实现最简单的router功能】2.1）创建my-vue-router.js// 我们在初始化的时候，给我们申明的Vue赋值，这个时候在vue.use使用的时候， // 我们就可以在自己的my-vue-router.js中拿到vue的构造函数 // 目前只是hash功能/且只支持一层router let Vue; class MyRouter { constructor(options) { this.$options = options // 把current作为响应式数据 // 将来发生变化，router-view的render函数能够再次执行 const initial = window.location.hash.slice(1) || "/" Vue.util.defineReactive(this, 'current', initial) // 监听hash变化 window.addEventListener("hashchange", () => { console.log(this.current) this.current = window.location.hash.slice(1) }) } } // 参数是Vue.use调用时传入的,这里就可以拿到vue咯，保存你的vue吧 MyRouter.install = function (_Vue) { Vue = _Vue // 1.挂载$router属性 // this.$router.push() // 我们在use的时候，实际上这个时候new vue实例还没有开始执行，我们无法拿到vue的run-time的结果 // 这个时候我就借用Vue混入的思想，并借用生命周期做到延时效果 // 最后我们在全局挂载$router Vue.mixin({ beforeCreate () { // 次钩子在每个组件创建实例时都会调用 // 根实例才有该选项 if (this.$options.router) { Vue.p…

Vue全家桶之vuex原理
type: item
date: 2021-07-22T16:41:00+08:00
description: 一、Vuex状态管理的思想数据封装，集中式管理，可见的数据变更【单项数据流】解决跨组件之间的数据共享同步数据和异步数据更新试图还不会使用的同学可以看相关文档vuex官方文档：https://vuex.vuejs.org/zh/vuex源码地址：https://github.com/vuejs/vuex 【可以看src文件下内容/也可以看dist打包后的js文件】个人使用文档：http://gongpengji.com/index.php/archives/22/1.1）什么时候使用vuex借用redux作者的话：（你品这句话）Flux 架构就像眼镜：您自会知道什么时候需要它。想要了解状态管理必须看官方神图1.2）流程大体分为三步actions派发任务mutations执行任务state维护的数据状态1.3) 实现一个vuex插件需要拆解几部分实现store类完成一个响应式的state完成commit（）完成dispatch（）完成getter完成module【本次没有实现这一块】实现全局挂载$store二、实现自己的vuex并能支撑基本功能前三步都是使用，和原来的使用方式是一样的，主要看最后一个文件那就是一个小型的vuex2-1）main.js中使用import store from './juziStore' new Vue({ router, store, render: h => h(App) }).$mount('#app')2-2）App.vue中调用 mutations-count:{{ $store.state.count }} actions-count:{{ $store.state.count }} getters-count:{{ $store.getters.dobolde }} 2-3）创建juziStore文件夹里面 - index.js细心的朋友发现我这里有一行注释了的代码，其实这个注释的代码以前是这样的【import Store from 'vuex'】，这样store就是从我们下载的npm包中引用store类但是我这里是vuex.common.js，其实这就是vuex的源码，我会直接引用，并断点。学习源码使用的推荐代码地址：【里面有vuex.js/vuex.common.js等等，我们都可以直接拿来学习断点，不断查看运行步骤】https://github.com/vuejs/vuex/tree/9039c2169634925682ffcb21c57f5df355e16ad1/distimport Vue from 'vue' // import MyStore from './vuex.common' import MyStore from './myStore' Vue.use(MyStore) export default new MyStore.Store({ state: { count: 0 }, mutations: { add (state) { state.count++ } }, actions: { add ({ commit }) { setTimeout(() => { commit('add') }, 222); } }, getters: { dobolde: (state) => { return state.count * 2 } }, modules: { } }) 2-4）创建juziStore文件夹里面 - myStore.js注意看注解// 1、实现状态管理仓库 store // 2、实现install插件 // 3、实现响应式state // 4、实现commit方法 // 5、实现dispath方法 // 6、实现getter方法 // 7、暴露store模块 // 喜闻乐见的Vue借用又来了 let Vue; class Store { constructor(options) { // 保存配置 this.$options = options // 指定上下文执行环境 this.commit = this.commit.bind(this) this.dispatch = this.dispatch.bind(this) // 保存this this.getters = {} // 拿到参数中的getters对象 this._wrappendGetters = options.getters let computed = {}; const store = this // 遍历对象 Object.keys(this._wrappendGetters).forEach(key => { // 当前的getters中的函数 let fn = stor…

SEO基座篇-next-react
type: item
date: 2020-05-02T20:16:00+08:00
description: 前言bb前段时间，一同事问我react相关知识，我的大脑突然空白，许多细节都已模糊，回去看看以前的项目，才回想起来点，温故知新（捡起来）vue,react都是很好的框架,两则相互的竞争，相互借鉴，突破对方的弱点，相信前端会越来越好（近年来相对稳定，有好有坏吧，不管怎么说，不管什么行业，尤其靠技术吃饭的，自己不提升将会被时代抛弃）同样服务端渲染的next框架nuxt搞过，好奇心：next也要学学，先学习该工具的使用vue与react框架思想一样，那么相对应他们与之配套的服务端渲染nuxt和next是不是大同小异，gogogo学习一个新语言，新框架，新工具，都请先阅读官方文档：Next英文文档，中文文档有点落后一、搭建项目官网脚手架 / 当然你也可以自己搭建，安装所需npm包即可新版本next需要注意node版本10以上npm init next-app # or yarn create next-app使用官方cli初始化项目，就只一个pages文件夹，其他都需要你自己丰富我的demo目录结构├── .next --------------------------- 打包后项目主文件 ├── api ----------------------------- 说明文件 ├── asyncData ------------------- node服务端请求接口 ├── syncData -------------------- 浏览器请求接口 ├── assets -------------------------- 项目静态资源文件目录（图片、公共样式、字体等） ├── components ---------------------- 组件 ├── layouts ------------------------- 布局模式 ├── pages --------------------------- 页面（该文件夹下也对应着项目路由路径） ├── server └── index.js -------------------- node服务启动文件 ├── static -------------------------- robot静态文件 ├── store --------------------------- redux状态管理 ├── utils --------------------------- 工具 ├── next.config.js ------------------- webpack配置入口 ├── package.json -------------------- 项目配置老规矩，整理出页面所需要的基础配置与依赖webpacknode服务配置路由获取数据和组件生命周期rudex状态管理最后开始写页面或改造已有项目基本目标确定，开始工作workwork一、webpacknext并没有对该配置文件做多余的处理，编程者还是自己选择所需的打包吧webpack使用zeit下提供的三连utils，简易的话就不用配置啦，相对nuxt，他就没有其他多余的配置，大多还是webpack的使用next.config.jsconst withSass = require('@zeit/next-sass') const withCSS = require('@zeit/next-css') const withSourceMaps = require('@zeit/next-source-maps') module.exports = withSass(withCSS(withSourceMaps()))二、node服务配置server/index.js这里可以使用express，也可以使用koa作为node框架服务const express = require('express') const next = require('next') const compression = require('compression') const dev = process.env.NODE_ENV !== 'production' const app = next({dev}) const handle = app.getRequestHandler() let port = dev ? 6666 : 8080 console.log('Waiting ready on http://localhost ' + port + ' ……') // Pass in the absolute path to your robots.txt file app.prepare() .then(() => { const server = e…

SEO基座篇-nuxt-vue
type: item
date: 2020-04-29T17:38:00+08:00
description: SEO的出现1、搜索引擎-在信息大爆炸的时代，为广大用户提供最精确，最优质的搜索结果，搜索引擎，放出一个虚拟用户，收录各服务中html信息2、前端框架的兴起，v8运行js还是快的，主体html结构都压缩在js中，用户可看不懂js啊，拜拜，你这个服务器下啥子都没有，不来啦。seo（技术层面占3-4成）目前来说，前端能做什么先做本质的东西，什么其他优化啊，友好啊，先不提，基座都定不了，怎么开展其他工作呢1、基础目标：构建出静态页面前后端不分离开发（主流seo排行高页面大部分为前后端不分离项目）nuxt next 等node服务构建框架 同理的ssr服务端渲染预渲染 （如果真想做把seo做起来，不太建议该方式）2、基座遇到的问题前后端不分离 -- 渐渐不被提倡 （由繁到简，在简到繁）node服务都没有线上部署过，怎么配合运维线上部署，后期怎么维护、、、、ssr 没有去实践过，俺就不谈论 思想是一样的，搭建node中间服务去渲染页面，并返回给浏览器已经构建好的html文件优缺点对比1、前后端不分离优点：符合seo标准的静态页面页面结构清晰，页面内容可控制比例高，定制化方便开发风险性较低，代码可读性高缺点：开发与迭代所需工时长项目较重，DOM操作频繁各类插件维护版本2、nuxt / ssr-server优点：符合seo标准的静态页面项目打包轻，数据驱动比DOM轻，快缺点：前期开发成本高，node服务错误较难排查node服务，如何维护，高并发访问量如何处理（稳定性有待查看）3、预渲染优点：开发快，在原有项目改动方便缺点：动态数据维护较差，seo效果一般nuxt开发实践开发前请通读官方文档与API本文档只会聊使用到的技术点，其他还是多看看官方文档嘻嘻--俺也没有仔细阅读官方文档，这样不太好哦，写完文档，俺得回去在看看（第一遍看有什么，第二遍看为什么，第三遍看怎么实现）一、搭建项目官网脚手架 / 当然你也可以自己搭建，安装所需npm包即可npx create-nuxt-app <项目名> yarn create nuxt-app <项目名>这里我使用了nuxt模版提供选择的express，因为在后期我想通过express框架，对node服务进行个性化管理与配置目录结构├── .nuxt --------------------------- 打包后项目主体文件 ├── api ----------------------------- 说明文件 ├── asyncData ------------------- node服务端请求接口 ├── syncData -------------------- 浏览器请求接口 ├── assets -------------------------- 项目静态资源文件目录（图片、公共样式、字体等） ├── components ---------------------- 组件 ├── layouts ------------------------- 布局模式 ├── middleware ---------------------- 中间件 ├── pages --------------------------- 页面（该文件夹下也对应着项目路由路径） ├── plugins ------------------------- 插件 └── main.js --------------------- 等同于vue的main.js(vue对象挂载其他插件) └── index.js -------------------- 引用当前文件夹的总出口 ├── server └── index.js -------------------- node服务启动文件 ├── public -------------------------- 入口文件 ├── static -------------------------- 组件 ├── store --------------------------- 布局模式 ├── utils --------------------------- 中间件 ├── app.html ------------------------ html入口文件 ├── nuxt.config.js ------------------- webpack配置入口 ├── package.json -------------------- 项目配置使用脚手架新建项目，大部分目录都会自动生成现在项目有了，先不要急着写，整理出页面所需要的基础配置与依赖--感谢来自佳宁支援搭建webpacknode服务配置路由layout布局重新封装axios请求（异步数据处理）插件依赖vuex状态管理…

Redux
type: item
date: 2020-03-03T18:47:41+08:00
description: Redux状态管理const { createStore } = require('redux')const defailState = {count: 0;}const reducer = function(state = defailState,action){xxx>>>自己调用的 接收一个状态，返回一个新的状态，原状态是对象，新状态也要是对象 } const store = createStore(reducer,action,xxx)--创建的时候会被执行一次reducerconst newState = store.getState()-获取最新状态-每次调用的时候也会执行reducerstore.dispatch({ ---派发的是action参数xxx: xxx})---每次调用时也会执行一次reducer订阅你的改变信息提醒---store.subsrcibe(()=>{xxxx})yarn add react-redux context--注入包import { Provider } from 'react-redux'ReactDom.render(<Provider store="store"> <Redux></Redux> </Provider>, document.xxxid('#root'))Redux.js中import { connect } from 'react-redux'iconst mapStateToProps = (state) => {return{ count:state.count }}const mapDispathToProps = (dispath) => {return{ incment(){ dispath({ type: xxx, payload:xxx, }) }, decment(){ dispath({ type: xxx, payload:xxx, }) } }}export defalut connect(mapStateToProps,mapDispathTopProps)(Redux)connect(fn1,fn2),接收两个函数fn1:绑定state中的值，返回对象fn2:绑定dispath函数，派发扁平对象，返回对象什么纯函数给定预期的输入，返回预期的输出什么不是纯函数给一个输入，不确定输出的结果！副作用想做异步请求，Action派发之前，需要中间件拦截：第三方工具--xxxxxx很多redux-thuckimport {applyMiddleware} from 'redux' ---中间件可以让dispatch接受函数import Thunk from 'redux-thuck'const store = createStore(reducer,applyMiddleware(Tunck))增强dispath，可以接收函数或对象或数组了在componentDidMount(){}中可以调用props中定义的方法UI组件思想ReduxUI 纯DOM模板:定义函数式组件，返回UI 注意接收传入的参数props,如果是传函数<ReduxUI {{ ..this.props,handleclick = {this.handleclick.bind(this)}, xxx}}></ReduxUI>ActionCreator !抽离函数ActionCreator.jsexport const loadData = ()=>{return (dispath) = > { dispath({扁平对象}) }}在Redux中结构的引入action-typesexport const INDEX = 'x/index'combineReducers() 合并reducer只接受同步函数

React-router
type: item
date: 2020-03-03T18:46:42+08:00
description: 原生版 React-router-native浏览器版本 React-router-domyarn add react-router-domimport {BrowserRouter as Router,Route,Switch} from 'react-router-dom'<Router><Route path='/' exact component={Cookbooks}></Route> <Route path='/maps' component={xxx}></Route></Router>exact 精准匹配原本是包容性路由！派他性路由--->Switch<Switch><Route path='/' exact component={Cookbooks}></Route> <Route path='/maps' component={xxx}></Route> <Route path='*' component={page404}></Route></Switch>this:在被route包裹中定义的组件，子组件中的this.props中被定义上history,location,match对象，有很多方法和数据可以调用！Link:toNavLink:toactiveClassNameRoute:上的属性--这三个都有props属性1.component={组件} path匹配了，才会渲染，会卸载组件2.render={函数式组件} path匹配了，才会渲染 ，只是渲染组件3.(牛逼-可以自定义route事件，可以拿到props的三大无敌属性history,location,match)children={函数式组件} 不管匹不匹配都会渲染让任意一个组件拥有props--使用高阶组件挂在上去withRouterwithRouterReact-router-dom版本：react-router -3.0版本：react-router-dom -4.x/5.xreact-router-dom -4.x/5.x的区别：1、5.x性能提升2、解决了两个bug-- Router 不需要一个唯一的子组件 --之前需要一个标签包裹 -- Router 再和connect一起使用的时候，4.x要求withRouter--Router在外定义。5.x可以卸载connect里面 了

React-Hook
type: item
date: 2020-03-03T18:45:05+08:00
description: hook --- 状态 useStateconst [ xxx,setxxx ] = useState(默认值)允许你创建多个状态，多个状态不会互相影响也可以在一个状态上维护一个对象每次必须新的对象，来替换原先状态.hook --- useEffectuseEffect( ()=>{ xxx } ）类似mount钩子加update钩子加unmount也允许你写多个useEffect(),并且接受第二个参数，为[ xxx ]，及监听的状态不发生改变，该函数就不会执行每次它自己调用的时候，都是在DOM渲染完毕之后的时候第一次会自动调用状态改变时会自动调用组件卸载的时候也会自动调用，但必须return 一个函数,这个函数会在卸载后执行 ！hook --- useContexthook --- useReduerhook --- useCallbackhook --- useMemohook --- useRefhook --- useImperaiveHandlehook --- useLayoutEffecthook --- useDebugValue

React-4
type: item
date: 2020-03-03T18:43:33+08:00
description: Reacthtml属性和DOM属性的区别组件通信父子组件：props兄弟组件：（状态提升）A用父组件的方法，把值传给父组件，兄弟用父组件的值！跨组件通信：Context其实还有老版本context！Context,类似vue中的provide，inject一个树下的全局数据！xxx:let aaa = React.createContext('默认值')exprot xxx父组件：import aaa from 'xxx'<aaa.Provider value={'赵倩'}>子组件，子子子组件</xxx.Provider>或let {Provider} = aaa<Provide></Provide>子组件：static contextType = aaa<>{this.context.xxx}<>函数式组件：<Consumer>{ 数据 }</Consumer>HOC:高阶组件highordercomponent 增强式组件！本质是个函数，接收一个组件作为参数，对组件进行自定义加工后返回（组件）

React-3
type: item
date: 2020-01-08T16:17:32+08:00
description: React组件状态管理：statesuper()setState:是异步的this.setState({}) merge上面的state的操作，1.setState实质上是将传入的第一个参数对象的state对象做merge2.如果依据愿原有的state更新state，最好传入一个函数，setState((prevState)=>{return xxx},callback(回调，等待上一个函数的执行，等待DOM渲染，类似nexttick))setState会导致组件重新渲染只要父组件render被调用，子组件render也会被调用，不管父组件的状态更不更新状态提升：Lifting State Up兄弟组件传参A子组件调用父组件方法，A子组件的值在使用方法的时候把A组件的状态（数据），传给了父组件，父组件接收一下，可以在传给B子组件受控组件和非受控组件表单 新版：this.input = React.createRef() 事件处理this.handleClick.bind(this)使用bind，每一次都会创建一个新的事件函数定义:在constructorthis.xxx = this.xxx.bind(this)常用1、需要传参的()=> this.handleClick(x,x,x,e)2、只需要传ethis.handleClick()老（16-）生命周期钩子 没加react.fiber算法时初始化阶段constructor(){}装载阶段componentWillMount(){}render(){}componentDidMount(){}props改变的阶段componentWillReceiveProps(){}shouldComponentUpdate(){return boolean} 不能再此修改：setState; === PureComponentcomponentWillUpdate(){}render() 不能再此修改：setStatecomponentDidUpdate(){} 不能再此修改：setStatestates状态阶段shouldComponentUpdate(){return boolean} 不能再此修改：setState; === PureComponentcomponentWillUpdate(){}render() 不能再此修改：setStatecomponentDidUpdate(){} 不能再此修改：setState卸载阶段可以使用React.Dom.xxxxxnode方法卸载节点componentWillUnmount()新（16+）生命周期钩子16.4挂载时constructor(){}getDerivedStateFromProps(){}render(){}React(DOM,refs)componentDidMount(){}更新时此钩子，在16.3时只是监测props不会陷入死循环getDerivedStateFromProps(props,state){必须有返回值，没有写null props为父组件实实传入的值 state为子组件 return { title:props.title } }merage两次的值shouldComponentUpdate(){}render(){}getSnapshotBeforeUpdate(){必须有返回值，没有写null}配合使用componentDidUpdate(){}React(DOM,refs)componentDidMount(){}卸载时componentWillUnmount16.3 getDerivedStateFromProps此钩子，在16.3时只是监测props,但是在16.4的时候，此钩子会在props,setState,forceupdata的时候触发引用了不是state的数据，并更新数据,但不会跟新DOM使用this.forceUpdate(),强迫人家一下咯！（刷新页面）forceUpdate使用，不会调用shouldComponentUpdate钩子static defaultProps()static displayName()

React-2
type: item
date: 2020-01-08T16:16:04+08:00
description: React轻量级UI库React高性能的体现：虚拟DOM-在内存数据，性能极高。React Fiber 16+核心算法-分片哪里用了JSX，哪里就要引React函数式组件，一个JS就是一个组件，但是没有状态，也叫无状态组件、傻瓜组件，影子组件，可以接收父组件传递的信息包裹用的标签，Fragment,记住解构去引，或不引用可以用空标签包裹创建方式1.Class方式创建组件2.js无状态创建方式3.使用createClass创建组件时，无法暴露，但可以引入插件：create-react-classporps：传值静态属性：默认值Props.defaultProps={title:"xxx"}或者static defaultProps = {title: "xxx"}读取子元素节点：this.props.childrenprops类型检查：使用包：prop-types静态属性：static propTypes = {title = PropTypes.[xxx/string/array/node...]}node节点可以传模板下去比较element,React 元素React 标签