404 单页应用 报错 路由_大前端进阶-同构应用

概述

前端领域中,随着Vue,React,Angular等框架的流行,前端工程化、模块化成为了当下主流技术方案。这类框架构建的SPA单页应用具有用户体验好、渲染性能好、可维护性高等有点,但是也存在以下两个方面的问题:

  1. 首屏加载时间长

SPA应用采用客户端渲染,用户需要等待客户端js解析完成之后才能看到页面,这样会导致首屏加载时间变长,用户体验差。

  1. 不利于SEO

由于SPA应用采用客户端渲染,在js未完成解析之前,网站HTML是没有内容的,这样导致搜索引擎爬取站点HTML时获取不到内容。

为了解决这两个问题,业界提出了一种新的解决方案,如下图:

cc8398d088d3e45ab936325578011517.png

利用服务端渲染解决首屏加载慢和不利于SEO的缺陷,首屏渲染完成之后,客户端渲染接管页面重新成为单页应用以保证良好的用户体验。这种方式称为现代化服务端渲染方式或者同构渲染。

与传统服务端渲染区别

传统服务端渲染,如JSP可以总结为以下几步:

  1. 客户端发送请求
  2. 服务端根据请求查找模板并获取数据。
  3. 执行渲染
  4. 生成html返回客户端展示

这种传统服务端渲染方式,会存在以下缺点:

  1. 前后端完全耦合,不利于开发维护。
  2. 前端发挥空间小。
  3. 服务端压力大。
  4. 用户体验一般。

而同构渲染只是在首屏渲染的时候和传统服务端类似,都是返回渲染好的html页面,但是,同构渲染中,当客户端展示渲染好的html页面后,客户端渲染会接管页面的控制权,也就是后续的渲染都是由客户端进行的,这样可以保证良好的用户体验。

同构渲染缺点

与单页应用相比,由于首屏渲染采用的是服务端渲染,所以存在以下缺点:

  1. 开发条件有限,开发有限制(服务端只能使用nodejs,而且并不是所有的工具包都能在服务端渲染中使用)。
  2. 涉及构建和部署的要求高(需要部署客户端和服务端,不能再和单页应用一样,部署静态站点即可)。
  3. 更多的服务端负载。

Nuxt.js

Nuxt.js是基于vue技术栈的一种同构应用解决方案,它屏蔽了vuejs构建同构应用的难点。

基本使用

搭建nuxtjs同构应用相对比较简单,通过以下四步即可搭建最简单的同构应用:

  1. 创建项目文件夹。
  2. npm或者yarn安装nuxt。
  3. 添加pages文件夹并在其中添加index.vue文件。
  4. 执行npx nuxt。

基础路由

pages文件夹下存放所有的路由页面vue文件,nuxt会根据pages文件夹自动生成路由。

如pages目录如下:

pages/--| user/-----| index.vue-----| one.vue--| index.vue

那么nuxt会自动生成如下的路由结构:

router: {  routes: [    {      name: 'index',      path: '/',      component: 'pages/index.vue'    },    {      name: 'user',      path: '/user',      component: 'pages/user/index.vue'    },    {      name: 'user-one',      path: '/user/one',      component: 'pages/user/one.vue'    }  ]}

动态路由

nuxt在解析路由结构时,如果遇到以_为前缀的vue文件时,会将其定义为带参数的动态路由。

如下面的文件结构:

pages/--| _slug/-----| comments.vue-----| index.vue--| users/-----| _id.vue--| index.vue

生成的路由表为:

router: {  routes: [    {      name: 'index',      path: '/',      component: 'pages/index.vue'    },    {      name: 'users-id',      path: '/users/:id?',      component: 'pages/users/_id.vue'    },    {      name: 'slug',      path: '/:slug',      component: 'pages/_slug/index.vue'    },    {      name: 'slug-comments',      path: '/:slug/comments',      component: 'pages/_slug/comments.vue'    }  ]}

嵌套路由

在vuejs中,我们可以通过子路由实现路由的多层嵌套,同样在nuxtjs中,可以通过特殊的文件结构实现嵌套路由。

创建嵌套路由,需要添加一个Vue文件,同时添加一个与该文件名称相同的文件夹用于存放子路由组件(在Vue文件中需要添加类似route-view的nuxt-child节点。)

