2 Commits
c91b231b60
...
0864938369
Author | SHA1 | Message | Date |
---|---|---|---|
|
0864938369 |
add:2025年6月18日-lihui学习笔记
|
2 weeks ago |
|
a98b611445 |
add:2025年6月18日-lihui学习笔记
|
2 weeks ago |
-
2GO学习/GOFrame.md
-
439GO学习/Gin框架.md
-
BINGO学习/assets/Gin框架/image-20250617112721609-17501308421881.png
-
BINGO学习/assets/Gin框架/image-20250617112721609.png
-
BINGO学习/assets/Gin框架/image-20250617112936947.png
-
BINGO学习/assets/Gin框架/image-20250617114457929.png
-
BINGO学习/assets/Gin框架/image-20250617115733445.png
-
89Git命令.md
-
BINassets/6-16_李慧学习记录/image-20250616180459370.png
-
BINassets/6-16_李慧学习记录/image-20250616180518835.png
-
BINassets/6-16股票学习/image-20250616114324156.png
-
0git
-
394前端/Vue3.md
-
BIN前端/assets/Vue3/image-20250618172046133.png
-
0学习记录/2025年6月11日学习记录.md
-
2学习记录/6-12_李慧学习记录.md
-
0学习记录/6-13_李慧学习报告.md
-
0学习记录/6-15_李慧学习记录.md
-
8学习记录/6-16_李慧学习记录.md
-
583学习记录/6-17_李慧学习记录.md
-
481学习记录/6-18_李慧学习记录.md
-
BIN学习记录/assets/6-16_李慧学习记录/image-20250617150826018.png
-
BIN学习记录/assets/6-16_李慧学习记录/image-20250617150903922.png
-
BIN学习记录/assets/6-16_李慧学习记录/image-20250617150917522.png
-
BIN学习记录/assets/6-17_李慧学习记录/image-20250617180547018.png
-
BIN学习记录/assets/6-18_李慧学习记录/image-20250618172336329.png
-
2股票/6-16股票学习.md
-
137股票/6-17股票学习.md
-
79股票/6-18股票学习.md
-
BIN股票/assets/6-16股票学习/image-20250617150944307.png
-
BIN股票/assets/6-17股票学习/image-20250617171603320.png
-
BIN股票/assets/6-17股票学习/image-20250617172405667.png
-
BIN股票/assets/6-17股票学习/image-20250617174011011.png
-
BIN股票/assets/6-17股票学习/image-20250617175850502.png
-
BIN股票/assets/6-17股票学习/image-20250617180042083.png
-
BIN股票/assets/6-18股票学习/image-20250618173052302.png
-
BIN股票/assets/6-18股票学习/image-20250618175722273.png
-
BIN股票/assets/6-18股票学习/image-20250618175734785.png
@ -0,0 +1,2 @@ |
|||
# GoFrame框架 |
|||
|
@ -0,0 +1,439 @@ |
|||
# Gin框架的基本使用 |
|||
|
|||
## 下载与安装 |
|||
|
|||
> 更改环境变量 GOPATH |
|||
> |
|||
> 方便将包下载到其他的盘符目录 |
|||
> |
|||
> 参考:[2024年go安装教程(Windows)包括配置GOPATH-CSDN博客](https://blog.csdn.net/weixin_63860405/article/details/139732041) |
|||
|
|||
### 下载 |
|||
|
|||
```shell |
|||
go get -u github.com/gin-gonic/gin |
|||
``` |
|||
|
|||
 |
|||
|
|||
## 基础使用 |
|||
|
|||
### GET请求 |
|||
|
|||
```go |
|||
|
|||
package main |
|||
|
|||
import "github.com/gin-gonic/gin" |
|||
|
|||
func main() { |
|||
router := gin.Default() |
|||
router.GET("/ping", func(c *gin.Context) { |
|||
c.JSON(200, gin.H{ |
|||
"message": "Hello World!", |
|||
}) |
|||
}) |
|||
router.Run() // 监听并在 0.0.0.0:8080 上启动服务 |
|||
// 默认是在8080端口启动服务,如果8080端口被占用,则自动寻找可用端口启动服务,可以指定端口 |
|||
} |
|||
``` |
|||
|
|||
 |
|||
|
|||
### ANY请求 |
|||
|
|||
根据请求来选择(使用if else) |
|||
|
|||
```go |
|||
// Any 请求 |
|||
router.Any("/any", func(c *gin.Context) { |
|||
if c.Request.Method == "POST" { |
|||
c.JSON(200, gin.H{ |
|||
"message": "POST", |
|||
}) |
|||
} else if c.Request.Method == "GET" { |
|||
c.JSON(200, gin.H{ |
|||
"message": "GET", |
|||
}) |
|||
} else { |
|||
c.JSON(200, gin.H{ |
|||
"message": "Any", |
|||
}) |
|||
} |
|||
}) |
|||
``` |
|||
|
|||
### POST请求 |
|||
|
|||
```go |
|||
// POST 请求 |
|||
router.POST("/post", func(c *gin.Context) { |
|||
c.JSON(200, gin.H{ |
|||
"message": "POST", |
|||
}) |
|||
}) |
|||
|
|||
``` |
|||
|
|||
 |
|||
|
|||
## 参数获取 |
|||
|
|||
### 获取query string 参数 |
|||
|
|||
格式:URL `?`后携带参数 |
|||
|
|||
例如:/user/searcher?username=xxx&address=xxx |
|||
|
|||
|
|||
|
|||
```go |
|||
// 获取参数,query string |
|||
router.GET("/user/search", func(c *gin.Context) { |
|||
username := c.DefaultQuery("username", "lihuibear") |
|||
address := c.Query("address") |
|||
|
|||
// 返回json数据 |
|||
c.JSON(200, gin.H{ |
|||
"username": username, |
|||
"address": address, |
|||
}) |
|||
|
|||
}) |
|||
``` |
|||
|
|||
 |
|||
|
|||
### 获取 form参数 |
|||
|
|||
当前端请求的数据通过form表单提交时,例如向`/user/search`发送一个POST请求,获取请求数据的方式如下: |
|||
|
|||
```go |
|||
router.POST("/user/search_by_form", func(c *gin.Context) { |
|||
// DefaultPostForm取不到值时会返回指定的默认值 |
|||
//username := c.DefaultPostForm("username", "小王子") |
|||
username := c.PostForm("username") |
|||
address := c.PostForm("address") |
|||
//输出json结果给调用方 |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"message": "ok", |
|||
"username": username, |
|||
"address": address, |
|||
}) |
|||
}) |
|||
``` |
|||
|
|||
### 获取JSON参数 |
|||
|
|||
当前端请求的数据通过JSON提交时,例如向`/json`发送一个JSON格式的POST请求,则获取请求参数的方式如下: |
|||
|
|||
```go |
|||
//获取JSON参数 |
|||
router.POST("/json", func(c *gin.Context) { |
|||
// 注意:下面为了举例子方便,暂时忽略了错误处理 |
|||
b, _ := c.GetRawData() // 从c.Request.Body读取请求数据 |
|||
// 定义map或结构体 |
|||
var m map[string]interface{} |
|||
// 反序列化 |
|||
_ = json.Unmarshal(b, &m) |
|||
|
|||
c.JSON(http.StatusOK, m) |
|||
}) |
|||
``` |
|||
|
|||
### 获取path参数 |
|||
|
|||
请求的参数通过URL路径传递,例如:`/user/search/小王子/沙河`。 获取请求URL路径中的参数的方式如下: |
|||
|
|||
```go |
|||
// 获取path参数 |
|||
router.GET("/user/search/:username/:address", func(c *gin.Context) { |
|||
username := c.Param("username") |
|||
address := c.Param("address") |
|||
//输出json结果给调用方 |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"message": "ok", |
|||
"username": username, |
|||
"address": address, |
|||
}) |
|||
}) |
|||
``` |
|||
|
|||
### 参数绑定 ShouldBind() |
|||
|
|||
为了能够更方便的获取请求相关参数,提高开发效率,我们可以基于请求的`Content-Type`识别请求数据类型并利用反射机制自动提取请求中`QueryString`、`form表单`、`JSON`、`XML`等参数到结构体中。 |
|||
|
|||
```go |
|||
// 参数绑定 |
|||
|
|||
// 绑定JSON的示例 ({"user": "q1mi", "password": "123456"}) |
|||
router.POST("/login_by_JSON", func(c *gin.Context) { |
|||
var login Login |
|||
|
|||
if err := c.ShouldBind(&login); err == nil { |
|||
fmt.Printf("login info:%#v\n", login) |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"user": login.User, |
|||
"password": login.Password, |
|||
}) |
|||
} else { |
|||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) |
|||
} |
|||
}) |
|||
// 绑定form表单示例 (user=q1mi&password=123456) |
|||
router.POST("/login_by_form", func(c *gin.Context) { |
|||
var login Login |
|||
// ShouldBind()会根据请求的Content-Type自行选择绑定器 |
|||
if err := c.ShouldBind(&login); err == nil { |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"user": login.User, |
|||
"password": login.Password, |
|||
}) |
|||
} else { |
|||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) |
|||
} |
|||
}) |
|||
// 绑定QueryString示例 (/loginQuery?user=q1mi&password=123456) |
|||
router.GET("/login_by_query", func(c *gin.Context) { |
|||
var login Login |
|||
// ShouldBind()会根据请求的Content-Type自行选择绑定器 |
|||
if err := c.ShouldBind(&login); err == nil { |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"user": login.User, |
|||
"password": login.Password, |
|||
}) |
|||
} else { |
|||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) |
|||
} |
|||
}) |
|||
``` |
|||
|
|||
`ShouldBind`会按照下面的顺序解析请求中的数据完成绑定: |
|||
|
|||
1. 如果是 `GET` 请求,只使用 `Form` 绑定引擎(`query`)。 |
|||
2. 如果是 `POST` 请求,首先检查 `content-type` 是否为 `JSON` 或 `XML`,然后再使用 `Form`(`form-data`)。 |
|||
|
|||
## Gin渲染 |
|||
|
|||
我们首先定义一个存放模板文件的`templates`文件夹,然后在其内部按照业务分别定义一个`posts`文件夹和一个`users`文件夹。 `posts/index.html`文件的内容如下: |
|||
|
|||
```template |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
|
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|||
<title>posts/index</title> |
|||
</head> |
|||
<body> |
|||
{{.title}} |
|||
</body> |
|||
</html> |
|||
{{end}} |
|||
``` |
|||
|
|||
`users/index.html`文件的内容如下: |
|||
|
|||
```template |
|||
{{define "users/index.html"}} |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|||
<title>users/index</title> |
|||
</head> |
|||
<body> |
|||
{{.title}} |
|||
</body> |
|||
</html> |
|||
{{end}} |
|||
``` |
|||
|
|||
Gin框架中使用`LoadHTMLGlob()`或者`LoadHTMLFiles()`方法进行HTML模板渲染。 |
|||
|
|||
```go |
|||
func main() { |
|||
r := gin.Default() |
|||
r.LoadHTMLGlob("templates/**/*") |
|||
//r.LoadHTMLFiles("templates/posts/index.html", "templates/users/index.html") |
|||
r.GET("/posts/index", func(c *gin.Context) { |
|||
c.HTML(http.StatusOK, "posts/index.html", gin.H{ |
|||
"title": "posts/index", |
|||
}) |
|||
}) |
|||
|
|||
r.GET("users/index", func(c *gin.Context) { |
|||
c.HTML(http.StatusOK, "users/index.html", gin.H{ |
|||
"title": "users/index", |
|||
}) |
|||
}) |
|||
|
|||
r.Run(":8080") |
|||
} |
|||
``` |
|||
|
|||
## 文件上传 |
|||
|
|||
### 单文件上传 |
|||
|
|||
```go |
|||
// 加载模板 |
|||
router.LoadHTMLFiles("./templates/upload.html") |
|||
// 上传文件 |
|||
router.GET("/upload", func(c *gin.Context) { |
|||
c.HTML(http.StatusOK, "upload.html", nil) |
|||
}) |
|||
|
|||
router.POST("/upload", func(c *gin.Context) { |
|||
// 接收用户上传文件的post请求 |
|||
f, err := c.FormFile("avatar") |
|||
if err != nil { |
|||
c.JSON(http.StatusInternalServerError, gin.H{ |
|||
"message": err.Error(), |
|||
}) |
|||
return |
|||
} |
|||
// 保存到指定目录 dst |
|||
dst := "./upload/" + f.Filename |
|||
c.SaveUploadedFile(f, dst) |
|||
|
|||
// 返回响应 |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"message": fmt.Sprintf("'%s' uploaded!", f.Filename), |
|||
}) |
|||
}) |
|||
``` |
|||
|
|||
### 多文件上传 |
|||
|
|||
```go |
|||
// 多文件上传 |
|||
|
|||
// 加载模板 |
|||
router.LoadHTMLFiles("./templates/uploads.html") |
|||
// 显示多文件上传页面 |
|||
router.GET("/multi-upload", func(c *gin.Context) { |
|||
c.HTML(http.StatusOK, "uploads.html", nil) |
|||
}) |
|||
// 多文件上传 |
|||
router.POST("/multi-upload", func(c *gin.Context) { |
|||
// Multipart form |
|||
form, err := c.MultipartForm() |
|||
if err != nil { |
|||
c.JSON(http.StatusBadRequest, gin.H{"error": "failed to parse multipart form"}) |
|||
return |
|||
} |
|||
|
|||
files := form.File["file"] |
|||
|
|||
for index, file := range files { |
|||
log.Println(file.Filename) |
|||
dst := fmt.Sprintf("./upload/%s_%d", file.Filename, index) |
|||
|
|||
if err := c.SaveUploadedFile(file, dst); err != nil { |
|||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) |
|||
return |
|||
} |
|||
} |
|||
|
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"message": fmt.Sprintf("%d files uploaded!", len(files)), |
|||
}) |
|||
}) |
|||
``` |
|||
|
|||
## 重定向 |
|||
|
|||
### http重定向 |
|||
|
|||
```go |
|||
// http 重定向 |
|||
router.GET("/abc", func(c *gin.Context) { |
|||
c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/") |
|||
}) |
|||
``` |
|||
|
|||
### 路由重定向 |
|||
|
|||
```go |
|||
// 路由重定向 |
|||
router.GET("/def", func(c *gin.Context) { |
|||
c.Request.URL.Path = "/ping" |
|||
router.HandleContext(c) |
|||
}) |
|||
|
|||
``` |
|||
|
|||
## Gin路由 |
|||
|
|||
### 普通路由 |
|||
|
|||
```go |
|||
r.GET("/index", func(c *gin.Context) {...}) |
|||
r.GET("/login", func(c *gin.Context) {...}) |
|||
r.POST("/login", func(c *gin.Context) {...}) |
|||
``` |
|||
|
|||
### any |
|||
|
|||
```go |
|||
r.Any("/test", func(c *gin.Context) {...}) |
|||
``` |
|||
|
|||
### 404页面 |
|||
|
|||
```go |
|||
r.NoRoute(func(c *gin.Context) { |
|||
c.HTML(http.StatusNotFound, "views/404.html", nil) |
|||
}) |
|||
``` |
|||
|
|||
### 路由组 |
|||
|
|||
我们可以将拥有共同URL前缀的路由划分为一个路由组。习惯性一对`{}`包裹同组的路由,这只是为了看着清晰,你用不用`{}`包裹功能上没什么区别。 |
|||
|
|||
```go |
|||
func main() { |
|||
r := gin.Default() |
|||
userGroup := r.Group("/user") |
|||
{ |
|||
userGroup.GET("/index", func(c *gin.Context) {...}) |
|||
userGroup.GET("/login", func(c *gin.Context) {...}) |
|||
userGroup.POST("/login", func(c *gin.Context) {...}) |
|||
|
|||
} |
|||
shopGroup := r.Group("/shop") |
|||
{ |
|||
shopGroup.GET("/index", func(c *gin.Context) {...}) |
|||
shopGroup.GET("/cart", func(c *gin.Context) {...}) |
|||
shopGroup.POST("/checkout", func(c *gin.Context) {...}) |
|||
} |
|||
r.Run() |
|||
} |
|||
``` |
|||
|
|||
路由组也是支持嵌套的,例如: |
|||
|
|||
```go |
|||
shopGroup := r.Group("/shop") |
|||
{ |
|||
shopGroup.GET("/index", func(c *gin.Context) {...}) |
|||
shopGroup.GET("/cart", func(c *gin.Context) {...}) |
|||
shopGroup.POST("/checkout", func(c *gin.Context) {...}) |
|||
// 嵌套路由组 |
|||
xx := shopGroup.Group("xx") |
|||
xx.GET("/oo", func(c *gin.Context) {...}) |
|||
} |
|||
``` |
|||
|
|||
通常我们将路由分组用在划分业务逻辑或划分API版本时。 |
|||
|
|||
### 路由原理 |
|||
|
|||
Gin框架中的路由使用的是[httprouter](https://github.com/julienschmidt/httprouter)这个库。 |
|||
|
|||
其基本原理就是构造一个路由地址的前缀树。 |
After Width: 722 | Height: 393 | Size: 58 KiB |
After Width: 722 | Height: 393 | Size: 58 KiB |
After Width: 389 | Height: 152 | Size: 6.0 KiB |
After Width: 587 | Height: 476 | Size: 22 KiB |
After Width: 861 | Height: 237 | Size: 15 KiB |
@ -0,0 +1,89 @@ |
|||
# Git命令 |
|||
|
|||
|
|||
## 一、仓库初始化与克隆 |
|||
|
|||
- **`git init`** —— 初始化本地仓库 |
|||
- **`git clone <url>`** —— 克隆远程仓库 |
|||
|
|||
|
|||
## 二、文件操作与提交 |
|||
|
|||
- **`git add <file>`** —— 添加单个文件到暂存区 |
|||
- **`git add .`** —— 添加所有文件到暂存区 |
|||
- **`git commit -m "msg"`** —— 提交暂存区到本地仓库 |
|||
- **`git status`** —— 查看工作区状态 |
|||
- **`git log`** —— 查看提交历史 |
|||
- **`git diff`** —— 查看工作区与暂存区的差异 |
|||
|
|||
|
|||
## 三、分支管理 |
|||
|
|||
- **查看分支**: |
|||
- `git branch` —— 查看本地分支 |
|||
- **创建分支**: |
|||
- `git branch <name>` —— 创建新分支 |
|||
- `git checkout -b <name>` —— 创建并切换分支 |
|||
- **切换分支**: |
|||
- `git checkout <name>` —— 切换分支 |
|||
- **合并分支**: |
|||
- `git merge <name>` —— 合并指定分支到当前分支 |
|||
- **删除分支**: |
|||
- `git branch -d <name>` —— 删除已合并分支 |
|||
- `git branch -D <name>` —— 强制删除分支 |
|||
|
|||
|
|||
## 四、远程仓库操作 |
|||
|
|||
- **查看远程信息**: |
|||
- `git remote -v` —— 查看远程仓库信息 |
|||
- **添加远程仓库**: |
|||
- `git remote add <name> <url>` —— 添加远程仓库 |
|||
- **拉取与推送**: |
|||
- `git pull <remote> <branch>` —— 拉取远程分支并合并 |
|||
- `git push <remote> <branch>` —— 推送本地分支到远程 |
|||
- `git push -u <remote> <branch>` —— 首次推送并关联上游分支 |
|||
- **获取远程分支**: |
|||
- `git fetch <remote>` —— 仅获取远程分支(不合并) |
|||
|
|||
|
|||
## 五、版本回退与撤销 |
|||
|
|||
- **撤销修改**: |
|||
- `git checkout -- <file>` —— 撤销工作区修改 |
|||
- `git reset HEAD <file>` —— 撤销暂存区修改 |
|||
- **回退版本**: |
|||
- `git reset --hard <commit>` —— 回退到指定提交 |
|||
- `git revert <commit>` —— 撤销指定提交(生成新提交) |
|||
|
|||
|
|||
## 六、临时存储与标签 |
|||
|
|||
- **临时存储**: |
|||
- `git stash` —— 临时保存当前修改 |
|||
- `git stash pop` —— 恢复最近一次 stash |
|||
- **标签操作**: |
|||
- `git tag <name>` —— 创建轻量标签 |
|||
- `git tag -a <name> -m "msg"` —— 创建带注释标签 |
|||
- `git tag` —— 查看所有标签 |
|||
- `git push <remote> <tag>` —— 推送单个标签到远程 |
|||
- `git push <remote> --tags` —— 推送所有标签 |
|||
|
|||
|
|||
## 七、高级操作 |
|||
|
|||
- **变基与提交管理**: |
|||
- `git rebase <branch>` —— 变基(线性化提交历史) |
|||
- `git cherry-pick <commit>` —— 复制指定提交到当前分支 |
|||
- **代码追溯**: |
|||
- `git blame <file>` —— 查看文件每行的修改历史 |
|||
- `git bisect` —— 二分查找定位问题提交 |
|||
|
|||
|
|||
## 八、配置管理 |
|||
|
|||
- **用户配置**: |
|||
- `git config --global user.name "Your Name"` —— 设置用户名 |
|||
- `git config --global user.email "you@example.com"` —— 设置邮箱 |
|||
- **查看配置**: |
|||
- `git config --list` —— 查看所有配置信息 |
Before Width: 218 | Height: 376 | Size: 14 KiB |
Before Width: 240 | Height: 441 | Size: 11 KiB |
Before Width: 638 | Height: 343 | Size: 74 KiB |
@ -0,0 +1,394 @@ |
|||
# Vue3 |
|||
|
|||
## 优点 |
|||
|
|||
1. Vue3 支持 Vue2 额大多数特性。 |
|||
2. 更好的支持 TypeScript。 |
|||
3. 打包大小减少 41%。 |
|||
4. 初次渲染快 55%,更新渲染快 133%。 |
|||
5. 内存减少 54%。 |
|||
6. 使用 proxy 代替 defineProperty 实现数据响应式。 |
|||
7. 重写虚拟 DOM 的实现和 Tree-Shaking。 |
|||
|
|||
## API |
|||
|
|||
### setup |
|||
|
|||
1. setup 是一个函数。只在初始化时执行一次。以后大部分代码都是在 setup 中写。 |
|||
2. 返回一个对象,对象中的属性或方法,模板中可以直接使用。 |
|||
3. setup 返回的数据会和 data 和 methods 进行合并,setup 优先级更高。 |
|||
4. setup 函数中没有 this。 以后开发都不使用 this |
|||
5. setup 不要写 async 函数。 |
|||
|
|||
> 因为 async 函数必须返回一个 json 对象供模板使用,如果 setup 是一个 async 函数,返回的将是一个 promise 对象。 |
|||
> 如果 setup 是一个 async 函数,那该组件就成了一个异步函数,需要配合 Suspense 组件才能使用 |
|||
|
|||
### ref |
|||
|
|||
让数据变为响应式的数据 |
|||
|
|||
使用方法: |
|||
|
|||
```vue |
|||
//(1)先引用ref |
|||
import {ref} from 'vue'; |
|||
|
|||
//(2)将数据变成响应式的。 |
|||
let data1=ref(12); |
|||
|
|||
//(3)操作数据 |
|||
data1.value = 123; |
|||
``` |
|||
|
|||
### reactive |
|||
|
|||
定义对象格式的响应式数据 |
|||
|
|||
如果使用了 ref,内部会自动将对象/数据转换为 reactive 代理器对象 |
|||
|
|||
### toRefs |
|||
|
|||
将响应式对象中所有属性包装为 ref 对象,并返回包含这些 ref 对象的普通对象。 |
|||
应用:对 trsctive 定义的对象进行 toRefs 包装,包装之后的对象中每个属性都是响应式的。 |
|||
|
|||
### 响应式原理 |
|||
|
|||
通过 proxy(代理):拦截对对象本身的操作,包括属性的读写、删除等操作。 |
|||
通过 Reflect(反射):动态对被代理对象的响应式属性进行特定的操作。 |
|||
|
|||
### watch 和 watchEffect |
|||
|
|||
#### watch - 指定监听数据 |
|||
|
|||
- 监听指定的一个或多个响应式数据,一旦发生变化,就会自动执行监视回调。 |
|||
- 如果是监听 reactive 对象中的属性,必须通过函数来指定。 |
|||
- 监听多个数据,使用数组来指定。 |
|||
- 默认初始时不指定回调,但是通弄过配置 immediate 为 true,来指定初始时立即执行第一次。 |
|||
- 通过配置 deep 为 true,来指定深度监视。 |
|||
|
|||
#### watchEffect - 不指定监听数据 |
|||
|
|||
- 不用直接指定啦监视的数据,回调函数中使用的哪些响应式数据就监听哪些响应式数据。 |
|||
- 默认初始就会执行一次。 |
|||
|
|||
### 生命周期 |
|||
|
|||
onMounted、onUpdated 和 onUnmounted等 |
|||
|
|||
 |
|||
|
|||
### ref获取元素 |
|||
|
|||
> vue2中是用this ref.xxx来获取元素或组件,但是vue3中没有this的概念。 |
|||
> vue3通过ref创建响应式数据的api来获取元素。 |
|||
|
|||
1.使用ref创建响应式数据,假设叫x |
|||
2.模板中绑定ref属性,值为上面的x |
|||
|
|||
注意不能使用v-bind动态绑定。 |
|||
这时 x 就是一个dom元素或组件了。 |
|||
|
|||
```vur |
|||
<!DOCTYPE html> |
|||
<html lang="zh-CN"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Vue 3 ref 引用示例</title> |
|||
<script src="https://cdn.tailwindcss.com"></script> |
|||
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet"> |
|||
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script> |
|||
</head> |
|||
<body class="bg-gray-50 min-h-screen"> |
|||
<div id="app" class="container mx-auto p-4 max-w-3xl"> |
|||
<div class="bg-white rounded-lg shadow-md p-6 mt-8"> |
|||
<h1 class="text-2xl font-bold text-gray-800 mb-6">Vue 3 ref 引用示例</h1> |
|||
|
|||
<div class="mb-6"> |
|||
<button @click="focusInput" class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded"> |
|||
<i class="fa fa-hand-pointer-o mr-2"></i>聚焦输入框 |
|||
</button> |
|||
<button @click="changeText" class="bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded ml-2"> |
|||
<i class="fa fa-pencil mr-2"></i>修改文本 |
|||
</button> |
|||
</div> |
|||
|
|||
<!-- 绑定 ref="x" 到输入框 --> |
|||
<div class="mb-6"> |
|||
<label for="exampleInput" class="block text-gray-700 text-sm font-bold mb-2">普通输入框</label> |
|||
<input type="text" id="exampleInput" ref="x" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="这是一个示例输入框"> |
|||
</div> |
|||
|
|||
<!-- 绑定 ref="x" 到自定义组件 --> |
|||
<div class="mb-6"> |
|||
<label class="block text-gray-700 text-sm font-bold mb-2">自定义组件</label> |
|||
<custom-component ref="x"></custom-component> |
|||
</div> |
|||
|
|||
<div class="bg-gray-100 p-4 rounded-md"> |
|||
<h3 class="font-semibold text-gray-700 mb-2">状态信息</h3> |
|||
<p class="text-gray-600"><i class="fa fa-info-circle mr-2"></i><span v-if="elementInfo">当前引用的元素: {{ elementInfo }}</span><span v-else>未选择元素</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
const { createApp, ref, onMounted } = Vue; |
|||
|
|||
// 自定义组件 |
|||
const CustomComponent = { |
|||
template: ` |
|||
<div class="p-4 border border-gray-300 rounded-md bg-gray-50"> |
|||
<p class="text-gray-700">这是一个自定义组件</p> |
|||
<button @click="doSomething" class="mt-2 bg-purple-500 hover:bg-purple-600 text-white px-3 py-1 rounded text-sm"> |
|||
<i class="fa fa-cog mr-1"></i>组件操作 |
|||
</button> |
|||
</div> |
|||
`, |
|||
methods: { |
|||
doSomething() { |
|||
alert('自定义组件被点击了!'); |
|||
}, |
|||
changeText() { |
|||
this.$el.querySelector('p').textContent = '文本已被修改'; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const app = createApp({ |
|||
components: { |
|||
CustomComponent |
|||
}, |
|||
setup() { |
|||
// 1. 使用 ref 创建响应式数据 x |
|||
const x = ref(null); |
|||
const elementInfo = ref(''); |
|||
|
|||
// 组件挂载后执行 |
|||
onMounted(() => { |
|||
updateElementInfo(); |
|||
}); |
|||
|
|||
// 聚焦输入框方法 |
|||
const focusInput = () => { |
|||
if (x.value) { |
|||
x.value.focus(); |
|||
updateElementInfo(); |
|||
} |
|||
}; |
|||
|
|||
// 修改文本方法 |
|||
const changeText = () => { |
|||
if (x.value) { |
|||
if (x.value.tagName === 'INPUT') { |
|||
x.value.value = '文本已被修改'; |
|||
} else if (typeof x.value.changeText === 'function') { |
|||
x.value.changeText(); |
|||
} |
|||
updateElementInfo(); |
|||
} |
|||
}; |
|||
|
|||
// 更新元素信息 |
|||
const updateElementInfo = () => { |
|||
if (x.value) { |
|||
if (x.value.tagName) { |
|||
elementInfo.value = `HTML 元素 - ${x.value.tagName.toLowerCase()}`; |
|||
} else { |
|||
elementInfo.value = '自定义组件实例'; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
return { |
|||
x, |
|||
focusInput, |
|||
changeText, |
|||
elementInfo |
|||
}; |
|||
} |
|||
}); |
|||
|
|||
app.mount('#app'); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
``` |
|||
|
|||
### 自定义hook函数 |
|||
|
|||
> hook函数翻译成中文就是钩子函数(注意并不是生命周期的钩子函数) |
|||
> 比如ref,reactive,computed,watch,onBeforeMount等都是hook函数,只不过他们都是vue内部hook函数。 |
|||
|
|||
1.创建一个函数,函数名称必须以"use"开头 |
|||
2.函数必须return一些数据。 |
|||
|
|||
`export function useFetchData()` |
|||
|
|||
### shallowReactive与shallowRef |
|||
|
|||
他们都表示浅响应式。 |
|||
|
|||
- shallowReactive:只处理了对象第一层属性的响应式(值响应第一层) |
|||
- shallowRef:只有重新复制时才是响应式(不响应内部数据,只响应整体。) |
|||
|
|||
### -readonly与shallowReadonly |
|||
|
|||
- 他们表示只读代理对象 |
|||
- readonly |
|||
- 深度只读 |
|||
- 设置readonly后,修改响应式数据会报错。 |
|||
- shalloReadonly |
|||
- 浅只读 |
|||
- 设置shalloReadonly后,修改响应式数据的第一层数据会报错。 |
|||
- 应用场景: |
|||
- 在某些特定情况下,我们可能不希望对数据进行更新的操作,那就可以包装成一个只读代理对象,而不能修改或删除。 |
|||
|
|||
### -toRaw与markRaw |
|||
|
|||
- toRaw |
|||
- 返回reactive或readonly对象的原始数据 |
|||
- 这是一个还原方法,可用于临时读取,得到的数据不具有响应式。 |
|||
- markRow: |
|||
- 标记一个对象,使其不具有响应式 |
|||
- 应用场景: |
|||
- 有些只不应被设置为响应式的,例如复杂的第三方实例或Vue组件对象。 |
|||
- 当渲染具有不可变数据源的大列表时,跳过代理转换可以提高性能。 |
|||
|
|||
### toRef |
|||
|
|||
- 为响应式对象上的某个属性创建一个ref引用,更新是应用对象会同步更新。 |
|||
- 与ref的区别:ref是拷贝了一份新的数据指单独操作,更新时相互不影响。 |
|||
|
|||
### -customRef |
|||
|
|||
- 用于自定义一个ref,可以显示的控制依赖追踪和触发相应。 |
|||
- 接受一个工厂函数,两个参数分别用于追踪的track与用于触发相应的trigger,并方法一个带有get和set属性的对象。 |
|||
- 需求:使用customRef实现防抖函数 |
|||
|
|||
### -provide与inject |
|||
|
|||
- provide和inject提供依赖注入,功能类似2.0的provide/inject |
|||
- 实现跨层级组件(祖孙)间通信。 |
|||
|
|||
### -响应式数据的判断 |
|||
|
|||
- isRef:检查一个值是否为一个ref对象。 |
|||
- isReactive:检查一个对象是否否是由reactive对象的响应式代理。 |
|||
- isReadonly:检查一个对象是否由readonly创建的只读代理。 |
|||
- isProxy:检查一个对象是否是由reactive或者readonly方法创建的代理。 |
|||
|
|||
### Fragment |
|||
|
|||
- 在vue2中:组件中必须有一个跟标签 |
|||
- 在vue3中:组价可以没有跟标签,内部会将多个标签包含在一个Fragment虚拟标签中。 |
|||
- 好处:减少标签层级,减小内存占用 |
|||
|
|||
### Teleport |
|||
|
|||
- Teleport提供了一种干净的方法,让组件的HTML在父组件界面外的特定标签(很可能是body)下插入显示。 |
|||
|
|||
### Suspense |
|||
|
|||
> Supense组件是配合一部组件使用的,它可以让一部组件返回数据前渲染一些后背内容。 |
|||
> 那我们首先要学会一个异步组件。 |
|||
|
|||
- 在setup函数总返回一个promise,就是一个异步组件。 |
|||
- setup函数携程async函数,也是一个异步组件。 |
|||
|
|||
### 其他新的API |
|||
|
|||
- 全新的全局API: |
|||
- createApp() |
|||
- defineProperty() |
|||
- defineComponent() |
|||
- nextTick() |
|||
- 将原来的全局API转移到应用对象: |
|||
- app.component() |
|||
- app.config() |
|||
- app.directive() |
|||
- app.mount() |
|||
- app.umount() |
|||
- app.use() |
|||
|
|||
### useSlots和useAttrs |
|||
|
|||
> useSlots 和 useAttrs 是真实的运行时函数,它会返回与 setupContext.slots 和 setupContext.attrs 等价的值,同样也能在普通的组合式 API 中使用。 |
|||
> 使用场景:父组件使用子组件的插槽 |
|||
|
|||
1.父组件 |
|||
|
|||
```xml |
|||
<template> |
|||
<h1>这是父组件</h1> |
|||
|
|||
<p>插槽上面1</p> |
|||
<slots-attrs msg="我是props的msg" heihei="我是attr"> |
|||
<template #header > |
|||
<div style="width:100%;height:100px;border:1px solid green;">我是父组件插槽--插入的内容。。。</div> |
|||
</template> |
|||
</slots-attrs> |
|||
<p>插槽下面2</p> |
|||
|
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import SlotsAttrs from '@/components/04/SlotsAttrs.vue' |
|||
|
|||
</script> |
|||
``` |
|||
|
|||
2.子组件 |
|||
|
|||
```xml |
|||
<template> |
|||
<Child ref="child"/> |
|||
|
|||
{{msg}} |
|||
</template> |
|||
|
|||
|
|||
<script lang="ts" setup> |
|||
import { ref,onMounted } from 'vue'; |
|||
import Child from '@/components/03/Child.vue' |
|||
|
|||
|
|||
const child = ref(null); |
|||
const msg=ref('') |
|||
|
|||
|
|||
onMounted(()=>{ |
|||
console.log("进来了") |
|||
console.log(child.value.msg) |
|||
msg.value = child.value.msg; |
|||
}) |
|||
|
|||
</script> |
|||
``` |
|||
|
|||
## 路由 |
|||
|
|||
(1)userRout:获得当前路由对象。 |
|||
(2)useRouter:获得路由实例,可以进行路由跳转。 |
|||
|
|||
### 使用 |
|||
|
|||
```javascript |
|||
import {useRoute,useRouter} from "vue-router" |
|||
``` |
|||
|
|||
## 实战 |
|||
|
|||
创建项目后 |
|||
|
|||
### ElementPlus |
|||
|
|||
引入 |
|||
|
|||
```sh |
|||
npm install element-plus --save |
|||
``` |
|||
|
|||
尝试静态界面 |
|||
|
|||
 |
After Width: 1582 | Height: 876 | Size: 50 KiB |
@ -0,0 +1,583 @@ |
|||
# 股票知识 |
|||
|
|||
## 趋势理论 |
|||
|
|||
根据道氏理论,股票价格运动有三种趋势 |
|||
|
|||
主要趋势、次要趋势和短暂趋势 |
|||
|
|||
### 主要趋势 |
|||
|
|||
主要趋势是股票价格广泛或全面性上升或下降的变动情形,持续时间通常为一年或以上。 |
|||
|
|||
从大的角度来看上涨和下跌的变动 |
|||
|
|||
主要趋势上升的,被称为多头市场 |
|||
|
|||
主要趋势下降的,被称为空头市场 |
|||
|
|||
#### 多头市场 |
|||
|
|||
多头市场是指主要趋势为上升的市场状态,也称为主要上升趋势。 |
|||
|
|||
三阶段:进货期->十分稳定的上升和增多的交易量->交易沸腾,成交量上升 |
|||
|
|||
#### 空头市场 |
|||
|
|||
也称为主要下跌趋势,是股票市场的一种状态,其主要特征是股价普遍下降。 |
|||
|
|||
三阶段:出货期->恐慌期->下跌期(继续下跌) |
|||
|
|||
### 次要趋势(修正趋势) |
|||
|
|||
次要趋势是主要趋势的调整,与主要趋势方向相反,持续时间从3周到数月不等。 |
|||
|
|||
### 短暂趋势 |
|||
|
|||
短暂趋势是短期的波动,很少超过三个星期,通常少于6天 |
|||
|
|||
每日行情的波动, |
|||
|
|||
长期投资者关注股价基本趋势,投机者关注修正趋势,短暂趋势重要性小,容易受人操控,一般不关注 |
|||
|
|||
### 道氏理论基本要点 |
|||
|
|||
#### 评价价格包容消化一切 |
|||
|
|||
### 如何判断大趋势运行方向 |
|||
|
|||
 |
|||
|
|||
通过趋势线 |
|||
|
|||
## 趋势理论延伸——趋势线 |
|||
|
|||
### 百分比回撤 |
|||
|
|||
通常,市场不会直线上升,也不会竖直跌落 |
|||
|
|||
 |
|||
|
|||
百分比回撤+蜡烛图结合 很有用 |
|||
|
|||
|
|||
|
|||
## 股票价格的运行规律 |
|||
|
|||
### 股价运行规律 |
|||
|
|||
1. 股价应在多空双方均衡位置上下波动。 |
|||
2. 原有的平衡被打破后,股价将寻找新的平衡。 |
|||
|
|||
持续整理保持平衡—打破平衡—新的平衡—再打破平衡-…… |
|||
|
|||
### 支撑线和压力线 |
|||
|
|||
支撑线又称为抵抗线。股价下跌到某个位置,股价停止下跌, |
|||
|
|||
压力线又称为阻力线。当股价上涨到某价位附近时,股价会停止上涨 |
|||
|
|||
 |
|||
|
|||
前期的高点和低点都是很重要的压力和支持 |
|||
|
|||
一条支撑线和压力线对当前时期股价变化影响的重要性有三方面的考虑: |
|||
|
|||
1. 股价在这个区域持续时间的长短 |
|||
2. 股价在这个区域伴随的成交量大小 |
|||
3. 这个支撑区域或压力区域发生的时间,距离当前这个时期的远近 |
|||
|
|||
持续时间长,成交量大,离现在近,则影响大 |
|||
|
|||
### 趋势线和轨道线 |
|||
|
|||
#### 趋势线 |
|||
|
|||
趋势线是衡量价格变化趋势的 |
|||
|
|||
上升趋势,两个显著的低点连成一条直线,就是上升趋势线 |
|||
|
|||
下降趋势,两个显著的高点连成一条直线,就是下降趋势线 |
|||
|
|||
上升趋势线是支持线的一种下降趋势线是压力线的一种 |
|||
|
|||
##### 趋势线两种作用 |
|||
|
|||
1. 对股价今后的变动起约束 |
|||
2. 趋势线被突破后,就说明股价下一步的趋势将要反向,越有效的趋势线被突破,其转势的信号越强烈 |
|||
|
|||
##### 怎么才算对趋势线的突破 |
|||
|
|||
1. 收盘价突破趋势线比日内的最高最低价突破趋势线重要; |
|||
2. 穿越趋势线后,离趋势线越远,突破越有效。人们可以根据各个股票的具体情况,自己制定一个界限,一般是用突破的幅度,如3%; |
|||
3. 穿越趋势线后,在趋势线的另一方停留的时间越长,突破越有效。 |
|||
|
|||
#### 轨道线 |
|||
|
|||
又称通道线,管道线 |
|||
|
|||
两条平行线组成一个轨道,这就是常说的上升和下降轨道即趋势线的平行线 |
|||
|
|||
管道线持续的时间越长,其意义越重大,一个长期的上升通道和下降通道被有效突破,它将代表着一个新趋势的开始。 |
|||
|
|||
#### 买卖法则 |
|||
|
|||
##### 上升趋势:一买三卖法则 |
|||
|
|||
一买:接触到趋势线买 |
|||
|
|||
三卖:接触到轨道线卖,突破管道线卖,跌破趋势线卖 |
|||
|
|||
 |
|||
|
|||
##### 下降趋势:一卖三买法则 |
|||
|
|||
一卖:接触趋势线卖 |
|||
|
|||
三买:接触管道线买,跌破管道线买,突破趋势线买 |
|||
|
|||
 |
|||
|
|||
# 学习内容-Gin框架的基本使用 |
|||
|
|||
## 下载与安装 |
|||
|
|||
> 更改环境变量 GOPATH |
|||
> |
|||
> 方便将包下载到其他的盘符目录 |
|||
> |
|||
> 参考:[2024年go安装教程(Windows)包括配置GOPATH-CSDN博客](https://blog.csdn.net/weixin_63860405/article/details/139732041) |
|||
|
|||
### 下载 |
|||
|
|||
```shell |
|||
go get -u github.com/gin-gonic/gin |
|||
``` |
|||
|
|||
 |
|||
|
|||
## 基础使用 |
|||
|
|||
### GET请求 |
|||
|
|||
```go |
|||
package main |
|||
|
|||
import "github.com/gin-gonic/gin" |
|||
|
|||
func main() { |
|||
router := gin.Default() |
|||
router.GET("/ping", func(c *gin.Context) { |
|||
c.JSON(200, gin.H{ |
|||
"message": "Hello World!", |
|||
}) |
|||
}) |
|||
router.Run() // 监听并在 0.0.0.0:8080 上启动服务 |
|||
// 默认是在8080端口启动服务,如果8080端口被占用,则自动寻找可用端口启动服务,可以指定端口 |
|||
} |
|||
``` |
|||
|
|||
 |
|||
|
|||
### ANY请求 |
|||
|
|||
根据请求来选择(使用if else) |
|||
|
|||
```go |
|||
// Any 请求 |
|||
router.Any("/any", func(c *gin.Context) { |
|||
if c.Request.Method == "POST" { |
|||
c.JSON(200, gin.H{ |
|||
"message": "POST", |
|||
}) |
|||
} else if c.Request.Method == "GET" { |
|||
c.JSON(200, gin.H{ |
|||
"message": "GET", |
|||
}) |
|||
} else { |
|||
c.JSON(200, gin.H{ |
|||
"message": "Any", |
|||
}) |
|||
} |
|||
}) |
|||
``` |
|||
|
|||
### POST请求 |
|||
|
|||
```go |
|||
// POST 请求 |
|||
router.POST("/post", func(c *gin.Context) { |
|||
c.JSON(200, gin.H{ |
|||
"message": "POST", |
|||
}) |
|||
}) |
|||
|
|||
``` |
|||
|
|||
 |
|||
|
|||
## 参数获取 |
|||
|
|||
### 获取query string 参数 |
|||
|
|||
格式:URL `?`后携带参数 |
|||
|
|||
例如:/user/searcher?username=xxx&address=xxx |
|||
|
|||
|
|||
|
|||
```go |
|||
// 获取参数,query string |
|||
router.GET("/user/search", func(c *gin.Context) { |
|||
username := c.DefaultQuery("username", "lihuibear") |
|||
address := c.Query("address") |
|||
|
|||
// 返回json数据 |
|||
c.JSON(200, gin.H{ |
|||
"username": username, |
|||
"address": address, |
|||
}) |
|||
|
|||
}) |
|||
``` |
|||
|
|||
 |
|||
|
|||
### 获取 form参数 |
|||
|
|||
当前端请求的数据通过form表单提交时,例如向`/user/search`发送一个POST请求,获取请求数据的方式如下: |
|||
|
|||
```go |
|||
router.POST("/user/search_by_form", func(c *gin.Context) { |
|||
// DefaultPostForm取不到值时会返回指定的默认值 |
|||
//username := c.DefaultPostForm("username", "小王子") |
|||
username := c.PostForm("username") |
|||
address := c.PostForm("address") |
|||
//输出json结果给调用方 |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"message": "ok", |
|||
"username": username, |
|||
"address": address, |
|||
}) |
|||
}) |
|||
``` |
|||
|
|||
### 获取JSON参数 |
|||
|
|||
当前端请求的数据通过JSON提交时,例如向`/json`发送一个JSON格式的POST请求,则获取请求参数的方式如下: |
|||
|
|||
```go |
|||
//获取JSON参数 |
|||
router.POST("/json", func(c *gin.Context) { |
|||
// 注意:下面为了举例子方便,暂时忽略了错误处理 |
|||
b, _ := c.GetRawData() // 从c.Request.Body读取请求数据 |
|||
// 定义map或结构体 |
|||
var m map[string]interface{} |
|||
// 反序列化 |
|||
_ = json.Unmarshal(b, &m) |
|||
|
|||
c.JSON(http.StatusOK, m) |
|||
}) |
|||
``` |
|||
|
|||
### 获取path参数 |
|||
|
|||
请求的参数通过URL路径传递,例如:`/user/search/小王子/沙河`。 获取请求URL路径中的参数的方式如下: |
|||
|
|||
```go |
|||
// 获取path参数 |
|||
router.GET("/user/search/:username/:address", func(c *gin.Context) { |
|||
username := c.Param("username") |
|||
address := c.Param("address") |
|||
//输出json结果给调用方 |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"message": "ok", |
|||
"username": username, |
|||
"address": address, |
|||
}) |
|||
}) |
|||
``` |
|||
|
|||
### 参数绑定 ShouldBind() |
|||
|
|||
为了能够更方便的获取请求相关参数,提高开发效率,我们可以基于请求的`Content-Type`识别请求数据类型并利用反射机制自动提取请求中`QueryString`、`form表单`、`JSON`、`XML`等参数到结构体中。 |
|||
|
|||
```go |
|||
// 参数绑定 |
|||
|
|||
// 绑定JSON的示例 ({"user": "q1mi", "password": "123456"}) |
|||
router.POST("/login_by_JSON", func(c *gin.Context) { |
|||
var login Login |
|||
|
|||
if err := c.ShouldBind(&login); err == nil { |
|||
fmt.Printf("login info:%#v\n", login) |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"user": login.User, |
|||
"password": login.Password, |
|||
}) |
|||
} else { |
|||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) |
|||
} |
|||
}) |
|||
// 绑定form表单示例 (user=q1mi&password=123456) |
|||
router.POST("/login_by_form", func(c *gin.Context) { |
|||
var login Login |
|||
// ShouldBind()会根据请求的Content-Type自行选择绑定器 |
|||
if err := c.ShouldBind(&login); err == nil { |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"user": login.User, |
|||
"password": login.Password, |
|||
}) |
|||
} else { |
|||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) |
|||
} |
|||
}) |
|||
// 绑定QueryString示例 (/loginQuery?user=q1mi&password=123456) |
|||
router.GET("/login_by_query", func(c *gin.Context) { |
|||
var login Login |
|||
// ShouldBind()会根据请求的Content-Type自行选择绑定器 |
|||
if err := c.ShouldBind(&login); err == nil { |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"user": login.User, |
|||
"password": login.Password, |
|||
}) |
|||
} else { |
|||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) |
|||
} |
|||
}) |
|||
``` |
|||
|
|||
`ShouldBind`会按照下面的顺序解析请求中的数据完成绑定: |
|||
|
|||
1. 如果是 `GET` 请求,只使用 `Form` 绑定引擎(`query`)。 |
|||
2. 如果是 `POST` 请求,首先检查 `content-type` 是否为 `JSON` 或 `XML`,然后再使用 `Form`(`form-data`)。 |
|||
|
|||
## Gin渲染 |
|||
|
|||
我们首先定义一个存放模板文件的`templates`文件夹,然后在其内部按照业务分别定义一个`posts`文件夹和一个`users`文件夹。 `posts/index.html`文件的内容如下: |
|||
|
|||
```template |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
|
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|||
<title>posts/index</title> |
|||
</head> |
|||
<body> |
|||
{{.title}} |
|||
</body> |
|||
</html> |
|||
{{end}} |
|||
``` |
|||
|
|||
`users/index.html`文件的内容如下: |
|||
|
|||
```template |
|||
{{define "users/index.html"}} |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|||
<title>users/index</title> |
|||
</head> |
|||
<body> |
|||
{{.title}} |
|||
</body> |
|||
</html> |
|||
{{end}} |
|||
``` |
|||
|
|||
Gin框架中使用`LoadHTMLGlob()`或者`LoadHTMLFiles()`方法进行HTML模板渲染。 |
|||
|
|||
```go |
|||
func main() { |
|||
r := gin.Default() |
|||
r.LoadHTMLGlob("templates/**/*") |
|||
//r.LoadHTMLFiles("templates/posts/index.html", "templates/users/index.html") |
|||
r.GET("/posts/index", func(c *gin.Context) { |
|||
c.HTML(http.StatusOK, "posts/index.html", gin.H{ |
|||
"title": "posts/index", |
|||
}) |
|||
}) |
|||
|
|||
r.GET("users/index", func(c *gin.Context) { |
|||
c.HTML(http.StatusOK, "users/index.html", gin.H{ |
|||
"title": "users/index", |
|||
}) |
|||
}) |
|||
|
|||
r.Run(":8080") |
|||
} |
|||
``` |
|||
|
|||
## 文件上传 |
|||
|
|||
### 单文件上传 |
|||
|
|||
```go |
|||
// 加载模板 |
|||
router.LoadHTMLFiles("./templates/upload.html") |
|||
// 上传文件 |
|||
router.GET("/upload", func(c *gin.Context) { |
|||
c.HTML(http.StatusOK, "upload.html", nil) |
|||
}) |
|||
|
|||
router.POST("/upload", func(c *gin.Context) { |
|||
// 接收用户上传文件的post请求 |
|||
f, err := c.FormFile("avatar") |
|||
if err != nil { |
|||
c.JSON(http.StatusInternalServerError, gin.H{ |
|||
"message": err.Error(), |
|||
}) |
|||
return |
|||
} |
|||
// 保存到指定目录 dst |
|||
dst := "./upload/" + f.Filename |
|||
c.SaveUploadedFile(f, dst) |
|||
|
|||
// 返回响应 |
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"message": fmt.Sprintf("'%s' uploaded!", f.Filename), |
|||
}) |
|||
}) |
|||
``` |
|||
|
|||
### 多文件上传 |
|||
|
|||
```go |
|||
// 多文件上传 |
|||
|
|||
// 加载模板 |
|||
router.LoadHTMLFiles("./templates/uploads.html") |
|||
// 显示多文件上传页面 |
|||
router.GET("/multi-upload", func(c *gin.Context) { |
|||
c.HTML(http.StatusOK, "uploads.html", nil) |
|||
}) |
|||
// 多文件上传 |
|||
router.POST("/multi-upload", func(c *gin.Context) { |
|||
// Multipart form |
|||
form, err := c.MultipartForm() |
|||
if err != nil { |
|||
c.JSON(http.StatusBadRequest, gin.H{"error": "failed to parse multipart form"}) |
|||
return |
|||
} |
|||
|
|||
files := form.File["file"] |
|||
|
|||
for index, file := range files { |
|||
log.Println(file.Filename) |
|||
dst := fmt.Sprintf("./upload/%s_%d", file.Filename, index) |
|||
|
|||
if err := c.SaveUploadedFile(file, dst); err != nil { |
|||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) |
|||
return |
|||
} |
|||
} |
|||
|
|||
c.JSON(http.StatusOK, gin.H{ |
|||
"message": fmt.Sprintf("%d files uploaded!", len(files)), |
|||
}) |
|||
}) |
|||
``` |
|||
|
|||
## 重定向 |
|||
|
|||
### http重定向 |
|||
|
|||
```go |
|||
// http 重定向 |
|||
router.GET("/abc", func(c *gin.Context) { |
|||
c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/") |
|||
}) |
|||
``` |
|||
|
|||
### 路由重定向 |
|||
|
|||
```go |
|||
// 路由重定向 |
|||
router.GET("/def", func(c *gin.Context) { |
|||
c.Request.URL.Path = "/ping" |
|||
router.HandleContext(c) |
|||
}) |
|||
|
|||
``` |
|||
|
|||
## Gin路由 |
|||
|
|||
### 普通路由 |
|||
|
|||
```go |
|||
r.GET("/index", func(c *gin.Context) {...}) |
|||
r.GET("/login", func(c *gin.Context) {...}) |
|||
r.POST("/login", func(c *gin.Context) {...}) |
|||
``` |
|||
|
|||
### any |
|||
|
|||
```go |
|||
r.Any("/test", func(c *gin.Context) {...}) |
|||
``` |
|||
|
|||
### 404页面 |
|||
|
|||
```go |
|||
r.NoRoute(func(c *gin.Context) { |
|||
c.HTML(http.StatusNotFound, "views/404.html", nil) |
|||
}) |
|||
``` |
|||
|
|||
### 路由组 |
|||
|
|||
我们可以将拥有共同URL前缀的路由划分为一个路由组。习惯性一对`{}`包裹同组的路由,这只是为了看着清晰,你用不用`{}`包裹功能上没什么区别。 |
|||
|
|||
```go |
|||
func main() { |
|||
r := gin.Default() |
|||
userGroup := r.Group("/user") |
|||
{ |
|||
userGroup.GET("/index", func(c *gin.Context) {...}) |
|||
userGroup.GET("/login", func(c *gin.Context) {...}) |
|||
userGroup.POST("/login", func(c *gin.Context) {...}) |
|||
|
|||
} |
|||
shopGroup := r.Group("/shop") |
|||
{ |
|||
shopGroup.GET("/index", func(c *gin.Context) {...}) |
|||
shopGroup.GET("/cart", func(c *gin.Context) {...}) |
|||
shopGroup.POST("/checkout", func(c *gin.Context) {...}) |
|||
} |
|||
r.Run() |
|||
} |
|||
``` |
|||
|
|||
路由组也是支持嵌套的,例如: |
|||
|
|||
```go |
|||
shopGroup := r.Group("/shop") |
|||
{ |
|||
shopGroup.GET("/index", func(c *gin.Context) {...}) |
|||
shopGroup.GET("/cart", func(c *gin.Context) {...}) |
|||
shopGroup.POST("/checkout", func(c *gin.Context) {...}) |
|||
// 嵌套路由组 |
|||
xx := shopGroup.Group("xx") |
|||
xx.GET("/oo", func(c *gin.Context) {...}) |
|||
} |
|||
``` |
|||
|
|||
通常我们将路由分组用在划分业务逻辑或划分API版本时。 |
|||
|
|||
### 路由原理 |
|||
|
|||
Gin框架中的路由使用的是[httprouter](https://github.com/julienschmidt/httprouter)这个库。 |
|||
|
|||
其基本原理就是构造一个路由地址的前缀树。 |
|||
|
|||
# 明日计划 |
|||
|
|||
1. 学习Goframe框架 |
|||
2. 学习股票知识 |
@ -0,0 +1,481 @@ |
|||
# K线的画法 |
|||
|
|||
## k线的画法 |
|||
|
|||
K线,又称日本线,起源于200年前的日本,最初用于米市交易。 |
|||
|
|||
K线是一种柱状线条,由影线和实体组成。 |
|||
|
|||
影线在实体上方的部分叫上影线,下方的部分叫下影线。 |
|||
|
|||
实体分为阴线和阳线两种,分别用黑(阴)线和红(阳)线表示。 |
|||
|
|||
一条K线记录的是某一只股票或指数一天的价格变动情况,将每天的K线按时间顺序排列,就组成这只股票自上市以来每天的价格变动情况,称为日K线图。 |
|||
|
|||
价格变动体现在四个方面(主要),开盘价、最高价、最低价、收盘价 |
|||
|
|||
阴线阳线的开盘价,收盘价相反 |
|||
|
|||
 |
|||
|
|||
## K线的种类 |
|||
|
|||
K线的种类主要有以下几种: |
|||
|
|||
1. **光头阳线和光头阴线**:没有上影线的K线,当收盘价或开盘价正好同最高价相等时出现。 |
|||
2. **光脚阳线和光脚阴线**:没有下影线的K线,当收盘价或开盘价正好同最低价相等时出现。 |
|||
3. **光头光脚的阳线和阴线**:既没有上影线也没有下影线的K线,当开盘价和收盘价分别与最高价和最低价相等时出现。 |
|||
4. **十字星**:收盘价与开盘价相同时出现的K线,没有实体。 |
|||
5. **T字型和倒T字型**:在十字星的基础上,加上光头或光脚的条件,没有实体,形状像英文字母T。 |
|||
6. **一字型**:四个价格都一样,在开盘即封时,在涨停或跌停时出现。 |
|||
|
|||
## K线的变化 |
|||
|
|||
### 三要素 |
|||
|
|||
1. 阴阳代表总体趋势 |
|||
2. 长短代表内在动力和趋势强弱 |
|||
3. 阴线代表转折信号 |
|||
|
|||
### K线间的相互关系 |
|||
|
|||
光头光脚长阳线,是强烈上升过程的最高形式,即后市看好的极端; |
|||
|
|||
光头光脚的长阴线,是强烈下跌过程的最高形式,即后市看坏的极端; |
|||
|
|||
十字星是多空双方平衡状态的最高形式 |
|||
|
|||
### K线长短相互关系 |
|||
|
|||
K线长短代表内在动力大小,其中,实体长度又可代表趋势强弱。 |
|||
|
|||
### 线长度加大会有三种变化 |
|||
|
|||
K线由小阳线、中阳线到长阳线不断加长,说明多方力量变得越来越强; |
|||
|
|||
K线由小阴线、中阴线到长阴线不断加长,说明空方力量变得越来越强; |
|||
|
|||
K线实体变化不大,上影线和下影线越来越长,说明市场内在动力越来越强,多空搏斗越来越激烈。 |
|||
|
|||
### K线长度变化与动力转化 |
|||
|
|||
#### 影线长短互相影响 |
|||
|
|||
 |
|||
|
|||
 |
|||
|
|||
### K线分析的应用时机 |
|||
|
|||
阳线出现在盘整或股价下跌趋势末期时,代表股价可能会开始反转向上; |
|||
|
|||
阴线出现在盘整或股价上涨趋势末期时,代表股价可能会开始反转向下 |
|||
|
|||
出现极长下影线时,表示买方支撑力较强 |
|||
|
|||
出现极长上影线时,表示卖压大。 |
|||
|
|||
十字线可视为反转信号 |
|||
|
|||
|
|||
|
|||
# Vue3 |
|||
|
|||
## 优点 |
|||
|
|||
1. Vue3 支持 Vue2 额大多数特性。 |
|||
2. 更好的支持 TypeScript。 |
|||
3. 打包大小减少 41%。 |
|||
4. 初次渲染快 55%,更新渲染快 133%。 |
|||
5. 内存减少 54%。 |
|||
6. 使用 proxy 代替 defineProperty 实现数据响应式。 |
|||
7. 重写虚拟 DOM 的实现和 Tree-Shaking。 |
|||
|
|||
## API |
|||
|
|||
### setup |
|||
|
|||
1. setup 是一个函数。只在初始化时执行一次。以后大部分代码都是在 setup 中写。 |
|||
2. 返回一个对象,对象中的属性或方法,模板中可以直接使用。 |
|||
3. setup 返回的数据会和 data 和 methods 进行合并,setup 优先级更高。 |
|||
4. setup 函数中没有 this。 以后开发都不使用 this |
|||
5. setup 不要写 async 函数。 |
|||
|
|||
> 因为 async 函数必须返回一个 json 对象供模板使用,如果 setup 是一个 async 函数,返回的将是一个 promise 对象。 |
|||
> 如果 setup 是一个 async 函数,那该组件就成了一个异步函数,需要配合 Suspense 组件才能使用 |
|||
|
|||
### ref |
|||
|
|||
让数据变为响应式的数据 |
|||
|
|||
使用方法: |
|||
|
|||
```vue |
|||
//(1)先引用ref |
|||
import {ref} from 'vue'; |
|||
|
|||
//(2)将数据变成响应式的。 |
|||
let data1=ref(12); |
|||
|
|||
//(3)操作数据 |
|||
data1.value = 123; |
|||
``` |
|||
|
|||
### reactive |
|||
|
|||
定义对象格式的响应式数据 |
|||
|
|||
如果使用了 ref,内部会自动将对象/数据转换为 reactive 代理器对象 |
|||
|
|||
### toRefs |
|||
|
|||
将响应式对象中所有属性包装为 ref 对象,并返回包含这些 ref 对象的普通对象。 |
|||
应用:对 trsctive 定义的对象进行 toRefs 包装,包装之后的对象中每个属性都是响应式的。 |
|||
|
|||
### 响应式原理 |
|||
|
|||
通过 proxy(代理):拦截对对象本身的操作,包括属性的读写、删除等操作。 |
|||
通过 Reflect(反射):动态对被代理对象的响应式属性进行特定的操作。 |
|||
|
|||
### watch 和 watchEffect |
|||
|
|||
#### watch - 指定监听数据 |
|||
|
|||
- 监听指定的一个或多个响应式数据,一旦发生变化,就会自动执行监视回调。 |
|||
- 如果是监听 reactive 对象中的属性,必须通过函数来指定。 |
|||
- 监听多个数据,使用数组来指定。 |
|||
- 默认初始时不指定回调,但是通弄过配置 immediate 为 true,来指定初始时立即执行第一次。 |
|||
- 通过配置 deep 为 true,来指定深度监视。 |
|||
|
|||
#### watchEffect - 不指定监听数据 |
|||
|
|||
- 不用直接指定啦监视的数据,回调函数中使用的哪些响应式数据就监听哪些响应式数据。 |
|||
- 默认初始就会执行一次。 |
|||
|
|||
### 生命周期 |
|||
|
|||
onMounted、onUpdated 和 onUnmounted等 |
|||
|
|||
 |
|||
|
|||
### ref获取元素 |
|||
|
|||
> vue2中是用this ref.xxx来获取元素或组件,但是vue3中没有this的概念。 |
|||
> vue3通过ref创建响应式数据的api来获取元素。 |
|||
|
|||
1.使用ref创建响应式数据,假设叫x |
|||
2.模板中绑定ref属性,值为上面的x |
|||
|
|||
注意不能使用v-bind动态绑定。 |
|||
这时 x 就是一个dom元素或组件了。 |
|||
|
|||
```vur |
|||
<!DOCTYPE html> |
|||
<html lang="zh-CN"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Vue 3 ref 引用示例</title> |
|||
<script src="https://cdn.tailwindcss.com"></script> |
|||
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet"> |
|||
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script> |
|||
</head> |
|||
<body class="bg-gray-50 min-h-screen"> |
|||
<div id="app" class="container mx-auto p-4 max-w-3xl"> |
|||
<div class="bg-white rounded-lg shadow-md p-6 mt-8"> |
|||
<h1 class="text-2xl font-bold text-gray-800 mb-6">Vue 3 ref 引用示例</h1> |
|||
|
|||
<div class="mb-6"> |
|||
<button @click="focusInput" class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded"> |
|||
<i class="fa fa-hand-pointer-o mr-2"></i>聚焦输入框 |
|||
</button> |
|||
<button @click="changeText" class="bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded ml-2"> |
|||
<i class="fa fa-pencil mr-2"></i>修改文本 |
|||
</button> |
|||
</div> |
|||
|
|||
<!-- 绑定 ref="x" 到输入框 --> |
|||
<div class="mb-6"> |
|||
<label for="exampleInput" class="block text-gray-700 text-sm font-bold mb-2">普通输入框</label> |
|||
<input type="text" id="exampleInput" ref="x" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="这是一个示例输入框"> |
|||
</div> |
|||
|
|||
<!-- 绑定 ref="x" 到自定义组件 --> |
|||
<div class="mb-6"> |
|||
<label class="block text-gray-700 text-sm font-bold mb-2">自定义组件</label> |
|||
<custom-component ref="x"></custom-component> |
|||
</div> |
|||
|
|||
<div class="bg-gray-100 p-4 rounded-md"> |
|||
<h3 class="font-semibold text-gray-700 mb-2">状态信息</h3> |
|||
<p class="text-gray-600"><i class="fa fa-info-circle mr-2"></i><span v-if="elementInfo">当前引用的元素: {{ elementInfo }}</span><span v-else>未选择元素</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
const { createApp, ref, onMounted } = Vue; |
|||
|
|||
// 自定义组件 |
|||
const CustomComponent = { |
|||
template: ` |
|||
<div class="p-4 border border-gray-300 rounded-md bg-gray-50"> |
|||
<p class="text-gray-700">这是一个自定义组件</p> |
|||
<button @click="doSomething" class="mt-2 bg-purple-500 hover:bg-purple-600 text-white px-3 py-1 rounded text-sm"> |
|||
<i class="fa fa-cog mr-1"></i>组件操作 |
|||
</button> |
|||
</div> |
|||
`, |
|||
methods: { |
|||
doSomething() { |
|||
alert('自定义组件被点击了!'); |
|||
}, |
|||
changeText() { |
|||
this.$el.querySelector('p').textContent = '文本已被修改'; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const app = createApp({ |
|||
components: { |
|||
CustomComponent |
|||
}, |
|||
setup() { |
|||
// 1. 使用 ref 创建响应式数据 x |
|||
const x = ref(null); |
|||
const elementInfo = ref(''); |
|||
|
|||
// 组件挂载后执行 |
|||
onMounted(() => { |
|||
updateElementInfo(); |
|||
}); |
|||
|
|||
// 聚焦输入框方法 |
|||
const focusInput = () => { |
|||
if (x.value) { |
|||
x.value.focus(); |
|||
updateElementInfo(); |
|||
} |
|||
}; |
|||
|
|||
// 修改文本方法 |
|||
const changeText = () => { |
|||
if (x.value) { |
|||
if (x.value.tagName === 'INPUT') { |
|||
x.value.value = '文本已被修改'; |
|||
} else if (typeof x.value.changeText === 'function') { |
|||
x.value.changeText(); |
|||
} |
|||
updateElementInfo(); |
|||
} |
|||
}; |
|||
|
|||
// 更新元素信息 |
|||
const updateElementInfo = () => { |
|||
if (x.value) { |
|||
if (x.value.tagName) { |
|||
elementInfo.value = `HTML 元素 - ${x.value.tagName.toLowerCase()}`; |
|||
} else { |
|||
elementInfo.value = '自定义组件实例'; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
return { |
|||
x, |
|||
focusInput, |
|||
changeText, |
|||
elementInfo |
|||
}; |
|||
} |
|||
}); |
|||
|
|||
app.mount('#app'); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
``` |
|||
|
|||
### 自定义hook函数 |
|||
|
|||
> hook函数翻译成中文就是钩子函数(注意并不是生命周期的钩子函数) |
|||
> 比如ref,reactive,computed,watch,onBeforeMount等都是hook函数,只不过他们都是vue内部hook函数。 |
|||
|
|||
1.创建一个函数,函数名称必须以"use"开头 |
|||
2.函数必须return一些数据。 |
|||
|
|||
`export function useFetchData()` |
|||
|
|||
### shallowReactive与shallowRef |
|||
|
|||
他们都表示浅响应式。 |
|||
|
|||
- shallowReactive:只处理了对象第一层属性的响应式(值响应第一层) |
|||
- shallowRef:只有重新复制时才是响应式(不响应内部数据,只响应整体。) |
|||
|
|||
### -readonly与shallowReadonly |
|||
|
|||
- 他们表示只读代理对象 |
|||
- readonly |
|||
- 深度只读 |
|||
- 设置readonly后,修改响应式数据会报错。 |
|||
- shalloReadonly |
|||
- 浅只读 |
|||
- 设置shalloReadonly后,修改响应式数据的第一层数据会报错。 |
|||
- 应用场景: |
|||
- 在某些特定情况下,我们可能不希望对数据进行更新的操作,那就可以包装成一个只读代理对象,而不能修改或删除。 |
|||
|
|||
### -toRaw与markRaw |
|||
|
|||
- toRaw |
|||
- 返回reactive或readonly对象的原始数据 |
|||
- 这是一个还原方法,可用于临时读取,得到的数据不具有响应式。 |
|||
- markRow: |
|||
- 标记一个对象,使其不具有响应式 |
|||
- 应用场景: |
|||
- 有些只不应被设置为响应式的,例如复杂的第三方实例或Vue组件对象。 |
|||
- 当渲染具有不可变数据源的大列表时,跳过代理转换可以提高性能。 |
|||
|
|||
### toRef |
|||
|
|||
- 为响应式对象上的某个属性创建一个ref引用,更新是应用对象会同步更新。 |
|||
- 与ref的区别:ref是拷贝了一份新的数据指单独操作,更新时相互不影响。 |
|||
|
|||
### -customRef |
|||
|
|||
- 用于自定义一个ref,可以显示的控制依赖追踪和触发相应。 |
|||
- 接受一个工厂函数,两个参数分别用于追踪的track与用于触发相应的trigger,并方法一个带有get和set属性的对象。 |
|||
- 需求:使用customRef实现防抖函数 |
|||
|
|||
### -provide与inject |
|||
|
|||
- provide和inject提供依赖注入,功能类似2.0的provide/inject |
|||
- 实现跨层级组件(祖孙)间通信。 |
|||
|
|||
### -响应式数据的判断 |
|||
|
|||
- isRef:检查一个值是否为一个ref对象。 |
|||
- isReactive:检查一个对象是否否是由reactive对象的响应式代理。 |
|||
- isReadonly:检查一个对象是否由readonly创建的只读代理。 |
|||
- isProxy:检查一个对象是否是由reactive或者readonly方法创建的代理。 |
|||
|
|||
### Fragment |
|||
|
|||
- 在vue2中:组件中必须有一个跟标签 |
|||
- 在vue3中:组价可以没有跟标签,内部会将多个标签包含在一个Fragment虚拟标签中。 |
|||
- 好处:减少标签层级,减小内存占用 |
|||
|
|||
### Teleport |
|||
|
|||
- Teleport提供了一种干净的方法,让组件的HTML在父组件界面外的特定标签(很可能是body)下插入显示。 |
|||
|
|||
### Suspense |
|||
|
|||
> Supense组件是配合一部组件使用的,它可以让一部组件返回数据前渲染一些后背内容。 |
|||
> 那我们首先要学会一个异步组件。 |
|||
|
|||
- 在setup函数总返回一个promise,就是一个异步组件。 |
|||
- setup函数携程async函数,也是一个异步组件。 |
|||
|
|||
### 其他新的API |
|||
|
|||
- 全新的全局API: |
|||
- createApp() |
|||
- defineProperty() |
|||
- defineComponent() |
|||
- nextTick() |
|||
- 将原来的全局API转移到应用对象: |
|||
- app.component() |
|||
- app.config() |
|||
- app.directive() |
|||
- app.mount() |
|||
- app.umount() |
|||
- app.use() |
|||
|
|||
### useSlots和useAttrs |
|||
|
|||
> useSlots 和 useAttrs 是真实的运行时函数,它会返回与 setupContext.slots 和 setupContext.attrs 等价的值,同样也能在普通的组合式 API 中使用。 |
|||
> 使用场景:父组件使用子组件的插槽 |
|||
|
|||
1.父组件 |
|||
|
|||
```xml |
|||
<template> |
|||
<h1>这是父组件</h1> |
|||
|
|||
<p>插槽上面1</p> |
|||
<slots-attrs msg="我是props的msg" heihei="我是attr"> |
|||
<template #header > |
|||
<div style="width:100%;height:100px;border:1px solid green;">我是父组件插槽--插入的内容。。。</div> |
|||
</template> |
|||
</slots-attrs> |
|||
<p>插槽下面2</p> |
|||
|
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import SlotsAttrs from '@/components/04/SlotsAttrs.vue' |
|||
|
|||
</script> |
|||
``` |
|||
|
|||
2.子组件 |
|||
|
|||
```xml |
|||
<template> |
|||
<Child ref="child"/> |
|||
|
|||
{{msg}} |
|||
</template> |
|||
|
|||
|
|||
<script lang="ts" setup> |
|||
import { ref,onMounted } from 'vue'; |
|||
import Child from '@/components/03/Child.vue' |
|||
|
|||
|
|||
const child = ref(null); |
|||
const msg=ref('') |
|||
|
|||
|
|||
onMounted(()=>{ |
|||
console.log("进来了") |
|||
console.log(child.value.msg) |
|||
msg.value = child.value.msg; |
|||
}) |
|||
|
|||
</script> |
|||
``` |
|||
|
|||
## 路由 |
|||
|
|||
(1)userRout:获得当前路由对象。 |
|||
(2)useRouter:获得路由实例,可以进行路由跳转。 |
|||
|
|||
### 使用 |
|||
|
|||
```javascript |
|||
import {useRoute,useRouter} from "vue-router" |
|||
``` |
|||
|
|||
## 实战 |
|||
|
|||
创建项目后 |
|||
|
|||
### ElementPlus |
|||
|
|||
引入 |
|||
|
|||
```sh |
|||
npm install element-plus --save |
|||
``` |
|||
|
|||
尝试静态界面 |
|||
|
|||
 |
|||
|
|||
# 明日计划 |
|||
|
|||
1. 股票知识 |
|||
2. 继续学习vue3 |
|||
3. 参与到金币前端的任务 |
After Width: 632 | Height: 338 | Size: 74 KiB |
After Width: 234 | Height: 413 | Size: 48 KiB |
After Width: 251 | Height: 459 | Size: 27 KiB |
After Width: 450 | Height: 297 | Size: 43 KiB |
After Width: 1582 | Height: 876 | Size: 50 KiB |
@ -0,0 +1,137 @@ |
|||
# 趋势理论 |
|||
|
|||
根据道氏理论,股票价格运动有三种趋势 |
|||
|
|||
主要趋势、次要趋势和短暂趋势 |
|||
|
|||
## 主要趋势 |
|||
|
|||
主要趋势是股票价格广泛或全面性上升或下降的变动情形,持续时间通常为一年或以上。 |
|||
|
|||
从大的角度来看上涨和下跌的变动 |
|||
|
|||
主要趋势上升的,被称为多头市场 |
|||
|
|||
主要趋势下降的,被称为空头市场 |
|||
|
|||
### 多头市场 |
|||
|
|||
多头市场是指主要趋势为上升的市场状态,也称为主要上升趋势。 |
|||
|
|||
三阶段:进货期->十分稳定的上升和增多的交易量->交易沸腾,成交量上升 |
|||
|
|||
### 空头市场 |
|||
|
|||
也称为主要下跌趋势,是股票市场的一种状态,其主要特征是股价普遍下降。 |
|||
|
|||
三阶段:出货期->恐慌期->下跌期(继续下跌) |
|||
|
|||
## 次要趋势(修正趋势) |
|||
|
|||
次要趋势是主要趋势的调整,与主要趋势方向相反,持续时间从3周到数月不等。 |
|||
|
|||
## 短暂趋势 |
|||
|
|||
短暂趋势是短期的波动,很少超过三个星期,通常少于6天 |
|||
|
|||
每日行情的波动, |
|||
|
|||
长期投资者关注股价基本趋势,投机者关注修正趋势,短暂趋势重要性小,容易受人操控,一般不关注 |
|||
|
|||
## 道氏理论基本要点 |
|||
|
|||
### 评价价格包容消化一切 |
|||
|
|||
## 如何判断大趋势运行方向 |
|||
|
|||
 |
|||
|
|||
通过趋势线 |
|||
|
|||
# 趋势理论延伸——趋势线 |
|||
|
|||
## 百分比回撤 |
|||
|
|||
通常,市场不会直线上升,也不会竖直跌落 |
|||
|
|||
 |
|||
|
|||
百分比回撤+蜡烛图结合 很有用 |
|||
|
|||
|
|||
|
|||
# 股票价格的运行规律 |
|||
|
|||
## 股价运行规律 |
|||
|
|||
1. 股价应在多空双方均衡位置上下波动。 |
|||
2. 原有的平衡被打破后,股价将寻找新的平衡。 |
|||
|
|||
持续整理保持平衡—打破平衡—新的平衡—再打破平衡-…… |
|||
|
|||
## 支撑线和压力线 |
|||
|
|||
支撑线又称为抵抗线。股价下跌到某个位置,股价停止下跌, |
|||
|
|||
压力线又称为阻力线。当股价上涨到某价位附近时,股价会停止上涨 |
|||
|
|||
 |
|||
|
|||
前期的高点和低点都是很重要的压力和支持 |
|||
|
|||
一条支撑线和压力线对当前时期股价变化影响的重要性有三方面的考虑: |
|||
|
|||
1. 股价在这个区域持续时间的长短 |
|||
2. 股价在这个区域伴随的成交量大小 |
|||
3. 这个支撑区域或压力区域发生的时间,距离当前这个时期的远近 |
|||
|
|||
持续时间长,成交量大,离现在近,则影响大 |
|||
|
|||
## 趋势线和轨道线 |
|||
|
|||
### 趋势线 |
|||
|
|||
趋势线是衡量价格变化趋势的 |
|||
|
|||
上升趋势,两个显著的低点连成一条直线,就是上升趋势线 |
|||
|
|||
下降趋势,两个显著的高点连成一条直线,就是下降趋势线 |
|||
|
|||
上升趋势线是支持线的一种下降趋势线是压力线的一种 |
|||
|
|||
#### 趋势线两种作用 |
|||
|
|||
1. 对股价今后的变动起约束 |
|||
2. 趋势线被突破后,就说明股价下一步的趋势将要反向,越有效的趋势线被突破,其转势的信号越强烈 |
|||
|
|||
#### 怎么才算对趋势线的突破 |
|||
|
|||
1. 收盘价突破趋势线比日内的最高最低价突破趋势线重要; |
|||
2. 穿越趋势线后,离趋势线越远,突破越有效。人们可以根据各个股票的具体情况,自己制定一个界限,一般是用突破的幅度,如3%; |
|||
3. 穿越趋势线后,在趋势线的另一方停留的时间越长,突破越有效。 |
|||
|
|||
### 轨道线 |
|||
|
|||
又称通道线,管道线 |
|||
|
|||
两条平行线组成一个轨道,这就是常说的上升和下降轨道即趋势线的平行线 |
|||
|
|||
管道线持续的时间越长,其意义越重大,一个长期的上升通道和下降通道被有效突破,它将代表着一个新趋势的开始。 |
|||
|
|||
### 买卖法则 |
|||
|
|||
#### 上升趋势:一买三卖法则 |
|||
|
|||
一买:接触到趋势线买 |
|||
|
|||
三卖:接触到轨道线卖,突破管道线卖,跌破趋势线卖 |
|||
|
|||
 |
|||
|
|||
#### 下降趋势:一卖三买法则 |
|||
|
|||
一卖:接触趋势线卖 |
|||
|
|||
三买:接触管道线买,跌破管道线买,突破趋势线买 |
|||
|
|||
 |
@ -0,0 +1,79 @@ |
|||
# K线的画法 |
|||
|
|||
## k线的画法 |
|||
|
|||
K线,又称日本线,起源于200年前的日本,最初用于米市交易。 |
|||
|
|||
K线是一种柱状线条,由影线和实体组成。 |
|||
|
|||
影线在实体上方的部分叫上影线,下方的部分叫下影线。 |
|||
|
|||
实体分为阴线和阳线两种,分别用黑(阴)线和红(阳)线表示。 |
|||
|
|||
一条K线记录的是某一只股票或指数一天的价格变动情况,将每天的K线按时间顺序排列,就组成这只股票自上市以来每天的价格变动情况,称为日K线图。 |
|||
|
|||
价格变动体现在四个方面(主要),开盘价、最高价、最低价、收盘价 |
|||
|
|||
阴线阳线的开盘价,收盘价相反 |
|||
|
|||
 |
|||
|
|||
## K线的种类 |
|||
|
|||
K线的种类主要有以下几种: |
|||
|
|||
1. **光头阳线和光头阴线**:没有上影线的K线,当收盘价或开盘价正好同最高价相等时出现。 |
|||
2. **光脚阳线和光脚阴线**:没有下影线的K线,当收盘价或开盘价正好同最低价相等时出现。 |
|||
3. **光头光脚的阳线和阴线**:既没有上影线也没有下影线的K线,当开盘价和收盘价分别与最高价和最低价相等时出现。 |
|||
4. **十字星**:收盘价与开盘价相同时出现的K线,没有实体。 |
|||
5. **T字型和倒T字型**:在十字星的基础上,加上光头或光脚的条件,没有实体,形状像英文字母T。 |
|||
6. **一字型**:四个价格都一样,在开盘即封时,在涨停或跌停时出现。 |
|||
|
|||
## K线的变化 |
|||
|
|||
### 三要素 |
|||
|
|||
1. 阴阳代表总体趋势 |
|||
2. 长短代表内在动力和趋势强弱 |
|||
3. 阴线代表转折信号 |
|||
|
|||
### K线间的相互关系 |
|||
|
|||
光头光脚长阳线,是强烈上升过程的最高形式,即后市看好的极端; |
|||
|
|||
光头光脚的长阴线,是强烈下跌过程的最高形式,即后市看坏的极端; |
|||
|
|||
十字星是多空双方平衡状态的最高形式 |
|||
|
|||
### K线长短相互关系 |
|||
|
|||
K线长短代表内在动力大小,其中,实体长度又可代表趋势强弱。 |
|||
|
|||
### 线长度加大会有三种变化 |
|||
|
|||
K线由小阳线、中阳线到长阳线不断加长,说明多方力量变得越来越强; |
|||
|
|||
K线由小阴线、中阴线到长阴线不断加长,说明空方力量变得越来越强; |
|||
|
|||
K线实体变化不大,上影线和下影线越来越长,说明市场内在动力越来越强,多空搏斗越来越激烈。 |
|||
|
|||
### K线长度变化与动力转化 |
|||
|
|||
#### 影线长短互相影响 |
|||
|
|||
 |
|||
|
|||
 |
|||
|
|||
### K线分析的应用时机 |
|||
|
|||
阳线出现在盘整或股价下跌趋势末期时,代表股价可能会开始反转向上; |
|||
|
|||
阴线出现在盘整或股价上涨趋势末期时,代表股价可能会开始反转向下 |
|||
|
|||
出现极长下影线时,表示买方支撑力较强 |
|||
|
|||
出现极长上影线时,表示卖压大。 |
|||
|
|||
十字线可视为反转信号 |
|||
|
After Width: 632 | Height: 338 | Size: 74 KiB |
After Width: 441 | Height: 258 | Size: 70 KiB |
After Width: 437 | Height: 674 | Size: 131 KiB |
After Width: 423 | Height: 312 | Size: 35 KiB |
After Width: 503 | Height: 340 | Size: 46 KiB |
After Width: 530 | Height: 313 | Size: 46 KiB |
After Width: 630 | Height: 647 | Size: 105 KiB |
After Width: 481 | Height: 209 | Size: 40 KiB |
After Width: 518 | Height: 307 | Size: 61 KiB |