👨‍💻‍记录使用Nuxt2开发项目过程中遇到的各种难点、API问题、BUG、及教程整理(不定时更新)😁

4,707 阅读6分钟

项目背景

以前公司的老官网是我17年入职之前就有的,是很老的PHP前后耦合的技术栈开发的,页面UI巨丑😅,然后17年初入职后UI设计师重新设计了一版,当时我用jQuery重构过一次,重构完了就闲置着没上线。新官网的第二次重构是18年初开始学习vue,当时用vue2重构,但重构完以后也一直闲置着没上线替换掉老官网,这期间一直在忙公司其他的重要项目😂。

后来在19年上旬,老板和运营同事觉得还是要替换掉老官网,并且要求必须解决SEO问题。当时我和后台同事尝试过使用掘金的方案,预渲染插件prerender-spa-plugin搭配vue-meta实现头部标签动态管理,但是这种方案只适用于纯静态页面,有很多动态数据的页面,例如各种类型的列表页或详情页,之前预渲染插件不能满足需求,没办法使用这种静态预渲染方案解决🙄。

后来又实现过第二种方案,还是采用前后耦合架构,java thymeleaf模板配合我这边jQuery,把整个项目几十个页面全部重写一遍,但是不用实现css,只要保证有很多动态数据的页面,把接口返回的数据正常展示渲染DOM即可,也既是服务端渲染,然后我这边大概花了两周写完全部页面后,java同事那边利用Nginx监听百度爬虫useragent动态判断,跳转到爬虫收录的页面,这种方案对于用户来说是无感的,理论上是可以解决我们的痛点,不影响爬虫收录的,但是后来搞了个其他域名,短暂的上线了一两个月,百度爬虫一直收录不到新域名,随机放弃这种方案🤔。

后来只能我前端这边采用Nuxt2重构为SSR服务端渲染项目,Nuxt2是从零开始,一点点学习然后上手从小到大解决了很多问题,项目底层的架构及封装也比之前vue-cli3构建的单页面项目更完善健壮,开发周期差不多耗时3个月,后续则是根据运营同事的使用反馈来优化各种小问题,从重构开发完毕并经过北京公司的运营同事测试使用后,在同年10月份正式上线更新替代掉老官网,其后一直没有影响到百度爬虫收录,后来又和java同事配合做了一些百度爬虫的优化方案,新增了很多收录,可以说这种方案比较完美的迭代了以前的老官网😎。

此篇文章在此记录整理,本人从19年开始上手使用Nuxt2以后,开发产品的过程中,针对项目中业务需求所遇到的各种难点、API问题、BUG、及教程整理(不定时更新)😁

PS:当时还跳了挺多坑的🤣

正文

1、掘金上有一些很不错的Nuxt教程文章,推荐几篇:

juejin.im/post/58ff96… juejin.im/post/5bd3fb… juejin.im/post/5cc81e…

2、在使用window对象时,页面有时会报错window is not defined,解决方法:

//用process.client判断是否客户端,包着window对象的代码就行
if (process.client) {
}

3、asyncData、fetch、validate使用范围:

只能在页面组件使用,即pages目录下的组件,components目录下的公共组件不可以使用这两个生命周期方法,参考:zh.nuxtjs.org/api/。

如果页面模块很多,比如拿之前vue2单页面应用的项目举例,这个是之前公司的门户官网,18年从jQuery重构为Vue2,然后19年初使用Nuxt2重构为服务端渲染。

拿views目录下的首页homepage目录举例(参考下图1),首页按业务功能模块分为7个vue子组件,如果在刚开始开发时,简单的Ctrl c - Ctrl v把vue2项目的该文件夹,照搬过去Nuxt项目的文件夹,肯定是不行的。

那这个7个子组件只能放到Nuxt项目的根目录下的components目录里(参考下图2),然后在pages目录下的homePage.vue父组件里引入这7个子组件。并且这些子组件从接口获取的数据必须要在asyncData、fetch这两个生命周期里写入。那么这种情况下,只能在pages目录下的homePage.vue(首页的父组件)的asyncData、fetch这两个生命周期里获取好动态数据,并通过props或vuex传给子组件,业务模块子组件拿到父组件传递过来的数据后进行处理渲染。

这样操作下来,整个首屏渲染页面在查看网页源代码时,各个业务模块子组件的DOM结构都是正常插入动态数据了,那么SEO爬虫就可以正常爬取到,同理,其他页面的重构思路都是一样的操作。

图1:

3095530314-5d283083b1532_fix732.jpeg

图2:

901780393-5d283127b66fa_fix732.jpeg

4、该问题的场景是,比如拿新闻详情页举例:NewsDetails/newsId,newsId在改变时,vue底层会“机智的”认为页面路由不需要动态更新,所以newsId在改变后,该详情页的数据还是上一条newsId的老数据😂。

vue-cli创建的项目,即客户端渲染,在详情页类型的文章页面中,如果右侧列表有同类型的文章,那么在点击跳转路由时,需要用到beforeRouteUpdate,判断from来源是不是本路由,是的话则把详情id更新为to路由对象里的id即可,参考Vue Router官方文档:router.vuejs.org/zh/guide/ad…

解决思路有两条,①是详情页watch监听newsId然后异步请求详情接口,②是用组件路由守卫beforeRouteUpdate

//我的代码是这样
beforeRouteUpdate(to, from, next){
    next();
    // console.log(to, from, next)

    if(from.path.indexOf('NewsDetails') != -1){
        this.newsId = to.params.newsId;
        //更新新闻资讯详情数据
        this.getNewsDetailsData();
    }
},

而Nuxt服务端渲染的项目,当时我写到这个页面时,发现不会有这种问题,页面可以正常异步更新详情接口,并展示正确的最新数据。

5、报错:Computed property "xxx(此处是vuex state的一个变量名)" was assigned to but it has no setter.

是因为vuex是单项流,v-model是双向绑定。 我这个报错的业务场景是,公共组件login、register的modal框,控制是否显示隐藏,我的项目使用的是antD vue UI组件库,modal组件的参数由 v-model="loginModalShow" 改为 :visible="loginModalShow"即可解决报错。

6、也可以像vue-cli项目一样,在plugin目录下新建route.js文件,在这里配置全局守卫,然后在nuxt.config.js里的plugins引入好就可以生效了。

参考下图。

3067366651-5d2856a557d8a_fix732.jpeg

4261475058-5d2856d6e5403_fix732.jpeg

Oops! ~~ Nuxt3要来啦,像Vue3一样底层是ts,之后抽时间还得卷起来学习啦😂😂😂