最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
当前位置: 首页 - 科技 - 知识百科 - 正文

Nuxt.js实现一个SSR的前端博客的示例代码

来源:懂视网 责编:小采 时间:2020-11-27 21:51:03
文档

Nuxt.js实现一个SSR的前端博客的示例代码

Nuxt.js实现一个SSR的前端博客的示例代码:为什么要用Nuxt.js 公司现有的项目只有落地页是通过前端本身server读取pug文件进行服务端渲染的,当然是为了首屏加载速度以及SEO。Nuxt.js 是一个基于Vue.js的通用应用框架,预设了利用Vue.js开发服务端渲染的应用所需要的各种配置,只需要安装官方文档的要求
推荐度:
导读Nuxt.js实现一个SSR的前端博客的示例代码:为什么要用Nuxt.js 公司现有的项目只有落地页是通过前端本身server读取pug文件进行服务端渲染的,当然是为了首屏加载速度以及SEO。Nuxt.js 是一个基于Vue.js的通用应用框架,预设了利用Vue.js开发服务端渲染的应用所需要的各种配置,只需要安装官方文档的要求

为什么要用Nuxt.js

公司现有的项目只有落地页是通过前端本身server读取pug文件进行服务端渲染的,当然是为了首屏加载速度以及SEO。Nuxt.js 是一个基于Vue.js的通用应用框架,预设了利用Vue.js开发服务端渲染的应用所需要的各种配置,只需要安装官方文档的要求进行开发,就可以很好的解决SSR的问题。我们以一个简单的博客为例,来实践一下Nuxt.js。

项目介绍

当前基于Nuxt.js的简化版博客,包括注册、登录、文章列表页面、文章详情页、以及用户列表页等几个页面,用户信息使用了Vux进行存储,异步数据使用了asyncData进行获取,配合了nuxtServerInit、cookie来处理刷新页面后Vux数据丢失的问题,同时使用了error模板页面处理常规错误,使用了中间件进行了简单的权限校验。该项目不足点,统一封装了axios的方法,但是没有考虑到服务端请求接口,token的处理。

