Appearance
官网
基础标准文档链接
bash
腾讯文档地址: https://docs.qq.com/sheet/DZk5FVXZKeFZhc1FK?tab=000001
bash
云效Git地址: https://codeup.aliyun.com/624ae3876d47d593cb382403/nanxihang/base/base_os/edit/master/README.md
使用 Nuxt3 做seo 框架官网Nuxt 3 documentation.
一、开发及部署
1.1 安装依赖
bash
# npm
npm install
# pnpm
pnpm install
# yarn
yarn install
1.2 运行
bash
# npm node>=18
npm run dev
# pnpm
pnpm run dev
# yarn
yarn dev
1.3 打包
bash
# npm
npm run build
# pnpm
pnpm run build
# yarn
yarn build
本地预览部署结果
bash
# npm
npm run preview
# pnpm
pnpm run preview
# yarn
yarn preview
1.4 docker 部署
bash
docker login # 如果用远端
docker build -t base_os .
docker run -it -p 3000:3000 base_os
docker run -d -it -p 3000:3000 --name=base_os base_os
1.5 PM2
部署中使用 pm2 部署 node 服务。默认集群启动 4 个实例
可进入容器中查看 pm2 的状态
docker exec -it aos_os bash
pm2 list
pm2 monit
1.6 Nginx 反向代理
server {
listen 443;
server_name <domain_name>;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:3000;
}
include <ssl_conf>;
}
了解更多部署情况 deployment documentation
二、目录结构
├── assets # 资源文件
├── components # 公共组件
├──── functionBtn # 公共悬浮操作按钮组件
├──── houseHeader # 公共页头组件
├──── houseFooter # 公共页脚组件
├──── VideoPlayer # 视频播放器组件
├── composables # 公共方法
├──── aes # aes加密解密方法
├──── apiClient # 客户端api请求
├──── apiServer # 服务端api请求
├──── apiUtil # api请求封装
├──── report # 阿里ARMS上报方法
├──── state # 全局状态管理
├──── vConsole # 移动端调试工具
├── layouts # 页面布局
├──── default # 默认布局
├── node_modules # 依赖包
├── pages # 页面目录
├──── index # 首页
├──── news # 新闻列表页面
├────── detail # 新闻详情页面
├── public # 静态资源目录
├── app.vue # 项目入口文件
├── error.vue # 错误页面
├── .dockerignore # docker 忽略文件
├── Dockerfile # docker 镜像文件
├── .gitignore # git 忽略文件
├── .env # 测试环境-环境变量
├── .env.pro # 生产环境-环境变量
├── .npmrc # npm 配置文件
├── ecosystem.conf # 实现多进程部署
├── nuxt.config.js # Nuxt配置文件
└── package.json # 项目配置文件
三、基础标准
1: 强制使用Nuxt框架实现SSR服务端渲染 基础代码已保留不允许更改
解决方案: nuxt.config.js 文件中配置ssr , 基础代码保留不允许更改
javascript
ssr: true
2: 分页逻辑需采用整页跳转(非AJAX局部切换) 提交代码时验证
示例文件: 新闻列表分页 (路径: pages/news/index.vue)
说明: 点击分页切换时更换路由地址,并且watch监听路由参数变化进行数据请求刷新
主要逻辑代码:
javascript
//分页点击事件
const cutPage = (index) => {
navigateTo({
path: '/news',
query: {
page: index,
},
});
window.scrollTo({
top: 0,
behavior: "smooth", // 平滑滚动
});
}
//路由参数监听
watch(() => route.query, (newValue) => {
message.warning('分页切换')
});
3: 移动端适配强制使用tailwind.css或windi.css 基础代码保留不允许更改
说明: 项目引入了windi.css,并且在windi.config.js中配置了移动端适配的尺寸配置
windi.css官网地址: https://windicss.org/
移动端样式适配:
css
<md:(flex-1 !bg-transparent !flex-col)
4: 生产环境打包需移除所有console.log输出 基础代码保留不允许更改
解决方案: nuxt.config.js 文件中可以配置vite打包时的日志打印限制
配置项:
javascript
vite: {
build: {
minify: 'terser',//压缩代码
terserOptions: {
compress: {
drop_console: true, //打包时删除console
drop_debugger: true, //打包时删除 debugger
},
},
},
},
5: 敏感数据传输需使用AES加密 基础代码保留不允许更改
说明: 加密功能已经封装到了api请求方法内部,直接调用即可,封装文件路径: composables/apiUtil.ts
主要加解密代码:
javascript
import oAes from './aes/encryption'; // aes加密引入
oAes.getAes(d, boolean) as Encrypted //参数加密
oAes.getUnAes(result, boolean); //数据解密
6: 浏览器标签图标需使用本地资源(favicon.ico),禁止外链 提交代码时验证
解决方案: 在public目录下放置favicon.ico文件,并且在nuxt.config.js中配置
javascript
app: {
head: {
link: [
{rel: "icon", type: "image/x-icon", href:"/nxh.ico"} //添加ico图标
],
},
},
7: 页面文字内容禁止设置user-select: none,确保用户可复制 基础代码保留不允许更改
解决方案: 在base.scss设置允许复制文案的样式
css
* {
user-select: auto;
}
8: 字体使用系统字体,但要设置一个优先顺序 基础代码保留不允许更改
解决方案: 在base.scss设置系统字体的样式
css
* {
font-family: "Open Sans", "PingFang SC", "Microsoft YaHei", "Helvetica Neue", "Hiragino Sans GB", "WenQuanYi Micro Hei", Arial, sans-serif !important;
}
9: 针对可跳转链接,鼠标放上去需要小手展示 提交代码时需要验证
解决方案: 在base.scss设置一个基础类名,基础代码保留不允许更改
css
.link-hover {
cursor: pointer;
}
10: 需配置蜘蛛文件(robots.txt) 提交代码时需要验证
解决方案: 在public目录下放置robots.txt文件,单独放置无法访问,需要后台配置一下Nginx
11:每个页面必须独立配置TDK(Title、Keywords、Description) 提交代码时需要验证
使用useSeoMeta:
javascript
useSeoMeta({
title: '新闻页面没有设置全TKD',
ogTitle:'新闻页面没有设置全TKD',
keywords: '新闻页面没有设置全TKD',
description: '新闻页面没有设置全TKD',
ogDescription: '新闻页面没有设置全TKD',
ogUrl: `${process.env.BASE_URL'}/news/detail?id=${route.query.id}`,
ogType: 'article',
article: {
publishedTime: '2022-01-01 00:00:00',
author: '北京南熙航'
},
})
12: 新闻详情页URL参数仅允许id,禁止附加其他字段 提交代码时需要验证
示例文件: 新闻列表分页 (路径: pages/news/index.vue)
主要跳转代码:
html
<NuxtLink :to="'/news/detail'+ id">点击跳转详情</NuxtLink>
13: 屏幕宽度超过2560px时,内容区域居中,两侧留白 基础代码已保留不允许更改 基础代码保留不允许更改
解决方案: 布局文件 layouts/default/index.vue 处理了内容区域slot的居中样式
主要适配代码:
css
.slot {
width: 100%;
max-width: 2560px;
margin: 0 auto;
}
14: 悬浮操作栏需根据断点切换为纯图标模式(需定义具体断点值,如<1320px) 提交代码时需要验证
解决方案: 在windi.config.js中配置需要适配的断点值,在悬浮组件 commonponents/functionBtn/index.vue 中根据配置项处理ui样式
示例代码:
css
//屏幕尺寸配置
screens: {
'sm': '480px',
'md': '750px',
'lg': '1281px',
'xlg': '1320px',//设置该尺寸为切换悬浮按钮的断点值
'xl': '1441px',
'2xl': '1921px',
'3xl': '2560px',
},
//functionBtn文件根据xlg适配写样式
<div class="w-[100px]"></div> //正常大屏宽度
<div class="<xlg:w-[50px]"></div> //小屏宽度
15: 轮播图必须启用自动播放(autoplay) 没有特殊说明,轮播图均采用无缝轮播(loop: true) 提交代码时需要验证
解决方案: 状态管理器文件 composables/state.js 中已设置全局变量 autoplayOptions,swiper直接使用 , 基础代码保留不允许更改
示例文件: 首页轮播图 (路径: pages/index/index.vue)
示例代码:
html
<swiper
:modules="modules"
:loop="true"
:autoplay="autoplayOptions"
:slides-per-view="1"
:pagination="{clickable: true}"
:navigation="true"
style="height: 600px"
>
<swiper-slide style="height: 100%;">
第一屏
</swiper-slide>
<swiper-slide style="height: 100%;">
第一屏
</swiper-slide>
</swiper>
16: 所有接口请求需触发全局Loading动画 提交代码时需要验证
示例代码:
javascript
import {useShowLoading} from '../../composables/state' //引入全局loading状态管理
const {showLoading} = useShowLoading() //获取showLoading方法
//请求接口
showLoading.value = true //显示loading
getNewsList().then(res => {
}).finally(() => {
showLoading.value = false //关闭loading
})
17: 数据加载完成前禁止显示“暂无数据”提示,需保持Loading状态 提交代码时需要验证
解决方案: 定义变量 isEndRequest 请求是否结束,根据这个变量以及数据是否为空来判断是否显示暂无数据提示
vue
<template>
<div v-if="!isEndRequest && !list.length">暂无数据</div>
<template>
<script>
export default {
data() {
return {
isEndRequest: false, //请求是否结束
list: [], //数据列表
}
},
created() {
this.getData()
},
methods: {
getData() {
//请求接口
this.isEndRequest = false //显示loading
getNewsList().then(res => {
this.list = res.data.list
this.isEndRequest = true //关闭loading
})
}
}
}
</script>
18: 移动端禁止新窗口跳转;PC端仅首页允许新标签页打开,其余页面需当前页跳转 提交代码时需要验证
示例代码:
html
<NuxtLink to="/xxx/xxx" target="_blank">首页链接</NuxtLink> //首页允许新标签页打开
<NuxtLink to="/xxx/xxx" target="_self">其余链接</NuxtLink> //其余页面禁止新窗口打开
19: 弹窗出现背后内容禁止滑动 基础代码保留不允许更改
解决方案: 根据全局变量给布局容器body添加类名body-hidden设置溢出隐藏
javascript
//添加类名
document.body.classList.add('body-hidden')
//移除类名
document.body.classList.remove('body-hidden')
20: 搜索框需支持回车键直接触发搜索 提交代码时需要验证
解决方案: 监听回车键触发搜索事件
javascript
//监听回车键触发搜索事件
document.addEventListener('keyup', (event) => {
if (event.keyCode === 13) {
this.search()
}
})
21: 移动端电话号码需使用实现点击拨号 提交代码时需要验证
示例代码:
html
<a href="tel:1234567890">1234567890</a>
22: 默认无动画要求时,基础元素需添加简单动画(如上浮效果)
解决方案: 引入animate.css动画库,在文件中直接使用
html
<div class="animate__animated animate__fadeInUp">内容</div>
23: 非小图标图片需添加加载背景(如灰色占位块) 基础代码保留不允许更改
解决方案: img标签添加全局的样式类名
html
<img class="loadingClassImg" src="xxx.jpg" alt=""> //图片最大2560 占位图居中
<img class="loadingClassMinImg" src="xxx.jpg" alt=""> //图片最大1920 占位图居中
<img class="loadingClassMinBotomImg" src="xxx.jpg" alt=""> //图片最大1920 占位图靠近底部
24: 非首屏图片启用懒加载,所有图片必须添加alt描述 提交代码时需要验证
示例代码:
html
/**
loading="lazy" 懒加载
alt="图片描述" 图片描述
**/
<img loading="lazy" src="xxx.jpg" alt="图片描述">
25: 新闻封面图悬停需触发 transform: scale 放大效果 提交代码时需要验证
解决方案: 图片悬停时添加样式类名 img-scale 类名不需要自己定义,直接使用即可
html
<img class="img-scale" src="xxx.jpg" alt="">
css
.img-scale{
overflow: hidden;
img{
transition: all .3s;
}
&:hover img{
transform: scale(1.1);
}
}
26: 图片需通过工具(如TinyPNG)压缩后上传 提交代码时需要验证
解决方案: 图片压缩工具推荐TinyPNG
27 滑块验证组件需动态加载(如通过import()),禁止全局引入 提交代码时需要验证
示例代码:
javascript
const SlideVerify = () => import('@/components/SlideVerify') //动态导入
28: 所有数据(前后台)需经过审核,禁止测试内容、占位图片或无效信息 提交代码时需要验证
说明: 前后台图片文案等都需要正常数据,不能出现测试内容、占位图片或无效信息
29: api服务端请求 提交代码时需要验证
示例文件::pages/news/detail.vue
主要代码:
javascript
const { data: newsData } = await useAsyncData(
'newsDetail',
async () => {
// 正常开发走下面,当前位置属于示例,没有接口
if(true){
return
}
const id = route.query.id
if (!id) {
return { error: 1 }
}
let resp = await getNewsInfo({ id })
console.log('resp =============',resp)
return resp
},
{
server: true,
client: false, // 只在服务端获取数据,避免重复获取
immediate: true,
transform: (result) => {
// 只做基本验证,避免过度处理
if (result?.error === 1) {
return { error: 1 }
}
return result
}
}
)
30 页面中的跳转 需使用NuxtLink组件,不能使用js跳转,除非是特殊情况 提交代码时需要验证
示例文件::pages/news/index.vue
主要代码:
html
<NuxtLink :to="'/news/detail'+ id">点击跳转详情</NuxtLink>
31 代码不允许写死变量,如果需要写死变量问题,直接提出问题,并说明原因
错误示例代码:
js
// 写死数组中的key值,可能会导致正式测试的差异
let options = [
{value:'协会动态',key:1825},
{value:'行业动态',key:1826},
{value:'政策法规',key:1827},
{value:'通知公告',key:1828},
]
32 官网发布上线 需要在源代码中可以搜索到相关页面的文案 保证seo优化
验证步骤:
- 打开官网页面
- 右键点击查看页面源代码
- 搜索相关页面的文案
- 验证是否有相关的文案