上一篇讲了ssr的项目从零开始搭建和静态的数据渲染,这一篇探讨一下异步的数据如何通过服务端渲染,在浏览器输入url之后,直接就渲染出来(预拉去数据)。
demo代码地址:https://github.com/haolovewan/vue-ssr-demo
分析
上一篇我们渲染的静态数据是通过服务端renderer.renderToString方法返回给浏览器一个静态的html;如果我们的组件中有异步的ajax,在我们正常普通的项目中,一般会在mounted中或者在created中获取数据,然后浏览器加载js再去渲染的;这个时候就必须得等我们的js脚本加载完了才会有数据;那么在服务端渲染的话,就得提前把这个数据给拿到,返回给前端的html中,这个数据就已经是存在这个html中了;这一步是关键的一步,也是最重要的一步。
如何实现
1,在开始渲染之前,预先获取数据,把数据存在Vuex的store中,因为vue组件还没开始渲染
2,后端渲染的时候,通过Vuex把获取到的ajax数据注入到组件中;
3,把获取到的数据赋值给window.INITIAL_STATE,通过HTML传给浏览器;
4,浏览器通过Vuex将window.INITIAL_STATE里的数据注入到组件中;
疑问点:
- 后端已经把 Ajax 数据转化为 HTML 了,为什么还需要把 Ajax 数据通过 window.INITIAL_STATE 传递到前端?
这个我试过了不给context.state赋值stoe.state;window.INITIAL_STATE没有值页面也不会有问题😂;下面这个回答是在网上找的,没看懂是啥意思,有知道的大佬,可以在评论区留言告诉下小弟。
→ 因为前端渲染的时候仍然需要知道这些数据。举个例子,你写了一个组件,给它绑定了一个点击事件,点击的时候打印出 this.msg 字段值。现在后端是把组件 HTML 渲染出来了,但是事件的绑定肯定得由浏览器来完成啊,如果浏览器拿不到跟服务器端同样的数据的话,在触发组件的点击事件的时候,又上哪儿去找 msg 字段呢? - 为啥需要在组件中单独写一个asyncData() 方法触发ajax?
在服务端渲染的时候,需要提前拉去数据,再去渲染vue组件;此时vue的生命周期还没有执行;通过当前访问的路由,通过router匹配到对应的组件,找到组件中绑定的静态方法去获取ajax数据就好了;这个时候是没有this的,那么我们的数据存储的话就需要一个媒介容器;这个时候vuex就再好不过了,把数据存在store里,所以需要把store当参数传入到asyncData方法中。 - 搭的这个项目既可以ssr服务端渲染,又能正常的客户端渲染,当客户端渲染的时候页面报错?
image.png
这个错误的原因是,页面刷新后,不会调用router. beforeResolve()路由守卫方法;所以导致计算属性报错,因为这个守卫方法里面写了浏览器渲染ajax获取的异步数据。
查看官网后发现,官网给出了两套方案:
1.在路由导航之前解析数据
2.匹配要渲染的视图后,再获取数据
第一种就是一开始用的router. beforeResolve();网上有大佬说需要将这个方法放到router.onReady()方法外面,试过还是不行。所以后面尝试的第二种方式。官网地址 - vuex Store action 需要返回promise
因为在asyncData方法中触发的是store.dispatch方法,vuex-action是支持异步的,在预拉去数据的时候需要等待ajax数据返回后做后续的渲染操作。
总结
经过好几天的不懈努力,终于是把这个ssr搞定了,也没有对它有原先那么强的抗拒心理了,感觉还挺有意思的。而且搭的这个项目如果服务端渲染不行了,随时可以切换到客户端渲染;在写文章之前感觉自己懂了,但是在写文章的时候,真的是绞尽脑汁,虽然写了ssr写了两篇,感觉内容不是很丰富,或许还是自己没有真正的理解透这个东西,需要在后续的学习中继续深入研究;如果有大佬阅读到此,如有一些讲述的不对的地方,或者意思表达不清晰的地方,望大佬们在评论中指出,小弟也将及时的更正,谢谢大家~
参考:
网友评论