目录结构

  •  assets: 资源文件。用于组织未编译的静态资源如 LESS、SASS或 JavaScript。
  • components: 组件。
  • layouts: page: 模板页面,默认为 default.vue可以在这个目录下创建全局页面的统一布局,或是错误处理页面页,需要提供一个nuxt 标签,类似于router-view
  • middleware: 中间件,放置自定义的中间件,会在加载组件之前调用。可以在页面中调用: middleware: '中间件名称'。
  • pages: 页面,index.vue 为根页面,Nuxt.js 框架读取该目录下所有的 .vue文件并自动生成对应的路由配置,如需要动态参数id,则可以添加_id的文件,必须是下划线加参数名。
  • plugin: 插件,用于组织那些需要在 根Vue.js应用实例化之前需要运行的 Javascript 插件。
  • static: 静态文件,静态文件目录 static用于存放应用的静态文件,此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。
  • store: 用于组织vuex状态管理。具体使用请移步至 官网。
  • nuxt.config.js: nuxt.config.js文件用于组织Nuxt.js 应用的个性化配置,配置head,loading,css,plugins等。
  • Nuxt.js生命周期

    1. incoming Request 浏览器发出的请求)
    2. nuxtServerInit 服务端接受请求后,要检查当前有没有 nuxtServerInit配置项,如果有就执行这个函数
    3. store action 用来操作vuex
    4. middleware 可以做jWT等一些操作。
    5. validate() 检验参数,参数检验失败,可以在layout里的error里面进行捕捉。
    6. asyncData()& fetch() asyncData用来渲染组件,fetch用来渲染vuex
    7. Render

    Nuxt扩展以后的生命周期和方法以下:

    beforeCreate: ƒ beforeCreate()
    components: {NuxtLoading: {…}}
    computed: {isOffline: ƒ}
    context: {isStatic: false, isDev: true, isHMR: true, app: {…}, payload: undefined, …}
    created: ƒ created()
    data: ƒ data()
    head: {title: "nuxt-meituan-ssr", meta: Array(3), link: Array(1), style: Array(0), script: Array(0)}
    methods: {refreshOnlineStatus: ƒ, refresh: ƒ, errorChanged: ƒ, setLayout: ƒ, loadLayout: ƒ}
    mounted: ƒ mounted()
    nuxt: {…}
    render: ƒ render(h, props)
    router: VueRouter {app: Vue, apps: Array(1), options: {…}, beforeHooks: Array(2), resolveHooks: Array(0), …}
    watch: {nuxt.err: "errorChanged"}

    注意:

  • Vue.js生命周期的钩子只有beforeCreate和created会在服务端和客户端渲染。
  • 以上生命周期里都获取不到window对象。
  • asyncData和fetch我们可以拿到数据,不要尝试挂载数据到data上,此时获取不到this对象。
  • 开发总结

    如何修改默认启动端口?

    可以在package.json下面修改配置,如下。

    "config":{
     "nuxt":{
     "host":"127.0.0.1",
     "port":"3304"
     }
    }

    如何添加全局的样式?

    可以在assets里添加全局Css文件,如在assets下的Css文件夹目录下添加了一个index.css文件,然后在nuxt-config.js里配置该css文件路径即可。 css:['~assers/css/index.css']

    通过别名访问图片在template里是正确的,为何在Css设置背景图却报错?

    在css配置的是,需要将'~/'后面的'/'去除掉。

     <img src="~/static/logo.jpg"/> 
     backround-image:url('~static/logo.jpg');

    如何添加路由动画?

    同样,我们在Css文件里添加一些动画代码,一般样式会在其后面添加-active和-leave-active,其实和Vue动画形式一致。其中以page开头的动画,默认会作用于全部页面,如果想给特定的页面加动画,可以在对应的页面script里引用,如 transitions: 'bounce'即可。

    .page-enter-active, .page-leave-active {
     transition: opacity .3s
     }
     .page-enter, .page-leave-active {
     opacity: 0
     }
     .bounce-enter-active {
     animation: bounce-in .8s;
     }
     .bounce-leave-active {
     animation: bounce-out .5s;
     }
     @keyframes bounce-in {
     0% { transform: scale(1) }
     50% { transform: scale(1.01) }
     100% { transform: scale(1) }
     }
     @keyframes bounce-out {
     0% { transform: scale(1) }
     50% { transform: scale(1.01) }
     100% { transform: scale(1) }
     }

    路由参数如何传递?

    同Vue-router,有声明式和编程式两种方式,无非是标签变成了 router.push(...)

     nuxt-link :to="{name:'article',params:{id:1234}}" >声明式</nuxt-link>
     // 编程式
     this.$router.push({
     name:'article',
     params:{
     id:1234
     }
     })

    动态路由如何进行参数检验?

    Nuxt.js提供了一个validate的生命周期钩子,可以在此进行参数的校验。以文章详情校验id为例,我们需要判断传入的id是否是数字,可以像下面这样处理。

     validate({ params }) {
     return /^\d+$/.test(params.id)
     }

    如何添加404等错误页面?

    可以在layout下新建一个error.vue页面,内容如下,当访问一个不存在的页面的时候,或者参数检验失败的时候,或者我们在middleware中间件处理抛出异常的时候,都会跳转到该页面。

    <template>
     <div class="container">
     <h1 v-if="error.statusCode === 404">页面不存在</h1>
     <h1 v-else>应用发生错误异常</h1>
     <nuxt-link to="/">首 页</nuxt-link>
     </div>
    </template>
    
    <script>
    export default {
     props: ['error'],
     layout: 'blog' // 指定模板页面
    }
    </script>

    middleware中的文件抛出错误

    export default function({ store, error, redirect }) {
     if (!store.state.user.userInfo.auth) {
     error({
     message: '没有权限哦!',
     statusCode: 403
     })
     }
    }

    顶部进度条如何设置?

    loading 属性配置 可以在nuxt-config.js设置loading的颜色,使用了this. loading可能无法在created里立即使用。此种配置loading有严重的缺陷,无法知道真正的加载进度。也可以自定义加载组件,loading: '~components/loading.vue'。

    export default {
     mounted () {
     this.$nextTick(() => {
     this.$nuxt.$loading.start()
     setTimeout(() => this.$nuxt.$loading.finish(), 500)
     })
     }
     }

    异步数据如何获取?

    Nuxt.js提供了两个函数,asyncData和fetch函数。asyncData 获取组件的数据,fetch 在渲染页面之前获取数据填充应用的状态树(store)。

    asyncData可以使用promise也可以使用async函数,记住,此时返回的东西需要用一个对象进行包裹,不能挂载到data里,此时没有this对象。

    // 方式一
     asyncData({ app,params,route,query,error}) {
     return getUserlist({}).then(res => {
     let user = [];
     user = res.list
     console.log(user,'user')
     return {user}
     })
     .catch(err => {
     console.log(err)
     })
    },
    
    // 方式二
    async asyncData({ app }) {
     let data = await getUserlist({});
     let user = data.list;
     return { user }
    }

    fetch函数同上,可以使用promise也可以使用async函数,通常会commit一个mutation。

    export default {
     fetch ({ store, params }) {
     return axios.get('http://my-api/stars')
     .then((res) => {
     store.commit('setStars', res.data)
     })
     }
    }
    </script>
    // 或者使用 async 或 await 的模式简化代码如下:
    <template>
     <h1>Stars: {{ $store.state.stars }}</h1>
    </template>
    
    <script>
    export default {
     async fetch ({ store, params }) {
     let { data } = await axios.get('http://my-api/stars')
     store.commit('setStars', data)
     }
    }
    </script>

    如何动态修改title的内容?

    如果是写死的,可以直接修改head的配置。

     head() {
     return {
     // title: '',这里一旦声明,在asyncdata里修改也不起作用,直接以这个为准
     meta: [
     {
     hid: 'description', // nuxt.config 替换唯一标识 hid { hid: 'description', name: 'description', content: 'Nuxt.js project' }
     name: 'content',
     content: '文章详情'
     }
     ]
     }
     },

    如果是动态数据从数据源里获取,然后通过asynData里的app对象,动态修改head的title。

     asyncData({ app, params }) {
     const id = params.id;
     return getArticleDetail({ id })
     .then(result => {
     app.head.title = result.title;
     })
     .catch(err => {})
     }

    如何进行权限JWT验证?

    登录成功以后,我们会在cookie和Vuex中缓存token信息,当界面刷新的时候,会走store里的nuxtServerInit 函数,该函数仅在每个服务器端渲染中运,可以使用req.headers.cookie获取浏览器的cookie,再次更新store里的值,接着会走到中间件,中间件进行验证,如果有token信息则继续,没有则跳转到登录页。
    1. 为什么要在nuxtServerInit更新store的值?
    需要在middleware里使用,否则刷新后store里的值为空了。
    2. 客户端调用接口可以拿到token,服务器端如何拿到?
    可以通过nuxtServerInit里的req拿到请求信息的cookie,然后请求接口。
    3. 前后端分离,刷新的时候如何保证用户名、token等信息依然存在?
    可以像上面一样,每次取cookie的值再次更新store,但这样有一个问题,cookie可能会被篡改,后端代码需要做验证。也可以每次刷新重新通过token请求接口,更新用户信息。

    store代码

    import Vue from 'vue';
    import Vuex from 'vuex';
    import user from './modules/user';
    import { COOKIE_KEY } from '~/assets/js/constant.js';
    Vue.use(Vuex);
    const store = () =>
     new Vuex.Store({
     modules: {
     user
     },
     actions: {
     async nuxtServerInit({ commit, dispatch }, { req, app }) {
     if (req.headers.cookie) {
     let parsedResult = {};
     req.headers.cookie.split(';').forEach(cookie => {
     const currentCookie = cookie.split('=');
     parsedResult[currentCookie[0].trim()] = (currentCookie[1] || '').trim();
     });
     const userInfo = {
     name: parsedResult[COOKIE_KEY.NAME],
     token: parsedResult[COOKIE_KEY.TOKEN]
     };
     commit('user/setUserInfo',userInfo);
     }
     }
     }
     });
    
    export default store;

    中间件代码

    export default function({ store, error, redirect }) {
     if (!store.state.user.userInfo.token || !store.state.user.userInfo.name) {
     // error({
     // message: 'You are not connected',
     // statusCode: 403
     // })
     redirect('/');
     }
    }

    nginx部署

     npm run build
    选择build以后的四个文件: .nuxt, static, nuxt.config.js, package.json上传到服务器。
    pm2 pm2 start npm --name 'package.json.name' -- run start
    nginx配置

    查看网页源代码可以看到:

     server{
     listen 3000;
     server_name felix12345.club; 
     gzip on;
     gzip_buffers 32 4K;
     gzip_comp_level 6;
     gzip_min_length 100;
     gzip_types application/javascript text/css text/xml;
     gzip_disable "MSIE [1-6]\."; 
     gzip_vary on;
     proxy_buffer_size 64k;
     proxy_buffers 32 32k;
     proxy_busy_buffers_size 128k;
     location / {
     root /data/ww/nuxt;
     proxy_pass http://127.0.0.1:3002;
     proxy_set_header X-Real-IP $remote_addr;
     }
     }

    这样,使用Nuxt.js实现了一个服务端渲染的简易博客。

    在线访问地址: http://felix12345.club:3000/article/

    声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文档

    Nuxt.js实现一个SSR的前端博客的示例代码

    Nuxt.js实现一个SSR的前端博客的示例代码:为什么要用Nuxt.js 公司现有的项目只有落地页是通过前端本身server读取pug文件进行服务端渲染的,当然是为了首屏加载速度以及SEO。Nuxt.js 是一个基于Vue.js的通用应用框架,预设了利用Vue.js开发服务端渲染的应用所需要的各种配置,只需要安装官方文档的要求
    推荐度:
    标签: ssr 博客 blog
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top