Skip to content

官网

基础标准文档链接

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

地址: https://tinypng.com/

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优化

验证步骤:

  1. 打开官网页面
  2. 右键点击查看页面源代码
  3. 搜索相关页面的文案
  4. 验证是否有相关的文案