nuxt3+ts+vue3的ssr项目总结

目录

一、什么是SSR、SEO、SPA,它们之间的关系又是怎样的。

二、VUE做SSR的几种方法

1、插件prerender-spa-plugin

2、VUE开启SSR渲染模式

3、使用NUXT框架 

三、NUXT3+VUE3+TS

(一)基本配置

1、文件夹介绍

assets

components

pages

api

plugins

utils 

2、布局使用

3、useFetch请求封装

(二)引入element-pluse

1、安装

2、引入

3、使用

(三)引入md文档

1、下载

2、引入

3、使用

用于输入数据

用于回显数据

(四)v-show与v-if踩坑

1、区别

2、问题

(五)el- select与el-tooltip踩坑

1、问题


一、什么是SSR、SEO、SPA,它们之间的关系又是怎样的。

SSR (Server-Side Rendering)服务器端渲染,是一种网页渲染方法,其中服务器在向客户端发送 HTML 之前将页面渲染为完全呈现的 HTML。在 SSR 中,服务器会处理页面的渲染,然后将呈现的 HTML 发送到客户端浏览器,浏览器接收到的是已经包含内容的页面。这有助于搜索引擎更好地索引页面内容,提高首次加载速度,以及有助于 SEO(搜索引擎优化)。

SEO (Search Engine Optimization)搜索引擎优化,是一系列技术和策略,旨在改进网站在搜索引擎结果页面上的排名,以增加网站的曝光度和访问量。在网站的 SEO 中,内容的可索引性、关键词的使用、页面速度和用户体验等都是重要因素。

SPA (Single Page Application)单页面应用,是一种基于 Web 的应用程序,它在加载初始页面后,通过 AJAX 或其他技术在同一个页面上动态加载内容,而不需要完整的页面刷新。SPA 通常在客户端使用 JavaScript 处理页面路由和渲染。SPA 的优点包括更流畅的用户体验,但它可能对搜索引擎索引和首次加载速度产生挑战。

SSR 和 SEO:SSR 通过在服务器端将完全呈现的 HTML 发送到客户端,有助于提高页面在搜索引擎中的可索引性。搜索引擎可以更容易地读取和理解页面内容,从而提高 SEO。相比之下,SPA 在初次加载时可能只有一个空的 HTML 骨架,内容是通过 JavaScript 动态加载的,这可能对 SEO 造成挑战。

SSR 和 SPA:SSR 和 SPA 是两种不同的页面渲染方法。SSR 在服务器端完成渲染,可以提供更好的 SEO 和首次加载性能,但也可能增加服务器负担。SPA 在客户端动态加载内容,提供更流畅的用户体验,但可能面临搜索引擎索引和初始加载速度的问题。一些项目结合两者,使用 SSR 渲染首次加载的内容,然后在后续页面切换时转为 SPA。

想了解更多关于ssr,seo,spa的知识可以看下面这篇文章:

浅谈SPA、SEO、SSR - 简书前后端分离算是最近Web开发的大趋势了,目前已经有大量的公司使用了前后端分离的开发方式。那我们就来大概谈谈前后端分离开发中必须要了解和接触的几个概念:SPA、SEO和SSR。...icon-default.png?t=N7T8https://www.jianshu.com/p/fcb98533bc18

二、VUE做SSR的几种方法

1、插件prerender-spa-plugin

prerender-spa-plugin 是一个用于预渲染单页面应用(SPA)的插件,它可以帮助你在构建时生成静态 HTML 文件,以优化搜索引擎索引和首次加载性能。它需要搭配webpack进行使用,并且改插件有局限性,只能用于较少页面的渲染,一旦渲染的较多负载会非常大,且不适用动态平衡路由的渲染。如商品详情页,文章详情页等等。且该项目已经停止更新了,请谨慎使用。

prerender-spa-plugin官网:GitHub - chrisvfritz/prerender-spa-plugin: Prerenders static HTML in a single-page application.Prerenders static HTML in a single-page application. - GitHub - chrisvfritz/prerender-spa-plugin: Prerenders static HTML in a single-page application.icon-default.png?t=N7T8https://github.com/chrisvfritz/prerender-spa-plugin

