Vue+Koa项目完整上线流程中遇到的问题

程序员有时候 “提笔忘字”, 以下是此次过程中遇到的问题流水账, 按顺序记录的, 不再细分什么前端后端了.

有些问题可能过于简单, 勿喷!

1, Koa 的 get, post 请求怎么获取参数

get 类请求: 直接使用 ctx.query 来获取前端传递来的参数
post 类请求: 需要使用到 koa-bodyparser 中间件, 然后通过 ctx.request.body 来获取前端传递的参数

koa-bodyparser 在使用 koa2 指令创建项目时已经内置.

2, get, post, put, delete 接口参数

直接贴一个路由文件的使用吧!

const router = require('koa-router')()
const { database } = require('../config/default')
const queryUtil = require('../service/query');router.prefix(`${database.BASIC_URL}/insurance`)router.get('/type', async function (ctx, next) {ctx.body = await queryUtil.getInsuranceType();
});router.post('/add', async (ctx, next) => {ctx.body = await queryUtil.addInsurance(ctx.request.body);
});router.get('/list', async (ctx, next) => {ctx.body = await queryUtil.insuranceList(ctx.query);
});router.put('/delete/validate', async function (ctx, next) {ctx.body = await queryUtil.deleteInsuranceValidate(ctx.request.body);
})router.delete('/delete', async (ctx, next) => {ctx.body = await queryUtil.deleteInsurance(ctx.query);
});router.get('/detail', async (ctx, next) => {ctx.body = await queryUtil.insuranceDetail(ctx.query);
});router.put('/edit', async (ctx, next) => {ctx.body = await queryUtil.editInsurance(ctx.request.body);
});module.exports = router

3, Vue 3 通过 customRef 实现防抖

废话不多说, 直接上代码:

src/utils/debouncedRef.js

import { customRef } from 'vue'export function useDebouncedRef(value, delay = 200) {let timeoutreturn customRef((track, trigger) => {return {get() {track()return value},set(newValue) {clearTimeout(timeout)timeout = setTimeout(() => {value = newValuetrigger()}, delay)}}})
}

哪个文件需要用到防抖函数, import 进去即可. 关于 customRef 的作用可参考官网介绍

4, defineModel()

defineModel(): 这个宏可以用来声明一个双向绑定 prop,通过父组件的 v-model 来使用。

个人理解: Vue 2 中 ---- “在组件上使用v-model” 的简化版.

我们知道, v-model 可以实现数据的双向绑定, 在 input 标签上使用时可以比较方便的获取 input 的 value 值. 这是因为 v-model 这个指令实际上就是一个 语法糖, 内部默认复合了一个 value 属性 和 一个 @input 方法.
因此, 我们想要在自定义组件上使用 v-model 时, 就需要在这个自定义组件中声明对应的 属性 和 方法 来配合.

那 Vue 3, 确切的说是 3.4+ 版本之后, 这个 defineModel() 的出现, 就会让我们在自定义组件中的配合不再那么麻烦.
以下是一个使用示例, 大家一看便知 ( 仅展示核心代码 ):

示例一: 子组件仅有一个需要传递的 model 属性

子组件 LabelInput.vue 核心代码

<script setup>const model = defineModel()</script><template>...<div class="item_con"><input :id="id" :type="type" v-model="model" :placeholder="placeholder"></div>
</template>

父组件中使用

<script setup>
import { ref } from 'vue'
import LabelInput from '@/components/LabelInput.vue'const username = ref('')
const password = ref('')</script><template><div class="username"><LabelInputv-model="username"></LabelInput></div><div class="password"><LabelInputv-model="password"></LabelInput></div>
</template>

示例二: 子组件仅有多个需要传递的 model 属性

子组件 Example.vue 核心代码

<script setup>const insuranceName = defineModel('insuranceName', { required: true })
const insuranceType = defineModel('insuranceType')</script><template><div class="item_con"><el-input v-model="insuranceName" /></div><div class="item_con"><el-select v-model="insuranceType">...</el-select></div>
</template>

父组件中使用

