只会笑的提莫 - vue
type: channel
link: http://gongpengji.com/index.php/category/vue
description: 框架学习！学习曲线平滑的框架！让前端工作越来越明确
items: Vue全家桶之vue-router原理
items: Vue全家桶之vuex原理
items: SEO基座篇-nuxt-vue
items: VUEX
items: VUE-4
items: VUE-2
items: VUE-1
items: VUE-3

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基座篇-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状态管理…

VUEX
type: item
date: 2019-07-24T23:14:00+08:00
description: 框架中的状态管理第一篇 vuex(请先看神图)单项数据流vuex管理流程状态管理应用包含三部分：state，驱动应用的数据源；view，以声明方式将 state 映射到视图；actions，响应在 view 上的用户输入导致的状态变化。进入实战在使用全局安装vue vue-cli使用vue全家桶指令vue create 项目名称安装vuex-- yarn add vuex1.打开main.js文件，此为vue项目的入口在这个文件中，创建vue实例，并挂在其他模块插件，在new构造函数中挂载store，store为整个vuex仓库，还可以挂载router路由最后记住挂载根节点import router from './router/' import store from './store/' new Vue({ store, router, render(h) { return h(App) } }).$mount('#app')2.创建与pages同级的文件夹store，创建index.js导入相应的包，并在Vue上使用Vuex创建Vuex实例 new Vuex.Store({})关键部分来了：在实例中定义Vuex灵魂部分state、getters、mutation、action、module，在后面会阐述，先看看我的简单布局 import Vue from 'vue' import Vuex from 'vuex' import http from '../utils/http' Vue.use(Vuex) const store = new Vuex.Store({ state: { data: {} }, getters: { }, mutations: { setFirstData(state, result) { state.data = result }, }, actions: { async loadFirstData({commit}, params) { let result = await http.get(params.firstReq) commit('setFirstData', result) }, }, module: { 状态树 } }) export default store3.看完大致结构，能帮助初学者快速搭建，当然每个单独的模块也可以单独定义在外面，再引入实例中。接下来我们来分别讲一讲五大核心的各自作用。stateVuex使用的单一状态树，在一个状态树中用一个对象，包裹着你定义的所有状态。当数据量大，且分为不同模块时，我们还可以使用module,后面会讲到。getter(getters)相信在学Vuex之前，大家已经了解Vue中的计算属性，用来监控data中的状态是否发生变化。其实getters类似于计算属性computed，我们可以在该对象中定义多个方法，当state中的数据发生变化，函数就会执行并返回新的状态。getter的返回值会根据他的依赖被缓存起来，且只有当它的依赖值发生变化才会被重新计算。注意：getter中定义函数，函数的一个参数为state，及上面定义的状态。Getter 也可以接受其他 getter 作为第二个参数。mutation(mutations)在Vuex中，想要更改store中的状态只有一个方法，那就是mutation。在mutation中你可以定义多个方法，这些方法的操作，最终是改变你在state中定义的属性，且这些方法接收state作为第一参数，当你想传入参数给该方法时，第二参数：载荷payload，该payload可以是对象或其他基本类型方法（state,payload） { } 注意：mutation中确实是定义了很多方法，但你只能通过store.commit('方法名')来调用。mutation必须必须是同步函数，不要在方法中进行异步操作支持的三种调用方式store.commit({ type: 'increment', amount: 10 }) store.commit('increment', { amount: 10 }) store.commit('increment', 10)action(actions)(详细再看vuex官网)看完到上面mutation时，发现mutation有一个尴尬的地方，它只能进行同步操作，但我们往往需要请求接口资源，进行异步操作。action就是来弥补mutation的不足的地方，但在使用action有几个注意的地方。不要尝试在action中直接改变state中的状态。你也改不了。(#^.^#)action提交的是mutation，而不是直接修改状态。通过context.commit(提交一个mutation…

VUE-4
type: item
date: 2019-07-24T23:13:21+08:00
description: vue 自定义指令：全局指令Vue.directive('focus',{inserted(el) { el.focus() }})调用 v-focus组件，实例上的指令directives: {demo(el,) { xxx } demo:{ bind(el,binding){ } }}过滤器filter Vue.filter('g',(value)=>{return xxx})也可以在局部上定义过滤器filters:{g(value){ }}还可以定义多个，并绑定多个过滤器绑定多个过滤器时，后一个过滤器是上一个过滤后的value还可以加参数插件使用插件：Vue.use('插件'，参数)开发咯插件.install = function(Vue,options){Vue.xxx = function(){} 全局资源 Vue.directives(){} Vue.mixins(){} 在实例上绑定方法 Vue.prototype.$xxx(){}}Vue-CLI:起步vue create xiaomi1,4,5,6stulessin packgjsonnoyarn

VUE-2
type: item
date: 2019-07-24T23:11:41+08:00
description: VUE （计算属性）计算属性：computed + watch + methodscomputed: {xxx : function(){ return 表达式 }}computed:基于缓存，检测data数据是否改变当数据没有改变时，多次调动该函数，但函数不会执行表达式中调用this.data中的属性，当data数据改变，(函数才会执行)表达式会重新计算，并返回。但是在methods中methods:{xxx : function () { return 表达式 }}多次调用，xxx会被执行多次，不管data数据是否改变，但是发现表达式的返回结果一样，DOM也不会重新渲染watch: {title() { }}零、computed watch methods的使用场景computed：--当依赖某些状态（state）产生新值的时候，优先选择使用computed：watch：--用来解决beforeUpdate,updated，两个钩子里修改状态导致死循环的问题，采用watch--监测可能异步改变值的时候methods：--定义事件响应函数--定义组件公共处理函数一、computed 和 methods 的区别1、相同点如果作为模板的数据显示，二者都能实现相应的功能，唯一不同的是methods定义的方法需要执行。2、不同点-- computed 会基于响应数据缓存，methods不会缓存（但是在绚烂DOM时会判断DOM是否改变，改变时才会重新渲染DOM）-- diff之前先看data里的数据是否发生变化，如果没有变化computed的方法不会执行，但methods里的方法会执行二、watch vs computed1、相同点如果作为信息展示，二者可以实现相同的功能。不同点是watch可能需要监听更过的属性。在这个时候我们优先使用computed2、不同点-- 当想在更新data数据后再次更新数据的时候，不能使用updated生命周期钩子。建议使用watch来监听data数据的变化-- 使用 watch 选项允许我们执行异步操作 (访问一个 API)，限制我们执行该操作的频率，并在我们得到最终结果前，设置中间状态。这些都是计算属性无法做到的。三、如何使模板重新渲染1、只要改变data里的数据就会可能触发模板渲染2、如果经过diff算法比较后，发现更新前后更新后的虚拟DOM相同，就不会渲染模板Class与Style绑定v-bind:xxx="表达式结果类型：可以是字符串，可以是对象，还可以是数组"v-bind:class="[]"v-bind:style="xxx"v-bind:class="{}" 对象且可以深拷贝兼容性1.自动添加前缀：当 v-bind:style 使用需要添加浏览器引擎前缀的 CSS 属性时，如 transform，Vue.js 会自动侦测并添加相应的前缀。2.多重值：从 2.3.0 起你可以为 style 绑定中的属性提供一个包含多个值的数组，常用于提供多个带前缀的值，条件渲染v-if 和 v-else 中间不能有元素（切记）v-else-if 包裹条件的模板标签，条件写在template上，但渲染后不会有该标签 :key 相同标签的独立性注意， 元素仍然会被高效地复用，因为它们没有添加 key 属性。v-show(boolean) -- 判断，显示隐藏v-for同时和v-if存在同标签判断中！v-for优先！当它们处于同一节点，v-for 的优先级比 v-if 更高，这意味着 v-if 将分别重复运行于每个 v-for 循环中。当你只想为部分项渲染节点时，这种优先级的机制会十分有用，v-for="(item,index） of/in 数组/对象"v-for可以接收三个参数，value，key，indexv-if 和 v-show 的区别DOM是真正否渲染！DOM是否隐藏，一定会渲染！数组变异方法:可以改变原数组的方法push()pop()shift()unshift()splice()sort()reverse()替换数组:不会改变原数组，而是返回一个新数组filter()concat()slice()注意：由于 JavaScript 的限制，Vue 不能检测以下数组的变动：1. 当你利用索引直接设置一个数组项时，例如：vm.items[indexOfItem] = newValue2. 当你修改数组的长度时，例如：vm.items.length = newLength目前2.0版本为了解决这个问题：使用setvm.$set(监听操作)Vue.set(监听操作)vue2.0使用definpropty监测对象，对数组下标可以操作，但不会响应vue3.0即将使用es6的监听方法，解决响应问题事件处理v-on:…

VUE-1
type: item
date: 2019-07-24T23:10:47+08:00
description: vue (开篇)（数据驱动）（函数式编程）（数据双向绑定）(不操作DOM)引入vue.js文件vue框架的优点：1、易学，入门2、性能好（虚拟DOM）3、组件（高内聚，低耦合）vue提示插件：Vetur常用方法：注意函数中使用this指向实例var vm = new Vue ({el: '标签', ---标签内的元素全部被vue监听 data: { 数据驱动 }, mounted () { this指向实例 且该函数自动执行 对异步请求的数据实时更新 }, computed: { total() { return } }, methods: { handleInput(e) { this.list.push(e.target.value) } }, components: { 'gp-10' : Gp10 //vue中模板中的自定义组件会自动转为小写；注意多个使用自定义标签时，不要使用单标签 }}).$mount('#root')标签中的方法v-for="" 循环v-if="" 条件v-bind:xxx = "" vue接管标签中的属性v-bind: === :v-on: === @v-model.number= "" 数值的话转为number (语法糖)v-bind:value="" + v-on 的结合v-on:input="" 事件处理函数v-on:keyup.13= ""v-on:keyup.enter= ""v-once 布尔值，标签中的文本不在更新v-text 不会解析标签v-html 少用.prevent显示数据内容使用 : {{}}动态参数 : []组件自定义：全局定义组件Vue.component('gp10',{template: "浏览器认识的标签"})局部定义组件var Gp10 = { props: ['title'] data() { return { } } template: "浏览器认识的标签", methods: { 自定义事件函数 }}实例：$话题Object.freeze(data) --- 冻结当前属性不能修改vm.$el --- 返回当前节点在实例外面vm.$el = '#xxx' 无效生命周期函数$options ： 调用自定义在Vue上的方法！this.options.方法 或 v-on:click='$option.方法'vm.$destory() -- 销毁实例，解绑全部指令和事件监听器触发：beforedestory 和 destoryed 的钩子钩子起步 new Vue()1.beforeCreate(){}--可以访问this --不可以访问this.title..等其他数据属性--此时可访问DOM模板2.created(){} --- 数据初始化的机会，但还没渲染DOM--第一次初始化的机会--此时可以访问数据--此时可访问DOM模板【创建结束后，进入判断，判断有无$el，有无$mount,有无模板-template】隐式函数钩子：render(createElement)3.beforeMount(){}--第二次初始化的机会--此时可访问DOM模板，但并没有绚烂【真实的绚烂DOM，替换el节点！】4.mounted(){}--此时DOM模板渲染完成，可以拿到该元素节点5.beforeUpdate(){}--当上面的钩子中data被更新的时候，指向当前钩子--拿的DOM是原来没更新的DOM6.updated()--当上面的钩子中data被更新的时候，指向当前钩子--拿的DOM是更新后的DOM7.beforeDestory()--卸载响应式，及__od__8.destroyed(){}errorCaptured

VUE-3
type: item
date: 2019-07-02T23:11:00+08:00
description: VUE组件组件的命名，注意规范：标签一定用肉串，或全小写子组件注意需要包裹divprops:['使用小驼峰']全局组件--局部组件Vue.components('xxx',{template:'xxx'})const Blog = {template:'xxx' components:{ xxx //引用其他组件 }}注意组件之间是单项数据流--组件外部不能互相访问--子组件数据传给父组件--父组件自定义方法，子组件在事件函数中调用！父子组件间信息传递-- 父传子：prop = ['']-- 子传父:父组件methods : {父组件方法(参数) { console.log(参数) }}子组件：methods : {子组件方法() { this.$emit('父组件自定义方法',传参) }}--组件外部不能访问组件内部的数据--组件内部不能修改组件外部的数据--不允许子组件修改父组件的数据--也不允许父组件修改子组件的数据父子组件传参局部子组件：应该在父组件定义之前定义；通过父组件模板tem中传.prop: [ 'xxx' ],子组件接收父组件传来的参数在子组件中使用，this.xxx插槽 --- slot，想在组件中放入内容，内容可以是标签，或文本 template: ` <slot>可定义多个插槽</slot> <slot name=''>且可定义name属性，来渲染name对应的原HTML标签</slot> <slot></slot> `插槽prop--请看官网-还组件之间还可以访问参数的方法,父组件访问子组件的信息动态组件-会被销毁及会执行destroyed钩子异步组件，路由懒加载<component :is="xxx"></comonent> 必须使用浏览器认识的标签但是，li只是零时装填，还是看xxx组件中的模板tem中的内容标签。会替换掉li的！使用<keep-alive></keep-live>缓存失去活性的组件，八个常用钩子失效，可用钩子activated,deactivated专为keep-alive使用！一个组件的data必须是一个函数浏览器渲染机制：ul下有的必须是li,所有vue中li装载模板变量局部组件：注意全局注册props:注意事项props: ['必须使用小驼峰','小驼峰']约束参数类型props: {"xxx":类型（String）， "xxx": Number "xxx": [String,Number] "xxx":{ type:Number required:true } "xxx":{ type:Number default: 100或function(){ return 100xxx } } "xxx":{ 自定义 validator:function(value){ return value === ??? } }}巨有用：非props在父组件tem...中定义的属性,但是子组件中的props中没有定义，会在子组件的标签上显示，在prop中定义了，该属性就会消失在子组件标签上。在子组件中使用inheritAttrs: false,也可以使子组件不继承某些属性！自定义组件使用v-model**将原生事件绑定在组件上@.click.native=""事件在父组件域上，执行调用在子组件。父子组件数据通信！方法一：父组件作用域下：update:v-xxx:update:xxx子组件:$emit('update:xxx',xxx-参数)方法二：父组件作用域下:title.sync="title"子组件:$emit('update:xxx',xxx-参数)混入-就是很多混子混进来了-大家一起混--继承--公用！mixins:[xxx,xxx]原定义的option中的方法会顶掉混子，即mixins中的方法data 会 merge，相同则覆盖。其他options也是一样咯！边界处理：子组件 标签中定义<xxx ref=''>父访问子 $refs子访问父 $parent子访问更节点 $root依赖注入父组件 provide: function () {return { getMap: this.getMap }}子访问，类似props ：inject:['']vue-bus bus总线递归组件：自己调用自己，记住给一个出口及终止条件内联模板：inline-template,在模板标签中写DOM标签强制渲染页面$forceUpdate();