媒介
前面两篇文章总结了 Vue 开发的大部门技巧和内容,最初一篇文章来对它停止一个收尾
那篇文章我们来谈谈一些 Vue 理解和理论要求高一点的问题
起首是生命周期那一块内容,跟着理论越多它的意义越大,理解也越深入
mixin功用强大,对代码复用组织都有很高的要求,算是 Vue 后期发力的高级技巧
办事端衬着可能是进修 Vue 最初一块阵地了,关于 SPA 框架的一个里程碑
最初,总结一下我在利用 Vue 中利用的技巧和经历
常规操做,先点赞后旁观哦!你的点赞是我创做的动力之一!
前情概要我将从 16 个方面来阐述 Vue 开发过程中的一些技巧和原理。若是你还未旁观上节文章,能够移步至
吃透 Vue 项目开发理论|16个方面深切前端工程化开发技巧【上】吃透 Vue 项目开发理论|16个方面深切前端工程化开发技巧【中】本篇概览Vue 生命周期什么是 Vue 生命周期?Vue 生命周期大要就是:一个从 Vue 实例的创建到组件销毁的一个的过程。
详细情况下,我们分为几个核心的阶段,而且每个阶段都有一套钩子函数来施行我们需要的代码。
生命周期阶段与钩子我们整理分类一下那些生命周期钩子,为了记忆便利分为 4 大核心阶段:
便利读者记忆,那里尽量利用图示:
能够看到每一个阶段中的钩子定名都很好记忆,阶段起头前利用 beforeXxx,阶段后完毕后利用xxxed
除那 8 个核心钩子,别的还有 3 个新增功用型钩子,目前总共是 11 个钩子 顺带提一下那 3 个钩子的功用
组件缓存,activated 与 deactivated,那两个钩子也是一对的,别离暗示被 keep-alive 缓存的组件激活和停用时挪用。组件错误捕捉,errorCaptured,对组件中呈现对异常错误停止处置,利用较少。图解生命周期我们看看官方的图解,在 Vue 教程实例那节官方教程间接跳转
官方图解官方图解并没有详细解释那张图。我猜一方面原因是那个图里面涉及的细节都是在 vue 源码里面表现,要实正解释起来也没那么简单。另一方面是希望我们多在理论中去理解里面的意义。
Vue 源码根本流程关于上面那张图的理解,我们需要对 Vue 源码停止梳理,才气实正的理解。大要按照现有的源码,我梳理了一下大致的流程:
我们能够清晰地看到,从 Vue 实例创建、组件挂载、衬着的一些过程中,有着明显的周期节点。
简化文字图解连系上面源码的流程和相关理论,简化每一个阶段做了哪些期间,每一个钩子里面是组件处于什么形态。
理论验证一下生命周期提出问题下面我们提出一些问题:
什么期间创建 el ?什么期间挂载 data ?什么期间能够拜候 dom ?什么情况下组件会更新?更新是同步更新仍是异步更新?什么情况下组件会被销毁?销毁组件后,还能够拜候哪些内容?编写代码起首写一个小 demo,打印关键组件信息<template><div><divclass="message">{{message}}div>div>template><script>exportdefault{data() {return{message:1}},methods: {printComponentInfo(lifeName) {console.log(lifeName)console.log(el,this.$el)console.log(data,this.$data)console.log(watch,this.$watch)}}}script>复造代码增加核心的 8 个生命周期钩子,别离挪用打印办法// ...beforeCreate() {this.printComponentInfo(beforeCreate)},created() {this.printComponentInfo(created)},beforeMount() {this.printComponentInfo(beforeMount)},mounted() {this.printComponentInfo(mounted)},beforeUpdate() {this.printComponentInfo(beforeUpdate)},updated() {this.printComponentInfo(updated)},beforeDestroy() {this.printComponentInfo(beforeDestroy)},destroyed() {this.printComponentInfo(destroyed)},// ...复造代码创建阶段beforeCreate 中methods中办法间接报错无法拜候,间接拜候 el 和 data 后
发现只能拜候到 watch, el 和 data 均不克不及拜候到
created 期间 el 无法拜候到,但是能够拜候到 data 了
挂载阶段beforeMount 中能够拜候 data 但是仍然拜候不到 el
mounted 中能够拜候到 el 了
初次加载页面,更新阶段和销毁阶段到钩子都未触发
更新阶段我们增加一行代码
this.message =this.message +1复造代码若是增加在 created 阶段,发现 update钩子仍然未触发,但是 el 和 data 的值都酿成了 2
若是增加在 mounted 阶段,发现 update钩子此时触发了
销毁阶段如何触发销毁的钩子呢? 大要有那几种办法
手动挪用 $destoryv-if 与 v-for 指令,(v-show 不可)路由切换和封闭或刷新阅读器 我们在 mounted 钩子里面增加一行代码手动销毁当前组件,或者跳转路由this.$destory(lifecycle)复造代码发现beforeDestory 和 destoryed 都触发了,并且el、data都一样仍是能够拜候到
生命周期钩子常见利用的场景beforeCreate 隆重操做 thisbeforeCreate 无法拜候到 this 中的 data、method
// 错误实例beforeCreate() {// 允许console.log(ok)// 不允许this.print()// 报错找不到this.message =1// 报错找不到}复造代码恳求应放在 created 钩子中created 能够拜候 this,但无法拜候 dom,dom 未挂载
created() {// 允许并保举this.$http.get(xxx).then(res => {this.data= res.data})// 不允许this.$elthis.$ref.democonsta = document.getElementById(demo)}复造代码操做 DOM 代码应放在 mounted 钩子中mounted 已经挂载 dom,能够拜候 this
mounted() {// 允许this.$elthis.$ref.demoleta = document.getElementById()}复造代码生命周期相关demo 代码见github-lifecycle-demo
理解并合理利用 mixin什么是 mixin(混入)当组件利用混入对象时,所有混入对象的选项将被混合进入该组件自己的选项 大致原理就是将外来的组件、办法以某种体例停止合并。合并的规则有点像继承和扩展。
当组件和混入对象含有同名选项时,那些选项将以得当的体例停止合并
我们看一下一个组件里面有哪些工具是能够合并的
// mixins/demoexportdefault{data() {return{}},mounted() {},methods: {},computed: {},components: {},directives: {}}复造代码data、methods、computed、directives、components 生命周期钩子
没错那些都能够混入
importdemoMixin form@/mixins/demoexportdefault{mixins: [demoMixin]}复造代码如许看来,良多页面反复的代码我们都能够间接抽取出来
或者是封拆成一个公共的 mixin
好比我们做 H5 页面,里面良多短信验证的逻辑固有逻辑,但是需要拜候到 this。利用东西函数必定不可。
那时候就能够考虑利用 mixin,封拆成一个具有响应式的模块。供需要的处所停止引入。
mixin 规则起首是优先级的问题,当重名选项时选择哪一个为最初的成果
默认规则我那里分为 3 类
data 混入: 以当前组件值为最初的值生命周期钩子: 保留所有钩子,先施行 mixins 的,后施行当前组件的methods、computed、directives、components 那种健值对形式,同名key,通盘以当前组件为准当然若是想改动规则,也能够通过设置装备摆设来改动规则
Vue.config.optionMergeStrategies.myOption =function(toVal, fromVal){// 返回合并后的值}复造代码mixin 的益处我们晓得 Vue 最能复用代码的就是组件。一般情况,我们通过 props 来控造组件的,将原有组件封拆成 HOC 高阶组件。而控造 props 的生成纷歧样的功用的代码仍是写在根底组件里。
<templatelang="pug">div.dibvan-button.btn(@click="$emit(click)":class="getClass" v-bind="$attrs":style="{width: size === large ? 345px: , backgroundColor: getBgColor, borderColor: getBgColor, color: getBgColor}")slottemplate><script>import{ Button }fromvantimportVuefromvueimport{ getColor }from@/utilsVue.use(Button)exportdefault{name:app-button,props: {type: {type:String,default:primary},theme: {type:String,default:blue},size: {type:String,default:}}}复造代码以那个组件为例,我们仍是通过公共组件内部的逻辑,来改动组件的行为。
但是,利用 mixin 供给了另一个思绪。我们写好公共的 mixin,每一个需要利用 mixin 的处所。我们停止扩展合并,差别与公共 mixin 的选项我们在当前组件中停止自定义,也就是扩展。我们新的逻辑是写在当前组件里面的,而非公共 mixins 里。
画个图理解一下:
最初总结一下 mixin 的长处
复用代码,公共逻辑抽离能够拜候 this, 能够操做响应式代码mixins 相对与组件来说,更像扩展说了那么多那 mixins 有什么害处呢?第一,万万不克不及滥用全局 mixins 因为会影响所有多子组件
第二,因为 mixins 的合并战略固有影响,可能在一些极端情况达不到你想要的效果。
好比:我已经存在一个 mixins,我的页面里面也有一些办法,我要引入mixins 就要做良多改动,来包管我的代码按我的需要运行。
页面 data 有一个 message 值,mixins 里面同样有一个。
根据默认规则,mixins 里面的 message 会被页面里面 message 笼盖。但是那两个 message 可能代表的意义纷歧样,都需要存在。那么我就需要改掉此中的一个,若是营业太深的话,可能那个 message 没那么好改。
有时候需要考虑那些问题,招致利用 mixins 城市增加一些开发承担。当然也是那些问题能够利用标准来躲避。
理解并利用 SSRSSR 是 Serve Side Render 的缩写,翻译过来就是我们常说的办事端衬着
简单归纳 SSR 存在的原因SPA 框架 SEO 的处理计划提拔首屏加载速度但是它还存在以下问题
有些生命周期钩子无法利用(之前提到的 activated 和 deactivated 等等)额外良多的设置装备摆设办事器资本的需求总得来说,SSR 是需要的但不是充实的,SPA 的 SEO 如今没有更好的计划,有那方面强烈需求的网站来说,SSR 确实很有需要
SSR 原理通过上面图我们能够得大致几点内容
通用营业代码只写一套。通过表露客户端和办事端两个入口,对 Vue 实例停止拜候。通过构建东西打成两个包,办事端包通过 node 办事器衬着给阅读器拜候。客户端和本来一样通过拜候资本获取。实现SSR 有 3 种体例1. 按照官网教程搭建,一步一步搭建SSR, 那里有详细教程,略微有点费事,但是可以体验搭建的过程,愈加深切细节。利用于操练,和现有项目标革新2. 利用demo革新,开源 demo,便利省时,适用代码参考进修vue-ssr-demo3. 利用nuxt,预设了 SSR 和预衬着,适用于需要 SSR 的新项目。别离测验考试用那 3 种体例搭建 SSR
五步简单理解SSR(按照官网教程,详细完操做查看整教程和demo)那里次要加深理解,vue-cli3+ 实现根本 SSR
第一步:安拆依赖vue-server-renderer (核心依赖,版本必需与 vue 版本一致)webpack-merge(用于webpack设置装备摆设合并)webpack-node-externals (用于webpack设置装备摆设更改)express (用于办事端衬着)第二步:成立入口,并革新革新分为 2 个入口,将 main.js 定为通用入口, 并额外增加entry-client.js 和 entry-serve.js 两个
1.革新次要入口,创建工场函数
// main.jsimportVuefromvueimportAppfrom./App.vueimport{ createRouter }from"./router"// app、routerexportfunctioncreateApp(){constrouter = createRouter()constapp =newVue({router,render:h=>h(App)})return{ app, router }}复造代码2.客户端入口
// client.jsimport{ createApp }from./main// 客户端特定引导逻辑const{ app } = createApp()app.$mount(app)复造代码3.办事端入口
// serve.jsimport{ createApp }from"./main";exportdefaultcontext => {// 因为有可能会是异步路由钩子函数或组件,所以我们将返回一个 PromisereturnnewPromise((resolve, reject) =>{const{ app, router } = createApp();// 设置办事器端 router 的位置router.push(context.url);// 比及 router 将可能的异步组件和钩子函数解析完router.onReady(()=>{constmatchedComponents = router.getMatchedComponents();// 婚配不到的路由,施行 reject 函数if(!matchedComponents.length) {returnreject({code:404});}// Promise 应该 resolve 应用法式实例,以便它能够衬着resolve(app);}, reject);});};复造代码第三步:革新 vue.config 设置装备摆设constVueSSRServerPlugin =require("vue-server-renderer/server-plugin");constVueSSRClientPlugin =require("vue-server-renderer/client-plugin");constnodeExternals =require("webpack-node-externals");constmerge =require("webpack-merge");constTARGET_NODE = process.env.WEBPACK_TARGET ==="node";consttarget = TARGET_NODE ?"server":"client";module.exports = {configureWebpack:()=>({entry:`./src/entry-${target}.js`,devtool:source-map,target: TARGET_NODE ?"node":"web",node: TARGET_NODE ?undefined:false,output: {libraryTarget: TARGET_NODE ?"commonjs2":undefined},externals: TARGET_NODE? nodeExternals({whitelist: [/\.css$/]}):undefined,optimization: {splitChunks:undefined},plugins: [TARGET_NODE ?newVueSSRServerPlugin() :newVueSSRClientPlugin()]}),//...};复造代码第四步:对路由 router 革新exportfunctioncreateRouter(){returnnewRouter({mode:history,routes: [//...]})}复造代码第五步:利用 express 运行办事端代码那一步次要是让 node 办事端响应 HTML 给阅读器拜候
const Vue = require(vue)const server = require(express)()const renderer = require(vue-server-renderer).createRenderer()server.get(*, (req, res) => {const app = new Vue({data: {url: req.url},template: `<div>拜候的 URL 是: {{ url }}div>`})renderer.renderToString(app, (err, html) => {if (err) {res.status(500).end(Internal Server Error)return}res.end(`html><htmllang="en"><head><title>Hellotitle>head><body>${html}body>html>`)})})server.listen(8080)复造代码nuxt 体验简单几步体验下 nuxt
安拆后简单看了一下源码,nuxt 把我们之前提到的重要的革新,全数封拆到 .nuxt 文件夹里面了
跑一下 dev 发现有两个端,一个 clinet 端,一个 server 端
最初查看一下效果,整个过程挺丝滑的。目次构造也比力契合我的气概,新项目需要 SSR 会考虑利用 nuxt
利用 webpack 插件预衬着处理 SEO 问题是不是只要 SSR 呢?其实预衬着也能做到,起首
区别利用 SSR 和预衬着办事端衬着处理的问题,不只只是把 HTML 页面给阅读器,更重要的是处置动态逻辑和 JS 代码后,将衬着后完好的 HTML 给阅读器,衬着的过程在办事端。预衬着,是操纵构建东西在 webpack 中生成静态的 HTML,间接给阅读器,衬着的过程在当地。预衬着插件里面提到两种不克不及利用:大量路由、动态内容利用 prerender-spa-plugin 插件停止简单预衬着安拆 prerender-spa-pluginyarnprerender-spa-plugin复造代码修改 webpack 设置装备摆设,比力简单就能完成设置装备摆设constpath = require(path)constPrerenderSPAPlugin = require(prerender-spa-plugin)constRenderer = PrerenderSPAPlugin.PuppeteerRenderermodule.exports = {plugins: [//...newPrerenderSPAPlugin({staticDir: path.join(__dirname,dist),outputDir: path.join(__dirname,prerendered),indexPath: path.join(__dirname,dist,index.html),routes: [/,/about,/some/deep/nested/route],postProcess (renderedRoute) {renderedRoute.route = renderedRoute.originalPathrenderedRoute.html = renderedRoute.html.split(/>[\s]+join(><)if(renderedRoute.route.endsWith(.html)) {renderedRoute.outputPath = path.join(__dirname,dist, renderedRoute.route)}returnrenderedRoute},minify: {collapseBooleanAttributes:true,collapseWhitespace:true,decodeEntities:true,keepClosingSlash:true,sortAttributes:true},renderer:newRenderer({inject: {foo:bar},maxConcurrentRoutes:4]}复造代码Vue 开发技巧总结从 5 个大的角度来提拔开发效率和体验,代码美妙和代码量量,用户体验
5 大角度提拔代码复用组件化开发,代码效率 * n利用 mixins 抽离公共逻辑,代码效率 * n东西化函数、利用 filter 编码效率+sass 复用 css,编码体验、效率+代码量量代码静态查抄 eslint + prettier,代码气概+、根底语法错误-数据类型控造 typescript,代码量量+前端测试 test,代码量量+代码优化合理利用 vue,衬着性能+合理利用 vuex 削减恳求,利用图片懒加载,加载性能+合理利用函数组件,组件性能+合理骨架屏、路由过渡,用户体验+开发效率利用更新的脚手架 vue-cli4,webpack 设置装备摆设效率+利用设置装备摆设好的脚手架模版 vue-h5-template,vue 设置装备摆设效率+利用更简洁的模版 pug,HTML 编写效率+利用更强大的 css 编写 sass,CSS 编写效率+利用模仿数据 mock,离开后端开发效率+开源组件封拆 HOC,组件开发,页面编写效率+瓶颈处理路由history利用,办事端设置装备摆设相关,URL美妙+处理SEO与首屏加载、办事端衬着 SSR 根本处理跋文做者面对 赋闲 和 禁足 在家里的双重冲击下,仍然对峙完成了那个系列的最初一篇文章。
若是能对你有帮忙,即是它更大的价值。都看到那里还不点赞,过分不去啦!
因为手艺程度有限,文章中若有错误处所,请在评论区指出,感激!

评论列表