<script setup>
import { ref } from 'vue'
import Example from './components/Example.vue'const insuranceName = ref('')
const insuranceType = ref('')</script><template><Examplev-model:insuranceName="insuranceName"v-model:insuranceType="insuranceType"></Example>
</template>

5, 网格布局

网格布局是一个 学起来稍复杂, 但是 用起来舒服 的一种布局方案.

学起来复杂: 属性太多了, 眼花缭乱
用起来舒服: 两三个属性就能实现以往实现起来很麻烦的布局效果.

常用的属性:

grid-template-columns
grid-template-rows
row-gap

没有了解过网格布局的小伙伴, 抽空学一学吧, 很好用!

6, Koa 连接 MySQL 数据库

使用 mysql 模块来辅助实现 MySQL 数据库连接:

安装指令:

npm i mysql

之后就是 koa 中的配置, 以下是我自己的简单封装:

1, 根目录/config/default.js

const database = {HOST: 'xxx.xxx.xxx.xxx', //数据库地址USER: 'root',PASSWORD: 'xxxxxx',DATABASE: 'xxx', //数据库名称...
}
module.exports = { database}

2, 根目录/db/mysql.js

const mysql = require('mysql')
const { database } = require('../config/default')const pool = mysql.createPool({host: database.HOST,user: database.USER,password: database.PASSWORD,database: database.DATABASE
})exports.query = function (sql, values) {return new Promise((resolve, reject) => {pool.getConnection(function (err, connection) {if (err) {reject(err)console.log(err, "数据库连接失败");resolve({code: 500,})} else {console.log("数据库连接成功");connection.query(sql, values, (err, results) => {if (err) {reject(err)resolve({code: 400})} else {resolve({code: 200,results,})connection.release()//resolve(rows)}//connection.release() // 释放连接池})}})})
}

3, 使用

某js 文件中

const db = require('../db/mysql')function xxx() {const queryData = await db.query(`select * from ...`);...
}
...

7, Element UI 中国城市三级联动

Element UI 中国省市区级联数据: element-china-area-data

安装

npm i element-china-area-data

使用

某.vue 文件中:

<script setup>
import { reactive } from 'vue'
import { pcaTextArr } from 'element-china-area-data'const userForm = reactive({address_city: [],
})</script><template><div class="city"><el-cascaderclass="city_con":options="pcaTextArr"clearableplaceholder="选择城市"v-model="userForm.address_city"></el-cascader></div>
</template>

8, Vue 3 使用 Element UI 中的 loading

对于 loading 的使用, 可以使用 v-loading 这个 Element UI 提供的自定义指令, 属性值为 Boolean 类型就行.

我这里是以 服务 的形式使用的 loading 加载样式, 做了全局封装.
优点: 全局共用一个 loading
缺点: 全局共用一个 loading
代码:
src/utils/loading.js

import { ElLoading } from "element-plus"// style
const loadingStyle = {lock: true,text: 'Loading',background: 'rgba(0, 0, 0, 0.7)',
}
let load = null
const loading = {loading: () => {!load && (load = ElLoading.service(loadingStyle))},close: () => {load && load.close()}
}export default loading

使用:

import loading from '@/utils/loading'// 显示 loading
loading.loading()// 关闭 loading
loading.close()

在合适的时机调用 loading 的两个方法即可.
比较简陋, 不喜勿喷!

我是在自己二次封装的 axios.js 文件中使用的, 只要发送网络请求, 就会有 loading 的显示.

9, Koa 中 mysql 模块的 query 方法使用

上述内容中已经讲了将 mysql 重新封装 ( 创建 db/mysql.js ), 然后再 要使用时 import 引入后 调用 query() 方法即可.
这里简单聊下 query() 方法的使用:

// 1, 完整 sql 语句
const queryData = await db.query(`select * from xxxx`);// 2, 使用 ?
const queryData = await db.query('SELECT * FROM `books` WHERE `author` = ?', ['David']);// 3, 对象
const queryData = await db.query({sql: 'SELECT * FROM `books` WHERE `author` = ?',timeout: 40000, // 40svalues: ['David']
});// 4, 对象, value
const queryData = await db.query({sql: 'SELECT * FROM `books` WHERE `author` = ?',timeout: 40000, // 40s},['David']
);// 5, sql, value
const queryData = await db.query('SELECT * FROM `books` WHERE `author` = ?', 'David');

10, Koa 执行定时任务

使用 node-schedule 来实现定时任务的执行.

安装

npm i node-schedule

使用

1, 根目录/schedule/index.js

const schedule = require('node-schedule');
const queryUtil = require('../service/query');const REFRESH_REMIND = 'refresh_remind';function refreshRemind() {// 重复const rule2 = new schedule.RecurrenceRule();// [0,1,2],表示周天、周一、周二都会执行rule2.dayOfWeek = [0, 1, 2, 3, 4, 5, 6];rule2.hour = 0;rule2.minute = 30;rule2.second = 0;schedule.scheduleJob(REFRESH_REMIND, rule2, async function() {// 每天 00:30:00 刷新 is_remind 数据const refreshResults = await queryUtil.refreshReminded();console.log('更新 is_remind 结果', refreshResults);});
}module.exports = { refreshRemind }

2, app.js


// schedule 定时任务 --- 在路由加载之前调用
const { refreshRemind } = require('./schedule/index')
refreshRemind();

scheduleJob() 方法的第一个参数还有其他传参形式:

const schedule = require('node-schedule');// 每逢分钟为 42 时触发, 例如: 19:42, 20:42, ...
const job = schedule.scheduleJob('42 * * * *', function(){console.log('The answer to life, the universe, and everything!');
});

┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ │
│ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
│ │ │ │ └───── month (1 - 12)
│ │ │ └────────── day of month (1 - 31)
│ │ └─────────────── hour (0 - 23)
│ └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, OPTIONAL)

更多配置请参考[官方文档[(https://www.npmjs.com/package/node-schedule)

11, Vue 3 跨域代理

最初找的文档都是要在 vue.config.js 文件中配置 devServer, 但是想着都 Vue 3 了, 应该有变化吧, 就去 vite 的官网去搜索方案, 还真是找到了, 为此还专门写了篇博客, 这里不再赘述, 传送门

12, 服务器中项目代码存放位置

项目写完之后, 该上线了, 前端项目 npm run build 之后的 dist 放置在哪里呢? 直接就开始 百度吧, 走了不少弯路.

印象最深的一个说放置于 koa 项目的 public 文件中, 然后修改 app.js 中静态资源的路径后面拼接上 /dist( 默认值: __dirname + ‘/public/’).

诶, 直接运行 koa, 浏览器地址栏 localhost:3000 还真把前端项目给跑起来了, 点了几个页面后, 刷新, 坏了 !!! Vue 的路由 与 Koa 的路由冲突了 !!! 又找方案!!!

找着找着, 发现不对, 我不都用 Nginx 了吗? 还乱配置啥? 于是, 静下来屡思路, 我应该让 Nginx 来管理呀!

于是, 最终 前端的 dist 放置于 Nginx 静态资源文件夹 html 下的一个文件夹中, 具体可参考上一篇博客, 传送门

里面还记录了 Nginx 的 config 文件该怎么配置.

Koa 的配置也在博客里边, 我这里就不赘述了.

13, 自定义指令实现 元素高度撑满父级

直接上代码:

1, src/directives/height.js

function siblings(elm) {var a = [] //保存所有兄弟节点var p =  elm && elm.parentNode.children //获取父级的所有子节点for (var i = 0; i < p.length; i++) { //循环if (p[i].nodeType == 1 && p[i] != elm) { //如果该节点是元素节点与不是这个节点本身a.push(p[i]) // 添加到兄弟节点里}}return a
}export default function(app) {app.directive("height", {mounted: function(el) {// 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)const parentNodesH = el.parentNode.clientHeightconst nodes = document.getElementById(el.id)const sibNodes = siblings(nodes)let exitH = 0sibNodes.forEach(el => {exitH += el.clientHeight})el.style.height = parentNodesH - exitH + 'px'}})}

2, src/directives/index.js

import registerHeight from './height'export default function registerDirectives(app) {registerHeight(app)
}

3, main.js

...
// 自定义指令
import registerDirectives from './directives'const app = createApp(App)app.use(createPinia())
app.use(router)
app.use(ElementPlus)
registerDirectives(app)app.mount('#app')

4, 使用

必须要有 id 属性

<template>...<div id="xxx" v-height>...</div>...
</template>

本章完!

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

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

相关文章

阿里云服务器centos_7_9_x64位,3台,搭建k8s集群

目录 1.环境信息 2.搭建过程 2.1 安装Docker源 2.2 安装Docker 2.3 安装kubeadm&#xff0c;kubelet和kubectl 2.4 部署Kubernetes Master(node1) 2.5 安装Pod网络插件&#xff08;CNI&#xff09; 2.6 加入Kubernetes Node 2.7 测试kubernetes集群 3.部署 Dashboard…

pytorch tensor维度变换

目录 1. view/reshape2. squeeze/unsqueeze3. expand 扩展4. repeat5 .t转置6. transpose7. permute 1. view/reshape view(*shape) → Tensor 作用&#xff1a;类似于reshape&#xff0c;将tensor转换为指定的shape&#xff0c;原始的data不改变。返回的tensor与原始的tensor…

【Linux系统学习】1.初识Linux

初识Linux 操作系统概述 初识Linux 虚拟机介绍 VMware WorkStation安装 1.操作系统概述 了解操作系统的作用 了解常见的操作系统 1.1 硬件和软件 计算机由哪两个主要部分组成&#xff1f; 硬件&#xff1a;计算机系统中由电子&#xff0c;机械和光电元件等组成的各种物理装置的…

小红的字符串中值

题目描述: 小红定义一个长度为奇数的字符串的“中值”为中间那个字符。例如"kou"的中值是o。 现在小红拿到了一个字符串&#xff0c;她想知道某个字符是多少个子串的中值。你能帮帮她吗&#xff1f; 输入描述: 输出描述: 一个整数&#xff0c;代表中值为chr的连续子串…

2024/02/06

画出TCP三次握手和四次挥手的示意图 三次握手 四次挥手 并且总结TCP和UDP的区别 TCP: TCP提供面向连接的&#xff0c;可靠的数据传输服务传输过程中&#xff0c;数据无误、数据无丢失、数据无失序、数据无重复 TCP会给每个数据包编上编号&#xff0c;该编号称之为序列号每个序…

DDoS攻击激增,分享高效可靠的DDoS防御方案

当下DDoS攻击规模不断突破上限&#xff0c;形成了 "网络威胁格局中令人不安的趋势"。专业数据显示&#xff0c;对比2022年上半年与2023年上半年&#xff0c;所有行业的DDoS攻击频率增加了314%。其中零售、电信和媒体公司遭受的攻击规模最大&#xff0c;三个垂直行业的…

5年前端仔的2023年终总结

突然发现已经有好几个月没有写过博客总结过什么&#xff0c;小小辩解一下&#xff0c;其实并不是笔者停止的学习和总结&#xff0c;随着在前端这个行业的逐年深入&#xff0c;渐渐的很多收获不再是像之前简单的技术点的确定性描述讲解了&#xff0c;而是某个领域的知识体系的串…

【新书推荐】6.3节 指令指针寄存器

8086 CPU内部的指令指针寄存器IP是计算机自动运行程序的关键。指令指针寄存器IP自动指向下一条将要执行的指令。 本节内容&#xff1a;使用指令指针寄存器读取和执行指令的工作原理和段寄存器的引用。 ■指令指针&#xff1a; 8086CPU中的指令指针寄存器IP是16位寄存器。指令指…

Swin-UMamba:结合基于ImageNet的预训练和基于Mamba的UNet模型

摘要 https://arxiv.org/pdf/2402.03302v1.pdf 准确的医学图像分割需要整合从局部特征到全局依赖的多尺度信息。然而&#xff0c;现有方法在建模长距离全局信息方面面临挑战&#xff0c;其中卷积神经网络&#xff08;CNNs&#xff09;受限于其局部感受野&#xff0c;而视觉转换…

Golang 学习(二)进阶使用

二、进阶使用 性能提升——协程 GoRoutine go f();一个 Go 线程上&#xff0c;可以起多个协程&#xff08;有独立的栈空间、共享程序堆空间、调度由用户控制&#xff09;主线程是一个物理线程&#xff0c;直接作用在 cpu 上的。是重量级的&#xff0c;非常耗费 cpu 资源。协…

osg模型的平移、缩放、旋转

加载2个模型&#xff0c;其中一个向上移动28个单位&#xff1b; 加载2个模型&#xff0c;其中一个缩放0.5倍&#xff0c;向下移动22个单位&#xff1b; 加载2个模型&#xff0c;其中一个缩放0.5倍、旋转45度、向右向下移动几个单位&#xff1b; 都是用矩阵实现的&#xff1b; …

Python算法题集_环形链表II

Python算法题集_环形链表II 题142&#xff1a;环形链表II1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【集合检索】2) 改进版一【字典检测】3) 改进版二【双指针】 4. 最优算法 本文为Python算法题集之一的代码示例 题142&#xff1a;环形链…

计算机设计大赛 深度学习+python+opencv实现动物识别 - 图像识别

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 inception_v3网络5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; *…

AJ-Report 【开源的一个BI平台】

AJ-Report是全开源的一个BI平台&#xff0c;酷炫大屏展示&#xff0c;能随时随地掌控业务动态&#xff0c;让每个决策都有数据支撑。     多数据源支持&#xff0c;内置mysql、elasticsearch、kudu驱动&#xff0c;支持自定义数据集省去数据接口开发&#xff0c;目前已支持30…

Linux(Debian系)的Python导入pandas包,报错:ImportError: No module named ‘_bz2‘

前言&#xff1a; 硬件操作系统国产化路漫漫&#xff0c;由此可见华为的厉害。 今天在香橙派上用自己编译的python导入pandas时&#xff0c;报错&#xff1a; from _bz2 import BZ2Compressor, BZ2Decompressor ImportError: No module named _bz2ImportError: No module name…

docker compose部署gitlab 获取初始密码

docker compose部署gitlab 获取初始密码 方式一&#xff1a; #获取gitlab容器名称 docker container ps#将获取到的容器名称替换 gitlabrunner docker container exec -it gitlabrunner grep Password /etc/gitlab/initial_root_password方式二&#xff1a; 直接修改密码 #…

2月6号作业

线程同步的方式&#xff1a;互斥锁&#xff0c;无名信号量&#xff0c;条件变量 互斥锁&#xff1a;初始化互斥锁&#xff1a;静态创建&#xff1a;pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER; 动态创建&#xff1a;int pthread_mutex_init(pthread_mutex_t * __rest…

【安卓跨程序共享数据,探究ContentProvider】

ContentProvider主要用于在不同的应用程序之间实现数据共享的功能&#xff0c;它提供了一套完整的机制&#xff0c;允许一个程序访问另一个程序中的数据&#xff0c;同时还能保证被访问数据的安全性。 目前&#xff0c;使用ContentProvider是Android实现跨程序共享数据的标准方…

java面试题:分布式和微服务的区别

1 分布式和微服务概念不同 微服务架构是架构设计方式&#xff0c;是设计层面的东西&#xff0c;一般考虑如何将系统从逻辑上进行拆分&#xff0c;也就是垂直拆分。 分布式系统是部署层面的东西&#xff0c;即强调物理层面的组成&#xff0c;即系统的各子系统部署在不同计算机…

宠物空气净化器哪个牌子好?养猫家庭如何挑选宠物空气净化器?

养猫的朋友都知道&#xff0c;猫咪掉毛是一个令人头痛的问题。猫毛和皮屑会漂浮在空气中&#xff0c;不仅遍布全屋的各个角落&#xff0c;而且清理起来也非常麻烦&#xff0c;特别是那些难以清除的猫毛。更糟糕的是&#xff0c;这些猫毛还可能引发人们的过敏反应&#xff0c;如…