如下面的文件结构:

pages/--| users/-----| _id.vue-----| index.vue--| users.vue

生成的路由表如下:

router: {  routes: [    {      path: '/users',      component: 'pages/users.vue',      children: [        {          path: '',          component: 'pages/users/index.vue',          name: 'users'        },        {          path: ':id',          component: 'pages/users/_id.vue',          name: 'users-id'        }      ]    }  ]}

自定义路由

nuxtjs不仅可以通过pages文件夹结构自动生成路由表,同样提供了配置文件的方式配置自定义路由。

nuxtjs的配置文件和vue.config.js一样,在项目根目录下创建nuxt.config.js文件,此文件默认导出一个配置对象,配置对象有一个 router 属性,可以在此属性下配置自定义路由。

export default {    router: {        extendRoutes(routes, resolve) {            // 可以采用此方式清空默认生成的路由            // routes.splice(0)            routes.push(...[                {                    path: '/',                    component: resolve(__dirname, 'your.vue'),                }            ])        }    }}

模板

nuxtjs是基于html模板生成html文件的,我们可以在项目中修改此模板。

定制模板需要在项目根目录下创建app.html文件,默认的html结构如下:

      {{ HEAD }}        {{ APP }}  

我们可以在head中添加相应自定义的css、js引用。

asyncData

在vuejs项目中,某个组件如果想要从服务端获取数据,一般都会在created声明周期函数中发起请求。在同构应用中,如果想要页面内容能够SEO,那么就不能采用此方式。

在nuxt中为vue组件添加了asyncData方法,此方法会在服务端被执行,执行后的结果会被合并到当前组件的data对象中。

如下例,在服务端获取所有的文章和标签并渲染:

async asyncData() {    const [articleRes, tagRes] = await Promise.all([      getAllArticles({        offest: 0,        limit: 10,      }),      getAllTags(),    ])    const { articles, articlesCount } = articleRes.data    const { tags } = tagRes.data    return {      articles,      articlesCount,      tags,    }  }

需要注意的是,此方法虽然是vue组件的一个方法,但是由于其在服务端被调用,所以方法内部不能通过this对象获取vue实例,如果想要获取实例上的某些信息,可以用上下文对象。

上下文对象

asyncData方法包含一个参数context,context对象上包含路由等常用信息。

route: 当前路由对象store: store对象params, query: 路由参数req, res: 请求,响应对象redirect: 用于重定向

身份验证

在同构应用中,当用户登录之后,其身份信息需要在客户端和服务端都能够被获取到,因此可以将信息保存在cookie中。

客户端获取信息并存入cookie:

methods: {    onSubmit() {        let request = this.isLogin ? login : register        request(this.user)            .then(({ data }) => {                // 获取到用户信息                const { user } = data                if (user) {                    const Cookie = process.client ? require('js-cookie') : undefined                    // 将获取到的用户信息保存在cookie中                    Cookie.set('user', user)                    this.$store.commit('setUser', user)                }            })            .catch((err) => {            })    }}

服务端读取cookie并存入store供客户端使用:

在store的action中可以添加一个名称为 nuxtServerInit 的异步方法,该方法会在nuxt应用启动的时候被调用。

nuxtServerInit({ commit }, { req }) {    let user = null    if (req && req.headers.cookie) {        const cookieParser = process.server ? require('cookieparser') : undefined;        const parsed = cookieParser.parse(req.headers.cookie)        try {            user = JSON.parse(parsed.user)        } catch (err) {        }    }    commit('setUser', user)}

插件

如果想要在vuejs程序运行之前执行某些js操作,如注册第三方组件库,此时可以利用插件。

所有的插件全部放在plugins目录下,如果想要在nuxt应用中使用elementui组件库,可以在plugins文件夹下添加element-ui.js文件:

import Vue from 'vue'import Element from 'element-ui'import locale from 'element-ui/lib/locale/lang/en'Vue.use(Element, { locale })

然后在nuxt.config.js的plugins属性数组中添加相应文件路径:

plugins: [    '@/plugins/element-ui',]

之后,就可以在vue组件中正常使用element-ui。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值