这里推荐一篇prerender-spa-plugin详细使用文章:

https://www.cnblogs.com/chuaWeb/p/prerender-plugin.htmlicon-default.png?t=N7T8https://www.cnblogs.com/chuaWeb/p/prerender-plugin.html写的非常详细。


2、VUE开启SSR渲染模式

Vue.js 的服务器端渲染(SSR)通过创建一个服务器入口文件来处理客户端请求,使用 createApp 函数创建 Vue 应用实例并配置路由,根据请求的 URL 匹配路由并预取数据,使用 renderToString 方法将应用渲染为完全呈现的 HTML 字符串,然后将渲染后的 HTML 和状态数据作为响应返回给客户端,客户端接管渲染过的 HTML 并激活应用。从而实现更好的搜索引擎优化、更快的首次加载速度以及服务器和客户端之间更一致的行为。但这个方案也被pass掉了,因为项目过于老,且代码很乱。各种冲突版本兼容问题层出不穷因此也放弃了。但这应该是在节省成本的方法中最适合的一个方案了。

Vue.js 的服务器端渲染(SSR)官网:

Vue.js 服务器端渲染指南 | Vue SSR 指南Vue.js 服务端渲染指南icon-default.png?t=N7T8https://v2.ssr.vuejs.org/zh/这里附带一篇我认为写的较好的博主的文章,大家可以借鉴一下:

如何在vue中实现SSR服务端渲染? - 掘金SSR意为服务端渲染,指由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可icon-default.png?t=N7T8https://juejin.cn/post/7063795725296992270

3、使用NUXT框架 

官网:介绍 · 开始使用Nuxt3 Nuxt中文站Nuxt的目标是使web开发直观和性能与伟大的DX铭记在心。icon-default.png?t=N7T8https://nuxt.com.cn/docs/getting-started/introduction

接下里来我将对NUXT的一些基本使用与踩坑展开描述。

三、NUXT3+VUE3+TS

首先这里默认你已经安装了NUXT3,如果不会的话,请移步至官网文档,就一个命令的事。(注意:node版本要大于16.11.0)

(一)基本配置

1、文件夹介绍

assets

在根目录文件下创建一个名为assets的文件夹用于存储静态文件。如图所示,可以将css文件,图片文件,svg文件包括iconfont字体等文件都存储在这里。

⚠️:这是官方约定俗成的东西。

components

一般用于存储封装好的通用组件。

pages

存放页面的文件夹

 

api

存放网络请求

 

plugins

存放各类插件。

utils 

存放各类工具。

2、布局使用

首先新建一个 layouts 文件夹,写入 default.vue 文件。

 找到 app.vue 文件添加 NuxtLayout 标签。

运行效果:

 

3、useFetch请求封装

首先在根目录下新建一个文件夹 service ,并新建一个文件 index.ts

添加代码如下:

import { UseFetchOptions } from "nuxt/app";type Methods = "GET" | "POST" | "DELETE" | "PUT";const BASE_URL = "https://xxx.com/";export interface IResultData<T> {code: number;data: T;msg: string;
}class HttpRequest {request<T = any>(url: string,method: Methods,data: any,options?: UseFetchOptions<T>,) {return new Promise((resolve, reject) => {const newOptions: UseFetchOptions<T> = {baseURL: BASE_URL,method: method,...options,};if (method === "GET" || method === "DELETE") {newOptions.params = data;}if (method === "POST" || method === "PUT") {newOptions.body = data;}useFetch(url, newOptions).then((res) => {resolve(res.data);}).catch((error) => {reject(error);});});}// 封装常用方法get<T = any>(url: string, params?: any, options?: UseFetchOptions<T>) {return this.request(url, "GET", params, options);}post<T = any>(url: string, data: any, options?: UseFetchOptions<T>) {return this.request(url, "POST", data, options);}Put<T = any>(url: string, data: any, options?: UseFetchOptions<T>) {return this.request(url, "PUT", data, options);}Delete<T = any>(url: string, params: any, options?: UseFetchOptions<T>) {return this.request(url, "DELETE", params, options);}
}const httpRequest = new HttpRequest();export default httpRequest;

