这是我参与「第四届青训营 」笔记创作活动的第三天
承接上回,这次我们开始着手进行后端的处理。昨天有自己的事情要搞,所以没有更新笔记。废话不多说,我们开始今天的代码之路。
对导航头下滑消失,上滑出现的更新
上次使用的代码实现的消失有些不那么顺滑,可以很明显的看到导航头消失的时候是直接被干掉的,没有一个上滑的过程,所以总体看起来比较丑。而且掘金首页的导航头是有上滑的趋势的,因此在这里更新一下导航头消失的代码:
<div :class="navShow ? 'navOn' : 'navOff'">
.navOn {
z-index: 1;
display: flex;
flex-direction: column;
background-color: rgb(249, 251, 252);
width: 100%;
height: 55px;
position: fixed;
top: 0;
left: 0;
right: 0;
transition: all 0.1s ease-in-out 0.1s;
transform: translateZ(0);
border-bottom: 1px solid rgb(243, 242, 242);
}
.navOff {
z-index: 1;
display: flex;
flex-direction: column;
background-color: rgb(249, 251, 252);
width: 100%;
height: 55px;
position: fixed;
top: 0;
left: 0;
right: 0;
transition: all 0.2s ease-in-out 0.2s;
transform: translate3d(0, -100%, 0);
}
js:
window.addEventListener("wheel", pan);
const navShow = ref(true);
function pan() {
const heightclass2 = document.documentElement.scrollTop; //获取滚轮的高度
if (heightclass2 > heightclass1.value) {
heightclass1.value = heightclass2;
navShow.value = false;
return;
}
if (heightclass2 < heightclass1.value) {
heightclass1.value = heightclass2;
navShow.value = true;
return;
}
}
这一次导航头的消失与出现就非常顺滑了。
后端的处理
首先我先解释一下为什么这么早出现后端,我的想法是先做一个“样本”出来,然后后面的网页就照着这个模板来做,这样或许会更便捷一些。那么话不多说开始配置我们的端口。
首先是在vue3创建的时候他会一同创建一个文件:
vite.config.ts
在这个文件中我们要配置一下前端从哪里拿到我后端的数据:
server: {
host: "localhost", //地址指向本机(这里是vue并非后端)
port: 8080,//前端端口
open: true,
https: false,
proxy: {//这里开始是定义如何访问后端,我习惯定义好这些再去写代码,当然也可以直接在代码里加地址。
"/api": {//api就约等于是地址前缀
target: "<http://127.0.0.1:8081/api>",//这里指的是访问后端的地址了(包括了端口号)
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ""),
},
},
},
定义好了这个以后还要去后端写代码(毕竟不能指望电脑帮我自动写......)
golang的代码中主要的是访问数据库并拿数据,监听网络请求并将对应数据发送去前端。
首先是数据库:
我使用的是postgresql
import (
"context"
"fmt"
"github.com/jackc/pgx/v4/pgxpool"
)
var (
conn *pgxpool.Pool
)
func init() {
var errors error
// 连接数据库
config, err := pgxpool.ParseConfig("postgres://账号:密码@数据库地址:端口号/库名")//例:postgres://postgres:123456@857857.cn:857/share
if err != nil {
fmt.Println(err)
}
conn, errors = pgxpool.ConnectConfig(context.Background(), config)
//处理连接失败的情况
if errors != nil {
fmt.Println(errors)
}
}
func GetDatabaseConnection() *pgxpool.Pool {
return conn//返回连接好的接口
}
其次是监听网络请求
连接完数据库以后就是监听前端的请求了:
import (
"net/http"
"serve/power"
)
func main() {
http.HandleFunc("/", power.Server)//监听到8081端口过来的以“/”开头的请求如“/api/user/content”转入函数Server(power是文件名,自己创建的)
http.ListenAndServe(":8081", nil)//监听端口号8081,与前端中访问后端的端口号一致
}
好了,弄完数据库跟监听请求就可以开始写具体功能了。
具体功能
在写功能呢之前还有个分发函数即Server函数,因为我们对后端的请求不可能是只有一个的。一般而言我们会有很多不同类型的请求发到后端,如:登陆、发布、评论等等,而每次的请求头其后缀都是不同的,为了能准确将对应请求发送到对应功能函数,我们需要一个分发函数,用以在请求与功能函数之间建立联系。
代码如下:
const reqR = "^/(?P<api>\w+)/(?P<user>\w+)/(?P<action>\w+)(\?(?P<query>.*))?"//正则表达式用来划分请求头
func Server(w http.ResponseWriter, r *http.Request) {
fmt.Println("server")
regPath := regexp.MustCompile(reqR) //按正则表达式获取数据
fieldNames := regPath.SubexpNames()
fields := regPath.FindStringSubmatch(r.URL.Path)
result := make(map[string]string)
for i, name := range fieldNames {
if i != 0 && name != "" {
result[name] = fields[i]
}
}
api := strings.ToLower(result["api"])
uwer := strings.ToLower(result["user"])
action := strings.ToLower(result["action"]) //将字符串转换为大写 获得数据为是login还是msg
if api == "" || user == "" || action == "" {
fmt.Println("未传")
return
}
fmt.Printf("api:%s, user: %s, action: %s\n",
reqType, target, action)
req := fmt.Sprintf("/%s/%s/%s", api, user, action) //本次获得的数据是:api:"api", user:"user", action:"content"
fmt.Println(req)
switch req {
case "/api/user/content":
Transmission(w, r)//跳转到对应函数
default:
return
}
}
具体功能函数
具体功能函数,直接放代码:
type Message struct {
Content []Content `json:"content"`
Err string `json:"err"`
Sign int `json:"sign"`
}
type Content struct {
Cid int `json:"cid"`
Title string `json:"title"`
About string `json:"about"`
Content string `json:"content""`
}
func Transmission(w http.ResponseWriter, r *http.Request) {
buf, err := ioutil.ReadAll(r.Body) //读取Body文件的内容
if err != nil {
fmt.Println("body错误")
return
}
if buf == nil {
fmt.Println("body下面错误")
return
}
jsonMap := make(map[string]interface{}) //设置map,分配内存
err = json.Unmarshal(buf, &jsonMap) //解析buf中的数据,并将结果写入jsonMap中
if err != nil {
fmt.Println("解析错误")
return
}
sign := jsonMap["sign"] //这里是读取前端传来的数据(自己定义)
b := sign.(float64) //a、b为int与float64的转换
a := int(math.Ceil(b))
var msg Message
var content Content
var contentArr []Content
dbconn := GetDatabaseConnection() //获取数据库连接
s := fmt.Sprintf(`select * from content where cid>=%d and cid<=%d`, a, a+9)//sql语句,并将筛选条件一并写入
rc, err := dbconn.Query(context.Background(), s)
if err != nil {
log.Println(err)
}
for rc.Next() {//循环赋值
err = rc.Scan(&content.Cid, &content.Title, &content.About, &content.Content)
if err != nil {
log.Println(err)
}
contentArr = append(contentArr, content)
}
//fmt.Println(contentArr[0])
msg.Content = contentArr
a = a + 10
msg.Sign = a
retu(w, &msg)//发还给前端
}
func retu(w http.ResponseWriter, msg *Message) {//返还数据
if w == nil || msg == nil {
fmt.Println("call respErr with invalid w/msg")
return
}
//将msg结构体转化为json字符串
buf, err := json.Marshal(&msg)
if err != nil {
w.Write([]byte(fmt.Sprintf(`{"msg":"%s"}`, err.Error())))
fmt.Println(err.Error())
return
}
w.Write(buf)
}
回到前端
好了,后端的代码暂时完成,下面我们要在前端搞搞事了
vue3的 onMounted(() => {})函数,加载页面时调用,用这个来获取数据:
onMounted(() => {
const url = "api/user/content";//后端地址
fetch(url, {
method: "POST",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: new Headers({
"Content-Type": "application/json",
}),
body: JSON.stringify({//我们传到后端的数据
sign: sign.value,
}),
redirect: "follow",
})
.then((v) => {
console.log(v);
return v.json();
})
.then((v) => {
for (let i = 0; i < 10; ++i) {
sister.push(v.content[i]);//将从后端拿到的数据赋值给前端的数据
}
sign.value = v.sign;
});
});
上面的代码是刚加载页面时调用,我们还要实现页面下滑到底部时再追加数据: window.addEventListener("wheel", dontHurt);鼠标滚动事件,每滚动一次调用dontHurt函数
function dontHurt() {
const scrollHeight = document.body.scrollHeight; //页面内容总高度
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop; //滚动距离
const clientHeight = document.body.clientHeight; //可视区高度
const distance = scrollHeight - scrollTop - clientHeight; //得到你现在的距离离页面底部的距离
if (distance < 100 && tok.value == 0) {//tok是自定义的锁,防止多次同时调用本函数
tok.value = 1;
const url = "api/user/content";
fetch(url, {
method: "POST",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: new Headers({
"Content-Type": "application/json",
}),
body: JSON.stringify({
sign: sign.value,
}),
redirect: "follow",
})
.then((v) => {
console.log(v);
return v.json();
})
.then((v) => {
for (let i = 0; i < 10; ++i) {
sister.push(v.content[i]);
}
sign.value = v.sign;
tok.value = 0;
});
}
}
好了,今天就到这吧,最近看别人玩魔兽世界,自己也搞了个号去玩了玩,感觉还不赖。