前端基础场第六天| 青训营笔记

180 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第三天

承接上回,这次我们开始着手进行后端的处理。昨天有自己的事情要搞,所以没有更新笔记。废话不多说,我们开始今天的代码之路。

对导航头下滑消失,上滑出现的更新

上次使用的代码实现的消失有些不那么顺滑,可以很明显的看到导航头消失的时候是直接被干掉的,没有一个上滑的过程,所以总体看起来比较丑。而且掘金首页的导航头是有上滑的趋势的,因此在这里更新一下导航头消失的代码:

 <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;
          });
      }
    }

好了,今天就到这吧,最近看别人玩魔兽世界,自己也搞了个号去玩了玩,感觉还不赖。