再在根目录下新建一个 api 文件夹,新建文件index。在这里引入并定义接口,以便于接口的统一处理。

import httpRequest from "~/service";const getAppdetail = (params: any) => {const URL = `/app-server/marketui/${params.marketID}/apps/${params.appID}/detail`return httpRequest.get(URL, params);
};export {getAppdetail,
};

使用如下:

<template>这是主页面的内容
</template><script setup lang="ts">
import { ref } from 'vue';
import { getAppdetail } from '../api/index';
let marketID = ref<string>('859a51f9bb3b48b5bfd222e3bef56425');
let appID = ref<string>('10d2295fc98d4163acc4b2ec9d2917b9');
let getAppdetailData = async () => {let Appdetail: any = await getAppdetail({marketID: marketID.value,appID: appID.value,});console.log(JSON.parse(JSON.stringify(Appdetail.value)));
};
getAppdetailData()
</script>
<style  scoped>
</style>

请求成功: 

        

(二)引入element-pluse

1、安装

安装element-pluse

npm install element-plus --save

官网文档:

Button 按钮 | Element Plusa Vue 3 based component library for designers and developersicon-default.png?t=N7T8https://element-plus.org/zh-CN/component/button.html 

2、引入

在 根目录创建 plugins 文件夹 ,新建一个名为 element-plus.js 的文件,并添加如下文件内容。

import { defineNuxtPlugin } from '#app'
import ElementPlus from 'element-plus'
import { ID_INJECTION_KEY } from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'import 'element-plus/dist/index.css'
export default defineNuxtPlugin(nuxtApp => {nuxtApp.vueApp.use(ElementPlus, {locale: zhCn,})nuxtApp.vueApp.provide(ID_INJECTION_KEY, {prefix: 100,current: 0,})
})

 大功告成就可以使用了。

3、使用

我们更改一下about页面的代码。

运行效果: 

(三)引入md文档

⚠️:此插件使用时需要搭配 <ClientOnly></ClientOnly> 或者 <no-ssr></no-ssr> 使用,否则会报错,因为在服务端获取不到顶级的window对象。 

1、下载

命令

npm install mavon-editor --save

GitHub:

GitHub - hinesboy/mavonEditor: mavonEditor - A markdown editor based on Vue that supports a variety of personalized featuresmavonEditor - A markdown editor based on Vue that supports a variety of personalized features - GitHub - hinesboy/mavonEditor: mavonEditor - A markdown editor based on Vue that supports a variety of personalized featuresicon-default.png?t=N7T8https://github.com/hinesboy/mavonEditor 

2、引入

在 根目录创建 plugins 文件夹 ,新建一个名为 vue-mavon-editor.js 的文件,并添加如下文件内容。

import { defineNuxtPlugin } from '#app'
import mavonEditor from 'mavon-editor'
import "mavon-editor/dist/css/index.css";export default defineNuxtPlugin( nuxtApp => {nuxtApp.vueApp.use(mavonEditor)
})

nuxt.config.ts 中添加如下代码。 

export default defineNuxtConfig({//其他配置plugins: [{ src: '@/plugins/vue-mavon-editor.js', ssr: false, mode: 'client' },],
})

3、使用

用于输入数据

这次我们更改 home 文件夹下的 index.vue

<template><h1>这是home页面</h1><ClientOnly><mavon-editorref="md"placeholder="请输入文档内容...":boxShadow="false"style="z-index:1;border: 1px solid #d9d9d9;height:50vh"v-model="value":toolbars="toolbars"/></ClientOnly></template><script setup lang="ts">
import { ref } from 'vue';
let value = ref<string>('**这是加粗的文字**');
let toolbars = ref<any>({bold: true, // 粗体italic: true, // 斜体header: true, // 标题underline: true, // 下划线strikethrough: true, // 中划线mark: true, // 标记superscript: true, // 上角标subscript: true, // 下角标quote: true, // 引用ol: true, // 有序列表ul: true, // 无序列表link: true, // 链接imagelink: true, // 图片链接code: true, // codetable: true, // 表格fullscreen: true, // 全屏编辑readmodel: true, // 沉浸式阅读htmlcode: true, // 展示html源码help: true, // 帮助/* 1.3.5 */undo: true, // 上一步redo: true, // 下一步trash: true, // 清空save: false, // 保存(触发events中的save事件)/* 1.4.2 */navigation: true, // 导航目录/* 2.1.8 */alignleft: true, // 左对齐aligncenter: true, // 居中alignright: true, // 右对齐/* 2.2.1 */subfield: true, // 单双栏模式preview: true // 预览})
</script>
<style  scoped>
</style>

 效果如图:

用于回显数据

<template><h1>这是home页面</h1><ClientOnly><mavon-editorref="md"v-highlight class="md" v-model="value" //引入要转换的内容:subfield="false"//开启单栏模式       :defaultOpen="'preview'" //开启单栏模式:toolbarsFlag="false" //开启单栏模式:editable="false"//开启单栏模式 :scrollStyle="true"//开启滚动条样式/></ClientOnly></template><script setup lang="ts">
import { ref } from 'vue';let value = ref<string>('**这是加粗的文字**');
</script>
<style  scoped>
</style>

(四)v-show与v-if踩坑

1、区别

  1. 渲染方式的区别

    • v-if:当条件为真时,元素会被渲染到DOM中;当条件为假时,元素会被完全从DOM中移除。
    • v-show:无论条件是真还是假,元素都会被渲染到DOM中,但是通过设置元素的display属性来控制是否显示在页面上。
  2. 初始渲染性能

    • v-if:在初始渲染时,如果条件为假,元素不会被添加到DOM中,因此可以提高初始加载性能。
    • v-show:无论条件如何,元素都会被添加到DOM中,只是通过CSS的display属性来控制显示与隐藏,因此初始加载性能上稍逊于v-if
  3. 切换开销

    • v-if:当条件从假切换到真时,会进行DOM插入操作,从真切换到假时,会进行DOM移除操作,可能涉及更多的DOM操作开销。
    • v-show:无论切换条件如何,只需操作CSS属性,因此切换时的性能开销较小。
  4. 适用场景

    • v-if:适合在条件不经常改变的情况下使用,因为它在切换时有更高的开销。
    • v-show:适合在条件需要经常改变的情况下使用,因为它的切换开销较小。

2、问题

使用v-show可能会导致文件加载错误,或者模块渲染失败。比如在这段代码中:

<div class="tag_box" v-if="parentNode"><div class="tag_icon"><img class="helm_icon" src="../../../assets/svg/tag-type.svg" alt="" /></div><div class="tag_name">{{ parentNode }}</div>
</div>

我的img文件中指向的是静态文件中的一个icon图标。

当我使用v-if时,正常展示。

 当我使用v-show时,展示就出现了问题。

目前不清楚是为何导致的但需要注意这一点。 

(五)el- select与el-tooltip踩坑

1、问题

可以详见这个issues。https://github.com/element-plus/element-plus/issues/9414icon-default.png?t=N7T8https://github.com/element-plus/element-plus/issues/9414

总的来说就是使用 el- select 与 el-tooltip 的地方会导致渲染出现问题,比如这里。

    <!-- 导航栏 --><!-- <no-ssr> --><nav class="navbar"><div class="navbar-box"><div style="font-size: 24px">云原生应用市场</div><div><ul><li><a :href="`/docs`" target="_blank"> 文档 </a></li><li><el-popover :width="160" placement="bottom" trigger="hover"><template #default><div><imgclass="wechart":src="marketInfo &&marketInfo.banners &&marketInfo.banners.length > 0 &&marketInfo.banners[0].imageURL"alt=""/><pstyle="font-size: 12px;margin-bottom: 0px;margin-top: 6px;text-align: center;">扫一扫,邀你进群交流吧</p></div></template><template #reference>加入群聊</template></el-popover></li><li><a :href="`/enterprise/login`"> 登录 </a></li></ul></div></div></nav><!-- </no-ssr> -->

运行效果:

 

可以看到,我这里点击跳转以后地址栏发生了变化,但是页面并没有跳过去,而且控制台也报错。Uncaught (in promise) TypeError: Cannot read properties of null (reading 'parentNode') 

 解决方法

使用 <no-ssr></no-ssr> 把对应的 el- select与el-tooltip 包裹住,让这一小段代码不使用ssr渲染,从上面的issues也可以看到这是element plus的一个bug,但是截止到目前仍未修复。

总结:坑还是挺多的,而且很多问题虽然解决了但不知道是为什么(有知道为什么的大佬如果您不嫌弃的话麻烦给我讲解一下),因为这个玩意已经加了两周多的班了,终于捋出来一些头绪了。终于也是快接近尾声了。seo优化这个词也终于从我的面试八股文中走了出来真真切切的体验了一把,虽然过程很艰难,但好在最难的时刻已经过去啦。加油加油各位!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/60122.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT 界面相关操作

1> 创建自定义类时需要指定父类 2> 第一个界面的相关操作 #include "widget.h" #include<iostream> //printf #include<QDebug> //qDebuf #include<QIcon> //图标的头文件 using namespace std; //coutWidget::Widget(QWidget *…

1.RTKLIB环境配置和调试

1.源码下载 下载链接&#xff1a;rtklib 注&#xff1a;2.4.2 p13为稳定版本&#xff08;标识p代表稳定版本&#xff09;&#xff0c;2.4.3 b34为最新实验版本&#xff08;标识b&#xff09;。点击2.4.3 b34 的Source Programs and Data 链接下载源码。 2.环境配置 **集成…

尚硅谷SpringMVC

五、域对象共享数据 1、使用ServletAPI向request域对象共享数据 首页&#xff1a; Controller public class TestController {RequestMapping("/")public String index(){return "index";} } <!DOCTYPE html> <html lang"en" xmln…

【ACM出版】第四届人工智能与计算工程国际学术会议(ICAICE 2023)

ACM出版|第四届人工智能与计算工程国际学术会议 The 4th International Conference on Artificial Intelligence and Computer Engineering 为了在人工智能技术应用与计算工程领域进一步的探索&#xff0c;与国内外学界和业界相关人员交流新问题、新发现、新成果、新应用&…

eureka迁移到nacos--双服务中心注册

服务注册中心的迁移有多种方式&#xff0c;官网使用nacos sync&#xff0c;还有民间开发的双注册中心组件eureka-nacos-proxy&#xff0c;但是我用了不太顺利&#xff0c;所以用的是阿里巴巴的双注册中心组件edas-sc-migration-starter spring boot&#xff1a;2.5.3 引入依赖 …

Springboot集成Docker并将镜像推送linux服务器

案例使用springboot项目&#xff0c;在IDEA 中集成Docker生成镜像&#xff0c;并将镜像发布到linux服务器 具体步骤如下&#xff1a; 1、Centos7安装Docker 更新系统的软件包列表 sudo yum update安装Docker所需的软件包和依赖项&#xff1a; sudo yum install docker完成…

华为OD机试 - 数字序列比大小 - 贪心算法(Java 2023 B卷 100分)

目录 一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 一、题目描述 A&#xff0c;B两个人万一个数字比大小的游戏&#xff0c;在游戏前&#xff0c;两个人会拿…

Linux 内核动态打印调试(dev_info、 dev_dbg )

目录 前言 1 printk消息级别 2 调整内核printk打印级别 3 dev_xxx函数简介 4 配置内核使用动态打印 5 动态调试使用方法 6 动态打印调试的基本原理 &#x1f388;个人主页&#x1f388;&#xff1a;linux_嵌入式大师之路的博客-CSDN博客&#x1f389;&#x1f389;&…

xss-labs靶场通关详解

文章目录 前言level1level2level3level4level5level6level7level8level9level10level11level12level13level14level15level16level17level18level19&level20 前言 赶着假期结尾的时候&#xff0c;赶紧给自己找点任务做。现在对xss还是一知半解&#xff0c;只是了解个大概&a…

Java seven 解读正则表达式、java方法的使用

目录 Java 正则表达式1. java.util.regex 包2. 捕获组3. 正则表达式语法4. Matcher 类的方法 Java 方法1. 定义&#xff1a;2. 优点3. 命名规则4. 方法调用5. 方法的重载6. 构造方法7. 可变参数8. finalize() 方法 Java 正则表达式 1. java.util.regex 包 Pattern 类&#xff…

自用Eclipse配置记录

喜欢用eclipse写代码&#xff0c;由于现在的eclipse配置导出的功能缺失较多。这里开一帖把本人常用的配置记录一番&#xff0c;省得再到处找。 另&#xff1a;工作空间中有个.metadata 目录保存了相关的插件及配置&#xff0c;可以复制到其他空工作间中复用配置。 设置工作空间…

Unity碰撞检测

Unity碰撞检测 前言准备材料代码使用OnCollisionEnter()进行碰撞Collider状态代码 使用OnTriggerEnter()进行碰撞Collider状态代码 区别代码OnCollisionEnter()OnTriggerEnter() 碰撞显示效果OnCollisionEnter()OnTriggerEnter() 提示结语 前言 碰撞检测可以说时学习Unity中最…

ChatGPT⼊门到精通(5):ChatGPT 和Claude区别

⼀、Claude介绍 Claude是Anthropic开发的⼀款⼈⼯智能助⼿。 官⽅⽹站&#xff1a; ⼆、Claude能做什么 它可以通过⾃然语⾔与您进⾏交互,理解您的问题并作出回复。Claude的主要功能包括: 1、问答功能 Claude可以解答⼴泛的常识问题与知识问题。⽆论是历史上的某个事件,理科…

k8s之存储篇---数据卷Volume

数据卷概述 Kubernetes Volume&#xff08;数据卷&#xff09;主要解决了如下两方面问题&#xff1a; 数据持久性&#xff1a;通常情况下&#xff0c;容器运行起来之后&#xff0c;写入到其文件系统的文件暂时性的。当容器崩溃后&#xff0c;kubelet 将会重启该容器&#xff…

Javaweb入门

Spring Spring发展到今天已经形成一种开发生态圈&#xff0c;Spring提供若干个子项目&#xff0c;每个项目用于完成特定的功能。 Spring Boot可以帮助我们非常快速的构建应用程序、简化开发、提高效率 SpringBootWeb入门 需求&#xff1a;使用Spring Boot开发一个web应用&a…

软件测试面试怎样介绍自己的测试项目?会问到什么程度?

想知道面试时该怎样介绍测试项目&#xff1f;会问到什么程度&#xff1f;那就需要换位思考&#xff0c;思考HR在这个环节想知道什么。 HR在该环节普遍想获得的情报主要是下面这2个方面&#xff1a; 1&#xff09;应聘者的具体经验和技术能力&#xff0c; 2&#xff09;应聘者的…

Vector 动态数组(迭代器)

C数据结构与算法 目录 本文前驱课程 1 C自学精简教程 目录(必读) 2 Vector<T> 动态数组&#xff08;模板语法&#xff09; 本文目标 1 熟悉迭代器设计模式&#xff1b; 2 实现数组的迭代器&#xff1b; 3 基于迭代器的容器遍历&#xff1b; 迭代器语法介绍 对迭…

新版HBuilderX在uni_modules创建搜索search组件

1、创建自定义组件 my-search 新版HBuilder没有了 component 文件夹&#xff0c;但是有 uni_modules 文件夹&#xff0c;用来创建组件&#xff1a; 右键 uni_modules 文件夹&#xff0c;点击 新建uni_modules创建在弹出框&#xff0c;填写组件名字&#xff0c;例如&#xff1a…

netmap安装使用

文章目录 1、安装编译netmap2、使用netmap3、运行编写自己的代码 1、安装编译netmap github地址 git clone https://github.com/luigirizzo/netmap 1、进入目录 cd netmap-master/LINUX 2、安装编译环境 apt-get install build-essential 3、初始化配置环境 ./configure 出现这…

【记录】手机QQ和电脑QQ里的emoji种类有什么差异?

版本 手机 QQ&#xff1a;V 8.9.76.12115 电脑 QQ&#xff1a;QQ9.7.15&#xff08;29157&#xff09; 偶然发现&#xff0c;有一种emoji手机上怎么找都找不到&#xff0c;一开始以为自己失忆了&#xff0c;后来发现这种emoji只在电脑上有。 接下来简单说一下找emoji差异的方式…