Compare commits
10 Commits
6669791fd3
...
6555c46f0f
Author | SHA1 | Date |
---|---|---|
|
6555c46f0f | |
|
24786f25f4 | |
|
aa00c07eb0 | |
|
26bd061953 | |
|
34bd3c0a8b | |
|
45ffbb6cdd | |
|
5ca6962782 | |
|
afd04a456b | |
|
0df9decdd5 | |
|
e81e7f2528 |
|
@ -0,0 +1,173 @@
|
|||
# Vim相关命令
|
||||
|
||||
## 基本移动命令
|
||||
|
||||
| 命令 | 描述 |
|
||||
| -------- | -------------------------------- |
|
||||
| `h` | 向左移动 |
|
||||
| `j` | 向下移动 |
|
||||
| `k` | 向上移动 |
|
||||
| `l` | 向右移动 |
|
||||
| `w` | 移动到下一个单词开头 |
|
||||
| `W` | 移动到下一个单词开头(忽略符号) |
|
||||
| `b` | 移动到上一个单词开头 |
|
||||
| `B` | 移动到上一个单词开头(忽略符号) |
|
||||
| `e` | 移动到当前单词末尾 |
|
||||
| `E` | 移动到当前单词末尾(忽略符号) |
|
||||
| `0` | 移动到行首 |
|
||||
| `^` | 移动到行首第一个非空白字符 |
|
||||
| `$` | 移动到行尾 |
|
||||
| `gg` | 移动到文件开头 |
|
||||
| `G` | 移动到文件末尾 |
|
||||
| `:[n]` | 移动到第 n 行 |
|
||||
| `Ctrl+f` | 向下翻页 |
|
||||
| `Ctrl+b` | 向上翻页 |
|
||||
| `H` | 移动到屏幕顶部 |
|
||||
| `M` | 移动到屏幕中间 |
|
||||
| `L` | 移动到屏幕底部 |
|
||||
|
||||
---
|
||||
|
||||
## 插入模式
|
||||
|
||||
| 命令 | 描述 |
|
||||
| -------- | -------------------------- |
|
||||
| `i` | 在光标前插入 |
|
||||
| `a` | 在光标后插入 |
|
||||
| `I` | 在行首插入 |
|
||||
| `A` | 在行尾插入 |
|
||||
| `o` | 在当前行下方新建一行并插入 |
|
||||
| `O` | 在当前行上方新建一行并插入 |
|
||||
| `R` | 进入替换模式(覆盖字符) |
|
||||
| `Ctrl+h` | 删除前一个字符(退格键) |
|
||||
| `Ctrl+w` | 删除前一个单词 |
|
||||
| `Ctrl+u` | 删除到行首 |
|
||||
|
||||
---
|
||||
|
||||
## 编辑命令
|
||||
|
||||
| 命令 | 描述 |
|
||||
| -------- | -------------------- |
|
||||
| `x` | 删除当前字符 |
|
||||
| `X` | 删除前一个字符 |
|
||||
| `dd` | 删除当前行 |
|
||||
| `dw` | 删除到下一个单词开头 |
|
||||
| `db` | 删除到上一个单词开头 |
|
||||
| `d$` | 删除到行尾 |
|
||||
| `d^` | 删除到行首 |
|
||||
| `dG` | 删除到文件末尾 |
|
||||
| `dgg` | 删除到文件开头 |
|
||||
| `yy` | 复制当前行 |
|
||||
| `yw` | 复制到下一个单词开头 |
|
||||
| `y$` | 复制到行尾 |
|
||||
| `p` | 粘贴到光标后 |
|
||||
| `P` | 粘贴到光标前 |
|
||||
| `u` | 撤销 |
|
||||
| `Ctrl+r` | 重做 |
|
||||
| `.` | 重复上一次修改 |
|
||||
| `J` | 合并下一行到当前行 |
|
||||
| `>>` | 向右缩进 |
|
||||
| `<<` | 向左缩进 |
|
||||
| `==` | 自动缩进当前行 |
|
||||
|
||||
---
|
||||
|
||||
## 搜索与替换
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ---------------- | ------------------------ |
|
||||
| `/pattern` | 向前搜索 pattern |
|
||||
| `?pattern` | 向后搜索 pattern |
|
||||
| `n` | 下一个匹配项 |
|
||||
| `N` | 上一个匹配项 |
|
||||
| `:%s/old/new/g` | 全局替换 old 为 new |
|
||||
| `:%s/old/new/gc` | 全局替换,每次确认 |
|
||||
| `:s/old/new/g` | 当前行替换 |
|
||||
| `*` | 向前搜索当前光标下的单词 |
|
||||
| `#` | 向后搜索当前光标下的单词 |
|
||||
| `:noh` | 临时取消搜索高亮 |
|
||||
|
||||
---
|
||||
|
||||
## 可视模式(选择文本)
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ---------------- | ------------------------------ |
|
||||
| `v` | 进入字符可视模式(按字符选择) |
|
||||
| `V` | 进入行可视模式(按行选择) |
|
||||
| `Ctrl+v` | 进入块可视模式(矩形选择) |
|
||||
| `ggVG` 或 `ggvG` | **全选**整个文件 |
|
||||
| `o` | 切换选择的光标端 |
|
||||
| `y` | 复制选中内容 |
|
||||
| `d` | 删除(剪切)选中内容 |
|
||||
| `c` | 修改(删除并进入插入模式) |
|
||||
| `~` | 切换选中内容的大小写 |
|
||||
|
||||
---
|
||||
|
||||
## 窗口管理
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ------------- | -------------- |
|
||||
| `:sp [file]` | 水平分割窗口 |
|
||||
| `:vsp [file]` | 垂直分割窗口 |
|
||||
| `Ctrl+w h` | 移动到左侧窗口 |
|
||||
| `Ctrl+w j` | 移动到下方窗口 |
|
||||
| `Ctrl+w k` | 移动到上方窗口 |
|
||||
| `Ctrl+w l` | 移动到右侧窗口 |
|
||||
| `Ctrl+w w` | 循环切换窗口 |
|
||||
| `Ctrl+w c` | 关闭当前窗口 |
|
||||
| `Ctrl+w o` | 只保留当前窗口 |
|
||||
| `Ctrl+w +` | 增加窗口高度 |
|
||||
| `Ctrl+w -` | 减少窗口高度 |
|
||||
| `Ctrl+w >` | 增加窗口宽度 |
|
||||
| `Ctrl+w <` | 减少窗口宽度 |
|
||||
| `Ctrl+w =` | 均衡窗口尺寸 |
|
||||
|
||||
---
|
||||
|
||||
## 标签页
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ---------------- | --------------------- |
|
||||
| `:tabnew [file]` | 新建标签页 |
|
||||
| `gt` | 下一个标签页 |
|
||||
| `gT` | 上一个标签页 |
|
||||
| `:tabclose` | 关闭当前标签页 |
|
||||
| `:tabonly` | 关闭其他标签页 |
|
||||
| `:tabmove [n]` | 移动标签页到第 n 位置 |
|
||||
|
||||
---
|
||||
|
||||
## 文件操作
|
||||
|
||||
| 命令 | 描述 |
|
||||
| -------------- | -------------------------- |
|
||||
| `:e file` | 打开文件 |
|
||||
| `:w` | 保存文件 |
|
||||
| `:w file` | 另存为 file |
|
||||
| `:q` | 退出 |
|
||||
| `:q!` | 强制退出不保存 |
|
||||
| `:wq` | 保存并退出 |
|
||||
| `:x` | 保存并退出(仅当有修改时) |
|
||||
| `:saveas file` | 另存为 file |
|
||||
| `:r file` | 插入文件内容到当前位置 |
|
||||
| `:r !command` | 插入命令输出到当前位置 |
|
||||
|
||||
---
|
||||
|
||||
## 其他实用命令
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ----------------- | --------------------------------------- |
|
||||
| `:set nu` | 显示行号 |
|
||||
| `:set nonu` | 隐藏行号 |
|
||||
| `:set hlsearch` | 高亮搜索结果 |
|
||||
| `:set nohlsearch` | 取消高亮搜索结果 |
|
||||
| `:set paste` | 进入粘贴模式(防止自动缩进) |
|
||||
| `:set nopaste` | 退出粘贴模式 |
|
||||
| `:!command` | 执行外部命令 |
|
||||
| `:help` | 打开帮助文档 |
|
||||
| `Ctrl+g` | 显示当前文件信息 |
|
||||
| `:%!command` | 用命令处理整个文件(如 `:%!sort` 排序) |
|
60
Vim/vim1.md
60
Vim/vim1.md
|
@ -1,60 +0,0 @@
|
|||
## **1. 基础移动(Navigation)**
|
||||
- **字符移动**:
|
||||
- `h` ← / `j` ↓ / `k` ↑ / `l` →
|
||||
- 方向键也能用,但 Vim 提倡用 `hjkl` 保持手不离键盘。
|
||||
- **单词移动**:
|
||||
- `w` → 跳到下一个单词开头
|
||||
- `b` ← 跳到上一个单词开头
|
||||
- `e` → 跳到当前单词末尾
|
||||
- **行内跳转**:
|
||||
- `0` 跳到行首,`^` 跳到第一个非空字符
|
||||
- `$` 跳到行尾
|
||||
- `f<char>` 向后搜索字符(如 `fa` 跳到下一个 `a`)
|
||||
- **屏幕移动**:
|
||||
- `Ctrl + u` 上翻半屏,`Ctrl + d` 下翻半屏
|
||||
- `gg` 跳到文件开头,`G` 跳到文件末尾
|
||||
- `:<行号>` 跳转到指定行(如 `:42` 跳到第 42 行)
|
||||
|
||||
---
|
||||
|
||||
## **2. 编辑文本(Editing)**
|
||||
- **插入模式**:
|
||||
- `i` 在光标前插入
|
||||
- `a` 在光标后插入
|
||||
- `I` 在行首插入,`A` 在行尾插入
|
||||
- `o` 在下一行插入,`O` 在上一行插入
|
||||
- **删除**:
|
||||
- `x` 删除当前字符
|
||||
- `dw` 删除一个单词
|
||||
- `dd` 删除整行
|
||||
- `D` 删除从光标到行尾
|
||||
- **复制/粘贴**:
|
||||
- `yy` 复制当前行
|
||||
- `p` 粘贴到光标后,`P` 粘贴到光标前
|
||||
- `yiw` 复制当前单词
|
||||
- **撤销/重做**:
|
||||
- `u` 撤销
|
||||
- `Ctrl + r` 重做
|
||||
|
||||
---
|
||||
|
||||
## **3. 选择与可视化模式(Visual Mode)**
|
||||
- `v` 进入字符选择模式
|
||||
- `V` 进入行选择模式
|
||||
- `Ctrl + v` 进入块选择模式(适合多行编辑)
|
||||
- 选中后可以用 `d`(删除)、`y`(复制)、`>`(缩进)等操作
|
||||
|
||||
---
|
||||
|
||||
## **4. 搜索与替换(Search & Replace)**
|
||||
- `/` + 关键词 → 搜索(`n` 下一个,`N` 上一个)
|
||||
- `:%s/old/new/g` → 全局替换(`g` 表示所有匹配)
|
||||
- `*` 快速搜索当前光标下的单词
|
||||
|
||||
---
|
||||
|
||||
## **5. 组合命令(Power Moves)**
|
||||
- `di"` → 删除引号内的内容
|
||||
- `ciw` → 修改当前单词
|
||||
- `dt<char>` → 删除直到某个字符(如 `dt)` 删除到 `)`)
|
||||
- `.` → 重复上一次操作
|
109
Vim/vim2.md
109
Vim/vim2.md
|
@ -1,109 +0,0 @@
|
|||
## 基本移动命令
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ------ | -------------------------- |
|
||||
| `h` | 向左移动 |
|
||||
| `j` | 向下移动 |
|
||||
| `k` | 向上移动 |
|
||||
| `l` | 向右移动 |
|
||||
| `w` | 移动到下一个单词开头 |
|
||||
| `b` | 移动到上一个单词开头 |
|
||||
| `e` | 移动到当前单词末尾 |
|
||||
| `0` | 移动到行首 |
|
||||
| `^` | 移动到行首第一个非空白字符 |
|
||||
| `$` | 移动到行尾 |
|
||||
| `gg` | 移动到文件开头 |
|
||||
| `G` | 移动到文件末尾 |
|
||||
| `:[n]` | 移动到第 n 行 |
|
||||
|
||||
## 插入模式
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ---- | -------------------------- |
|
||||
| `i` | 在光标前插入 |
|
||||
| `a` | 在光标后插入 |
|
||||
| `I` | 在行首插入 |
|
||||
| `A` | 在行尾插入 |
|
||||
| `o` | 在当前行下方新建一行并插入 |
|
||||
| `O` | 在当前行上方新建一行并插入 |
|
||||
|
||||
## 编辑命令
|
||||
|
||||
| 命令 | 描述 |
|
||||
| -------- | -------------------- |
|
||||
| `x` | 删除当前字符 |
|
||||
| `dd` | 删除当前行 |
|
||||
| `dw` | 删除到下一个单词开头 |
|
||||
| `d$` | 删除到行尾 |
|
||||
| `d^` | 删除到行首 |
|
||||
| `yy` | 复制当前行 |
|
||||
| `p` | 粘贴 |
|
||||
| `u` | 撤销 |
|
||||
| `Ctrl+r` | 重做 |
|
||||
| `.` | 重复上一次修改 |
|
||||
|
||||
## 搜索与替换
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ---------------- | ------------------- |
|
||||
| `/pattern` | 向前搜索 pattern |
|
||||
| `?pattern` | 向后搜索 pattern |
|
||||
| `n` | 下一个匹配项 |
|
||||
| `N` | 上一个匹配项 |
|
||||
| `:%s/old/new/g` | 全局替换 old 为 new |
|
||||
| `:%s/old/new/gc` | 全局替换,每次确认 |
|
||||
|
||||
## 可视模式
|
||||
|
||||
| 命令 | 描述 |
|
||||
| -------- | ---------------- |
|
||||
| `v` | 进入字符可视模式 |
|
||||
| `V` | 进入行可视模式 |
|
||||
| `Ctrl+v` | 进入块可视模式 |
|
||||
|
||||
## 窗口管理
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ------------- | -------------- |
|
||||
| `:sp [file]` | 水平分割窗口 |
|
||||
| `:vsp [file]` | 垂直分割窗口 |
|
||||
| `Ctrl+w h` | 移动到左侧窗口 |
|
||||
| `Ctrl+w j` | 移动到下方窗口 |
|
||||
| `Ctrl+w k` | 移动到上方窗口 |
|
||||
| `Ctrl+w l` | 移动到右侧窗口 |
|
||||
| `Ctrl+w c` | 关闭当前窗口 |
|
||||
| `Ctrl+w o` | 只保留当前窗口 |
|
||||
|
||||
## 标签页
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ---------------- | -------------- |
|
||||
| `:tabnew [file]` | 新建标签页 |
|
||||
| `gt` | 下一个标签页 |
|
||||
| `gT` | 上一个标签页 |
|
||||
| `:tabclose` | 关闭当前标签页 |
|
||||
|
||||
## 文件操作
|
||||
|
||||
| 命令 | 描述 |
|
||||
| --------- | -------------- |
|
||||
| `:e file` | 打开文件 |
|
||||
| `:w` | 保存文件 |
|
||||
| `:w file` | 另存为 file |
|
||||
| `:q` | 退出 |
|
||||
| `:q!` | 强制退出不保存 |
|
||||
| `:wq` | 保存并退出 |
|
||||
| `:x` | 保存并退出 |
|
||||
|
||||
## 其他实用命令
|
||||
|
||||
| 命令 | 描述 |
|
||||
| ----------------- | --------------------------------- |
|
||||
| `*` | 搜索当前光标下的单词 |
|
||||
| `#` | 反向搜索当前光标下的单词 |
|
||||
| `:%!command` | 将当前缓冲区内容通过 command 过滤 |
|
||||
| `:r!command` | 将 command 的输出插入到当前位置 |
|
||||
| `:set nu` | 显示行号 |
|
||||
| `:set nonu` | 隐藏行号 |
|
||||
| `:set hlsearch` | 高亮搜索结果 |
|
||||
| `:set nohlsearch` | 取消高亮搜索结果 |
|
|
@ -69,6 +69,5 @@
|
|||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -49,4 +49,4 @@ spring:
|
|||
param: user
|
||||
value: bunny
|
||||
# filters:
|
||||
# - RedirectTo=/api/order/?(?<segment>.*), /$\{segment}
|
||||
# - RedirectTo=/api/order/?(?<segment>.*), /$\{segment}
|
|
@ -7,7 +7,6 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
// Feign 客户端
|
||||
// @FeignClient(value = "service-product", path = "/api/product", fallback = ProductFeignClientFallback.class)
|
||||
@FeignClient(value = "gateway", path = "/api/product", fallback = ProductFeignClientFallback.class)
|
||||
public interface ProductFeignClient {
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,20 +13,7 @@
|
|||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>mq-demo</name>
|
||||
<description>mq-demo</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer/>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection/>
|
||||
<developerConnection/>
|
||||
<tag/>
|
||||
<url/>
|
||||
</scm>
|
||||
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<spring-modulith.version>1.3.5</spring-modulith.version>
|
||||
|
|
|
@ -3,26 +3,28 @@ package cn.bunny.mq.mqdemo.mq.listener;
|
|||
import com.rabbitmq.client.Channel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.amqp.core.Message;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.amqp.rabbit.annotation.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static cn.bunny.mq.mqdemo.domain.RabbitMQMessageListenerConstants.*;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MessageListenerOrder {
|
||||
|
||||
// /* 测试这个,需要注释下main那个 */
|
||||
// @RabbitListener(bindings = @QueueBinding(
|
||||
// exchange = @Exchange(value = EXCHANGE_DIRECT),
|
||||
// value = @Queue(value = QUEUE_NAME, durable = "true"),
|
||||
// key = ROUTING_KEY_DIRECT,
|
||||
// arguments = @Argument(name = "alternate-exchange", value = ALTERNATE_EXCHANGE_BACKUP)
|
||||
// )
|
||||
// )
|
||||
// public void processMessage(String dataString, Message message, Channel channel) {
|
||||
// System.out.println("消费端接受消息:" + dataString);
|
||||
// }
|
||||
/* 测试这个,需要注释下main那个 */
|
||||
@RabbitListener(bindings = @QueueBinding(
|
||||
exchange = @Exchange(value = EXCHANGE_DIRECT),
|
||||
value = @Queue(value = QUEUE_NAME, durable = "true"),
|
||||
key = ROUTING_KEY_DIRECT,
|
||||
arguments = @Argument(name = "alternate-exchange", value = ALTERNATE_EXCHANGE_BACKUP)
|
||||
)
|
||||
)
|
||||
public void processMessage(String dataString, Message message, Channel channel) {
|
||||
System.out.println("消费端接受消息:" + dataString);
|
||||
}
|
||||
|
||||
// /* 如果测试这个需要注释上面那个 */
|
||||
// @RabbitListener(queues = {QUEUE_NAME})
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script src="js/vue@2.7.16.js"></script>
|
||||
<title>模板语法</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>插值语法</h1>
|
||||
<h3>你好:{{name}}</h3>
|
||||
<br />
|
||||
|
||||
<h1>指令语法</h1>
|
||||
<a :href="url" target="_blank">v2.cn.vuejs.org</a>
|
||||
|
||||
<!-- v-bind 可以省略 -->
|
||||
<a v-bind:href="url" target="_blank">v2.cn.vuejs.org</a>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
name: "Bunny",
|
||||
url: "https://v2.cn.vuejs.org/",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,21 @@
|
|||
## Vue2 模板语法详解
|
||||
|
||||
在 Vue2 中,使用双大括号 `{{}}` 的语法称为插值语法(Mustache 语法),它用于在模板中显示数据。
|
||||
|
||||
### 基本用法
|
||||
```html
|
||||
<h3>你好:{{name}}</h3>
|
||||
```
|
||||
|
||||
### 实现原理
|
||||
当 Vue 实例创建时,会将 data 对象中的属性转换为 getter/setter,使其成为响应式数据。当数据变化时,视图会自动更新。
|
||||
|
||||
```javascript
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
name: "Bunny", // 响应式数据
|
||||
url: "https://v2.cn.vuejs.org/"
|
||||
}
|
||||
})
|
||||
```
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="js/vue@2.7.16.js"></script>
|
||||
<title>10-列表渲染</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<ul>
|
||||
<!-- 可以遍历数组、对象、字符串 -->
|
||||
<li v-for="(item,index) in list" :key="index">
|
||||
{{item}}--{{item.name}}--{{index}}
|
||||
</li>
|
||||
</ul>
|
||||
<br>
|
||||
<ul>
|
||||
<li v-for="(item,index) of person" :key="index ">
|
||||
{{item}}--{{index}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
list: [
|
||||
{ id: 1, name: "1" },
|
||||
{ id: 2, name: "2" },
|
||||
{ id: 3, name: "3" },
|
||||
{ id: 4, name: "4" },
|
||||
],
|
||||
person: {
|
||||
name: "Bunny",
|
||||
age: 16
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,158 @@
|
|||
# Vue2 列表渲染(v-for)详解文档
|
||||
|
||||
## 一、基本概念
|
||||
|
||||
Vue2 中的 `v-for` 指令用于基于源数据多次渲染元素或模板块。它可以遍历数组、对象和字符串,是构建动态列表的核心指令。
|
||||
|
||||
## 二、代码示例解析
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<!-- 遍历数组 -->
|
||||
<ul>
|
||||
<li v-for="(item, index) in list" :key="item.id">
|
||||
{{item}}--{{item.name}}--{{index}}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- 遍历对象 -->
|
||||
<ul>
|
||||
<li v-for="(value, key, index) of person" :key="key">
|
||||
{{value}}--{{key}}--{{index}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
list: [
|
||||
{ id: 1, name: "1" },
|
||||
{ id: 2, name: "2" },
|
||||
{ id: 3, name: "3" },
|
||||
{ id: 4, name: "4" }
|
||||
],
|
||||
person: {
|
||||
name: "Bunny",
|
||||
age: 16
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## 三、核心语法
|
||||
|
||||
### 1. 遍历数组
|
||||
```html
|
||||
<element v-for="(item, index) in array" :key="uniqueId">
|
||||
{{ index }}: {{ item }}
|
||||
</element>
|
||||
```
|
||||
|
||||
### 2. 遍历对象
|
||||
```html
|
||||
<element v-for="(value, key, index) in object" :key="key">
|
||||
{{ index }}. {{ key }}: {{ value }}
|
||||
</element>
|
||||
```
|
||||
|
||||
### 3. 遍历字符串
|
||||
```html
|
||||
<element v-for="(char, index) in string" :key="index">
|
||||
{{ index }}: {{ char }}
|
||||
</element>
|
||||
```
|
||||
|
||||
## 四、关键特性
|
||||
|
||||
| 特性 | 说明 | 示例 |
|
||||
| --------- | ---------------- | ----------------------- |
|
||||
| `in`/`of` | 两种语法等效 | `v-for="item in items"` |
|
||||
| 索引参数 | 可选的第二个参数 | `(item, index)` |
|
||||
| `:key` | 必须的唯一标识 | `:key="item.id"` |
|
||||
| 嵌套循环 | 支持多层嵌套 | 嵌套使用 `v-for` |
|
||||
|
||||
## 五、最佳实践
|
||||
|
||||
### 1. 正确的 key 使用
|
||||
- **必须**为每个节点提供唯一的 `key` 属性
|
||||
- **避免**使用索引作为 key(当列表会变化时)
|
||||
- **理想** key 应该是数据中的唯一 ID
|
||||
|
||||
```html
|
||||
<!-- 推荐 -->
|
||||
<li v-for="item in items" :key="item.id">
|
||||
|
||||
<!-- 不推荐 -->
|
||||
<li v-for="(item, index) in items" :key="index">
|
||||
```
|
||||
|
||||
### 2. 性能优化
|
||||
- 对大列表使用虚拟滚动(如 vue-virtual-scroller)
|
||||
- 避免在 `v-for` 中使用复杂表达式
|
||||
- 必要时使用 `v-if` 和 `v-for` 分离(Vue2 中 `v-for` 优先级更高)
|
||||
|
||||
### 3. 数组更新检测
|
||||
Vue 能检测以下数组方法的变化:
|
||||
- `push()`
|
||||
- `pop()`
|
||||
- `shift()`
|
||||
- `unshift()`
|
||||
- `splice()`
|
||||
- `sort()`
|
||||
- `reverse()`
|
||||
|
||||
## 六、高级用法
|
||||
|
||||
### 1. 范围迭代
|
||||
```html
|
||||
<span v-for="n in 10">{{ n }} </span>
|
||||
```
|
||||
|
||||
### 2. 组件中使用
|
||||
```html
|
||||
<my-component
|
||||
v-for="(item, index) in items"
|
||||
:item="item"
|
||||
:index="index"
|
||||
:key="item.id">
|
||||
</my-component>
|
||||
```
|
||||
|
||||
### 3. 过滤/排序列表
|
||||
```javascript
|
||||
computed: {
|
||||
filteredItems() {
|
||||
return this.items.filter(item => item.isActive);
|
||||
},
|
||||
sortedItems() {
|
||||
return [...this.items].sort((a, b) => a.price - b.price);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 七、常见问题
|
||||
|
||||
1. **为什么列表不更新?**
|
||||
- 确保使用了变异方法修改数组
|
||||
- 对于非变异方法,使用新数组替换旧数组
|
||||
- 对象属性添加需要使用 `Vue.set`
|
||||
|
||||
2. **`v-if` 和 `v-for` 一起使用?**
|
||||
- Vue2 中不推荐同一元素使用两者
|
||||
- 解决方案:
|
||||
```html
|
||||
<template v-for="item in items">
|
||||
<div v-if="item.isVisible" :key="item.id">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
3. **如何获取当前元素?**
|
||||
- 通过事件传递:
|
||||
```html
|
||||
<div v-for="item in items" @click="handleClick(item)">
|
||||
```
|
|
@ -0,0 +1,58 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script src="js/vue@2.7.16.js"></script>
|
||||
<title>列表过滤</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>列表过滤</h1>
|
||||
<input type="text" v-model="keyword" />
|
||||
<button @click="sortType = 2">年龄升序</button>
|
||||
<button @click="sortType = 1">年龄降序</button>
|
||||
<button @click="sortType = 0">重置</button>
|
||||
|
||||
<ul>
|
||||
<li v-for="(item,index) in filterPersion" :key="index">
|
||||
{{item.name}}---{{item.age}}---{{item.sex}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
sortType: 0,
|
||||
keyword: "",
|
||||
list: [
|
||||
{ id: "001", name: "Bunny-001", age: 19, sex: "男" },
|
||||
{ id: "002", name: "Bunny-002", age: 16, sex: "男" },
|
||||
{ id: "003", name: "Bunny-003", age: 20, sex: "女" },
|
||||
{ id: "004", name: "Bunny-004", age: 18, sex: "男" },
|
||||
{ id: "005", name: "Bunny-005", age: 19, sex: "女" },
|
||||
],
|
||||
},
|
||||
computed: {
|
||||
filterPersion() {
|
||||
let newList = this.list.filter(
|
||||
(persion) => persion.name.indexOf(this.keyword) !== -1
|
||||
);
|
||||
|
||||
if (this.sortType != 0) {
|
||||
newList = newList.sort((a, b) =>
|
||||
this.sortType == 2 ? a.age - b.age : b.age - a.age
|
||||
);
|
||||
}
|
||||
|
||||
return newList;
|
||||
},
|
||||
},
|
||||
methods: {},
|
||||
});
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,168 @@
|
|||
# Vue2 列表过滤与排序综合文档
|
||||
|
||||
## 一、功能概述
|
||||
|
||||
本示例展示了 Vue2 中如何实现列表的实时过滤与动态排序功能,结合计算属性实现了高效的数据处理。
|
||||
|
||||
## 二、代码实现解析
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<h1>列表过滤</h1>
|
||||
<!-- 搜索框 -->
|
||||
<input type="text" v-model="keyword">
|
||||
<!-- 排序按钮 -->
|
||||
<button @click="sortType = 2">年龄升序</button>
|
||||
<button @click="sortType = 1">年龄降序</button>
|
||||
<button @click="sortType = 0">重置</button>
|
||||
|
||||
<!-- 结果列表 -->
|
||||
<ul>
|
||||
<li v-for="(item,index) in filterPersion" :key="item.id">
|
||||
{{item.name}}---{{item.age}}---{{item.sex}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
sortType: 0, // 0-默认 1-降序 2-升序
|
||||
keyword: "", // 搜索关键词
|
||||
list: [
|
||||
{ id: "001", name: "Bunny-001", age: 19, sex: "男" },
|
||||
{ id: "002", name: "Bunny-002", age: 16, sex: "男" },
|
||||
// ...其他数据
|
||||
]
|
||||
},
|
||||
computed: {
|
||||
filterPersion() {
|
||||
// 1. 过滤
|
||||
let newList = this.list.filter(person =>
|
||||
person.name.includes(this.keyword)
|
||||
);
|
||||
|
||||
// 2. 排序
|
||||
if (this.sortType !== 0) {
|
||||
newList.sort((a, b) =>
|
||||
this.sortType === 2 ? a.age - b.age : b.age - a.age
|
||||
);
|
||||
}
|
||||
|
||||
return newList;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## 三、核心机制详解
|
||||
|
||||
### 1. 数据流设计
|
||||
```
|
||||
原始数据 (list)
|
||||
↓
|
||||
[过滤] → 根据 keyword 筛选
|
||||
↓
|
||||
[排序] → 根据 sortType 排序 (可选)
|
||||
↓
|
||||
渲染列表 (filterPersion)
|
||||
```
|
||||
|
||||
### 2. 计算属性优势
|
||||
- **自动缓存**:依赖项未变化时不重新计算
|
||||
- **响应式**:keyword 或 sortType 变化自动更新
|
||||
- **声明式**:模板保持简洁,逻辑集中管理
|
||||
|
||||
### 3. 排序算法优化
|
||||
```javascript
|
||||
// 三元运算符实现升降序切换
|
||||
(a, b) => this.sortType === 2 ? a.age - b.age : b.age - a.age
|
||||
```
|
||||
|
||||
## 四、最佳实践建议
|
||||
|
||||
### 1. 性能优化
|
||||
- **避免深拷贝**:直接操作过滤后的数组
|
||||
- **防抖处理**:搜索框添加防抖(使用 lodash.debounce)
|
||||
- **分页加载**:大数据集应配合分页
|
||||
|
||||
### 2. 代码改进
|
||||
```javascript
|
||||
// 更安全的字符串包含检查
|
||||
person.name.toLowerCase().includes(this.keyword.toLowerCase())
|
||||
|
||||
// 可配置的排序函数
|
||||
const sortStrategies = {
|
||||
1: (a, b) => b.age - a.age,
|
||||
2: (a, b) => a.age - b.age
|
||||
};
|
||||
newList.sort(sortStrategies[this.sortType]);
|
||||
```
|
||||
|
||||
### 3. Key 的使用
|
||||
```html
|
||||
<!-- 使用唯一id而非index作为key -->
|
||||
<li v-for="item in filterPersion" :key="item.id">
|
||||
```
|
||||
|
||||
## 五、扩展功能实现
|
||||
|
||||
### 1. 多条件过滤
|
||||
```javascript
|
||||
filterPersion() {
|
||||
return this.list.filter(person => {
|
||||
const nameMatch = person.name.includes(this.keyword);
|
||||
const ageMatch = this.filterAge === '' || person.age == this.filterAge;
|
||||
return nameMatch && ageMatch;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 多列排序
|
||||
```javascript
|
||||
data() {
|
||||
return {
|
||||
sortConfig: { field: 'age', order: 1 } // 1升序,-1降序
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
sortedList() {
|
||||
return [...this.filteredList].sort((a, b) => {
|
||||
return a[this.sortConfig.field] > b[this.sortConfig.field]
|
||||
? this.sortConfig.order : -this.sortConfig.order;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 异步数据加载
|
||||
```javascript
|
||||
async loadData() {
|
||||
this.list = await fetch('/api/persons').then(res => res.json());
|
||||
}
|
||||
```
|
||||
|
||||
## 六、常见问题解决方案
|
||||
|
||||
1. **列表不更新问题**
|
||||
- 确保使用变异方法修改原始数组
|
||||
- 或使用 `Vue.set` 更新数组元素
|
||||
|
||||
2. **排序状态保持**
|
||||
```javascript
|
||||
created() {
|
||||
this.sortType = Number(localStorage.getItem('sortType')) || 0;
|
||||
},
|
||||
watch: {
|
||||
sortType(newVal) {
|
||||
localStorage.setItem('sortType', newVal);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **空搜索结果处理**
|
||||
```html
|
||||
<div v-if="filterPersion.length === 0">暂无匹配结果</div>
|
||||
```
|
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script src="js/vue@2.7.16.js"></script>
|
||||
<title>Vue监测数据的原理_数组</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>列表过滤</h1>
|
||||
<button @click="changeList">修改</button>
|
||||
|
||||
<ul>
|
||||
<li v-for="(item,index) in list" :key="index">
|
||||
{{item.name}}---{{item.age}}---{{item.sex}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
list: [
|
||||
{ id: "001", name: "Bunny-001", age: 19, sex: "男" },
|
||||
{ id: "002", name: "Bunny-002", age: 16, sex: "男" },
|
||||
{ id: "003", name: "Bunny-003", age: 20, sex: "女" },
|
||||
{ id: "004", name: "Bunny-004", age: 18, sex: "男" },
|
||||
{ id: "005", name: "Bunny-005", age: 19, sex: "女" },
|
||||
],
|
||||
},
|
||||
methods: {
|
||||
changeList() {
|
||||
// 无法修改数组,显示不出来修改
|
||||
// this.list[0] = { id: "002", name: "Bunny-002", age: 16, sex: "男" };
|
||||
|
||||
// 可以这样修改
|
||||
// 详细参考 https://v2.cn.vuejs.org/v2/guide/list.html#%E5%8F%98%E6%9B%B4%E6%96%B9%E6%B3%95
|
||||
// this.list.splice(0, 1, {
|
||||
// id: "0021",
|
||||
// name: "Bunny-0021",
|
||||
// age: 16,
|
||||
// sex: "男",
|
||||
// });
|
||||
|
||||
// 或者这样修改
|
||||
// Vue.$set(this.list, 0, {
|
||||
this.$set(this.list, 0, {
|
||||
id: "0021",
|
||||
name: "Bunny-0021",
|
||||
age: 16,
|
||||
sex: "男",
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,175 @@
|
|||
# Vue2 数组变化监测原理与实战指南
|
||||
|
||||
## 一、核心原理
|
||||
|
||||
Vue2 通过重写数组的变异方法实现对数组变化的监测,这是其响应式系统的关键部分。当直接通过索引修改数组元素时(如 `arr[0] = newValue`),Vue 无法自动检测到这种变化。
|
||||
|
||||
## 二、代码示例解析
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<h1>列表更新演示</h1>
|
||||
<button @click="changeList">修改数组</button>
|
||||
<ul>
|
||||
<li v-for="(item,index) in list" :key="item.id">
|
||||
{{item.name}}---{{item.age}}---{{item.sex}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
list: [
|
||||
{ id: "001", name: "Bunny-001", age: 19, sex: "男" },
|
||||
// ...其他初始数据
|
||||
],
|
||||
},
|
||||
methods: {
|
||||
changeList() {
|
||||
// ❌ 无效的修改方式
|
||||
// this.list[0] = { id: "002", name: "Bunny-002", age: 16, sex: "男" };
|
||||
|
||||
// ✅ 方式1:使用变异方法
|
||||
this.list.splice(0, 1, {
|
||||
id: "0021",
|
||||
name: "Bunny-0021",
|
||||
age: 16,
|
||||
sex: "男",
|
||||
});
|
||||
|
||||
// ✅ 方式2:使用Vue.set/$set
|
||||
// Vue.$set(this.list, 0, {
|
||||
this.$set(this.list, 0, {
|
||||
id: "0021",
|
||||
name: "Bunny-0021",
|
||||
age: 16,
|
||||
sex: "男",
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## 三、响应式数组操作方法
|
||||
|
||||
### 1. Vue 包装的变异方法
|
||||
|
||||
Vue 重写了以下数组方法,使其能触发视图更新:
|
||||
|
||||
- `push()` / `pop()`
|
||||
- `shift()` / `unshift()`
|
||||
- `splice()`
|
||||
- `sort()` / `reverse()`
|
||||
|
||||
### 2. 特殊场景处理
|
||||
|
||||
| 场景 | 正确方法 | 错误方法 |
|
||||
| -------- | ------------------------------- | ----------------------- |
|
||||
| 修改元素 | `Vue.set(arr, index, newValue)` | `arr[index] = newValue` |
|
||||
| 添加元素 | `arr.splice(index, 0, newItem)` | `arr[index] = newItem` |
|
||||
| 删除元素 | `arr.splice(index, 1)` | `delete arr[index]` |
|
||||
|
||||
### 3. 注意事项
|
||||
|
||||
- 使用 `filter()`、`concat()` 等非变异方法时,需要用返回的新数组替换原数组
|
||||
- 嵌套数组需要深度观测
|
||||
|
||||
## 四、原理深入
|
||||
|
||||
### 1. 实现机制
|
||||
|
||||
Vue 通过以下步骤实现数组响应式:
|
||||
|
||||
1. 拦截数组原型方法
|
||||
2. 在方法执行后通知依赖更新
|
||||
3. 对新增元素进行响应式处理
|
||||
|
||||
### 2. 源码关键部分
|
||||
|
||||
```javascript
|
||||
// 简化版的数组响应式实现
|
||||
const arrayProto = Array.prototype;
|
||||
const arrayMethods = Object.create(arrayProto);
|
||||
|
||||
const methodsToPatch = [
|
||||
"push",
|
||||
"pop",
|
||||
"shift",
|
||||
"unshift",
|
||||
"splice",
|
||||
"sort",
|
||||
"reverse",
|
||||
];
|
||||
|
||||
methodsToPatch.forEach(function (method) {
|
||||
const original = arrayProto[method];
|
||||
def(arrayMethods, method, function mutator(...args) {
|
||||
const result = original.apply(this, args);
|
||||
const ob = this.__ob__;
|
||||
let inserted;
|
||||
switch (method) {
|
||||
case "push":
|
||||
case "unshift":
|
||||
inserted = args;
|
||||
break;
|
||||
case "splice":
|
||||
inserted = args.slice(2);
|
||||
break;
|
||||
}
|
||||
if (inserted) ob.observeArray(inserted);
|
||||
ob.dep.notify(); // 通知更新
|
||||
return result;
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## 五、最佳实践
|
||||
|
||||
### 1. 性能优化
|
||||
|
||||
- 大数据量操作时使用 `Vue.nextTick` 批量更新
|
||||
- 避免在模板中直接操作复杂数组计算
|
||||
|
||||
### 2. 代码规范
|
||||
|
||||
- 统一使用 `Vue.set` 或 `splice` 修改数组
|
||||
- 为 `v-for` 设置合适的 `key`
|
||||
|
||||
### 3. 扩展方法
|
||||
|
||||
```javascript
|
||||
// 安全的数组修改方法
|
||||
function safeArrayUpdate(arr, index, newValue) {
|
||||
if (Array.isArray(arr)) {
|
||||
return Vue.set(arr, index, newValue);
|
||||
}
|
||||
throw new Error("Target is not an array");
|
||||
}
|
||||
```
|
||||
|
||||
## 六、常见问题解决方案
|
||||
|
||||
1. **为什么我的数组修改不生效?**
|
||||
|
||||
- 检查是否使用了 Vue 能检测的变异方法
|
||||
- 确认没有直接修改数组长度(如 `arr.length = 0`)
|
||||
|
||||
2. **如何强制更新数组?**
|
||||
|
||||
```javascript
|
||||
// 方法1:使用空splice触发更新
|
||||
this.list.splice();
|
||||
|
||||
// 方法2:使用Vue.set
|
||||
Vue.set(this.list, 0, this.list[0]);
|
||||
```
|
||||
|
||||
3. **对象数组中的对象属性修改**
|
||||
- 直接修改对象属性可以触发更新(因为对象是响应式的)
|
||||
```javascript
|
||||
// 这是有效的
|
||||
this.list[0].name = "new name";
|
||||
```
|
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script src="js/vue@2.7.16.js"></script>
|
||||
<script src="js/dayjs.min.js"></script>
|
||||
<title>过滤器</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- 管道符只能使用在filters中 -->
|
||||
<h3>现在是:{{time | timeFormater}}</h3>
|
||||
<h3>现在是:{{time | timeFormater("YYYY年MM月DD日 HH:mm:ss")}}</h3>
|
||||
<h3>
|
||||
现在是:{{time | timeFormater("YYYY年MM月DD日 HH:mm:ss") |
|
||||
timeFormaterSlice}}
|
||||
</h3>
|
||||
|
||||
<!-- 不能使用在v-model -->
|
||||
<h3 :peiqi="message | globeTimeFormaterSlice">
|
||||
使用全局过滤器:{{message | globeTimeFormaterSlice}}
|
||||
</h3>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
// 定义全局过滤器
|
||||
Vue.filter("globeTimeFormaterSlice", function (val) {
|
||||
return val.slice(0, 4);
|
||||
});
|
||||
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
time: new Date(),
|
||||
message: "全局的过滤器使用在标签上...",
|
||||
},
|
||||
methods: {},
|
||||
filters: {
|
||||
/* 时间格式化 */
|
||||
timeFormater(val, str = "YYYY-MM-DD HH:mm:ss") {
|
||||
return dayjs(val).format(str);
|
||||
},
|
||||
timeFormaterSlice(val) {
|
||||
return val.slice(0, 4);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,143 @@
|
|||
# Vue2 过滤器(Filter)使用指南
|
||||
|
||||
## 一、基本概念
|
||||
|
||||
过滤器(Filters)是Vue2中用于文本格式化处理的特殊函数,可以在模板中使用管道符(`|`)对数据进行转换处理。
|
||||
|
||||
## 二、代码示例解析
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<!-- 使用局部过滤器 -->
|
||||
<h3>现在是:{{time | timeFormater}}</h3>
|
||||
|
||||
<!-- 传参的过滤器 -->
|
||||
<h3>现在是:{{time | timeFormater("YYYY年MM月DD日 HH:mm:ss")}}</h3>
|
||||
|
||||
<!-- 过滤器链式调用 -->
|
||||
<h3>现在是:{{time | timeFormater("YYYY年MM月DD日 HH:mm:ss") | timeFormaterSlice}}</h3>
|
||||
|
||||
<!-- 使用全局过滤器 -->
|
||||
<h3 :peiqi="message | globeTimeFormaterSlice">
|
||||
使用全局过滤器:{{message | globeTimeFormaterSlice}}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 全局过滤器定义
|
||||
Vue.filter("globeTimeFormaterSlice", function(val) {
|
||||
return val.slice(0, 4);
|
||||
});
|
||||
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
time: new Date(),
|
||||
message: "全局的过滤器使用在标签上..."
|
||||
},
|
||||
filters: {
|
||||
// 局部过滤器定义
|
||||
timeFormater(val, str = "YYYY-MM-DD HH:mm:ss") {
|
||||
return dayjs(val).format(str);
|
||||
},
|
||||
timeFormaterSlice(val) {
|
||||
return val.slice(0, 4);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## 三、核心特性
|
||||
|
||||
### 1. 过滤器类型
|
||||
|
||||
| 类型 | 定义位置 | 作用域 | 示例 |
|
||||
| ---------- | ---------------------- | -------- | --------------------------- |
|
||||
| 局部过滤器 | Vue实例的`filters`选项 | 当前组件 | `{{ data | localFilter }}` |
|
||||
| 全局过滤器 | `Vue.filter()` | 所有组件 | `{{ data | globalFilter }}` |
|
||||
|
||||
### 2. 使用方式
|
||||
|
||||
| 方式 | 语法 | 说明 |
|
||||
| -------- | --------------------------------- | ------------------ |
|
||||
| 基本使用 | `{{ data | filter }}` | 单个过滤器 |
|
||||
| 传参使用 | `{{ data | filter(arg1, arg2) }}` | 可传递额外参数 |
|
||||
| 链式调用 | `{{ data | filter1 | filter2 }}` | 多个过滤器依次处理 |
|
||||
|
||||
## 四、最佳实践
|
||||
|
||||
### 1. 命名规范
|
||||
- 使用动词+名词形式(如`formatDate`、`truncateText`)
|
||||
- 全局过滤器加前缀(如`globe_`)避免命名冲突
|
||||
|
||||
### 2. 适用场景
|
||||
- 文本格式化(日期、货币等)
|
||||
- 数据简单转换(截取、大小写转换等)
|
||||
- 显示内容的修饰(添加前缀/后缀)
|
||||
|
||||
### 3. 注意事项
|
||||
- **不能**在`v-model`中使用
|
||||
- **避免**复杂业务逻辑,复杂处理应使用计算属性
|
||||
- **推荐**纯函数实现,不要修改原始数据
|
||||
|
||||
## 五、高级用法
|
||||
|
||||
### 1. 动态过滤器名
|
||||
```javascript
|
||||
filters: {
|
||||
dynamicFilter(val, filterName) {
|
||||
return this[filterName](val);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 过滤器工厂函数
|
||||
```javascript
|
||||
function createPrefixFilter(prefix) {
|
||||
return function(val) {
|
||||
return prefix + val;
|
||||
}
|
||||
}
|
||||
|
||||
Vue.filter('withPrefix', createPrefixFilter('Info: '));
|
||||
```
|
||||
|
||||
### 3. 结合计算属性使用
|
||||
```javascript
|
||||
computed: {
|
||||
formattedTime() {
|
||||
return this.$options.filters.timeFormater(this.time);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 六、与Vue3的区别
|
||||
|
||||
| 特性 | Vue2 | Vue3 |
|
||||
| ---------- | ------ | ----------------- |
|
||||
| 过滤器支持 | ✅ 支持 | ❌ 移除 |
|
||||
| 替代方案 | - | 使用方法/计算属性 |
|
||||
|
||||
## 七、常见问题
|
||||
|
||||
1. **为什么过滤器不生效?**
|
||||
- 检查过滤器名称拼写
|
||||
- 确认是否在正确的作用域定义
|
||||
- 确保返回值不是undefined
|
||||
|
||||
2. **如何调试过滤器?**
|
||||
```javascript
|
||||
filters: {
|
||||
debugFilter(val) {
|
||||
console.log('Filter input:', val);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **过滤器能接收多个参数吗?**
|
||||
```html
|
||||
<!-- 可以,第一个参数永远是管道符前的值 -->
|
||||
{{ data | filter(arg1, arg2) }}
|
||||
```
|
|
@ -0,0 +1,64 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="js/vue@2.7.16.js"></script>
|
||||
<title>数据绑定</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
单项数据绑定:<input type="text" v-bind:value="name">
|
||||
双向数据绑定:<input type="text" v-model="name">
|
||||
</div>
|
||||
|
||||
<div id="root">
|
||||
2秒后绑定到这个上
|
||||
单项数据绑定:<input type="text" v-bind:value="name">
|
||||
双向数据绑定:<input type="text" v-model="name">
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
// 只要vm有的内容都可以用
|
||||
const v = new Vue({
|
||||
// el: "#app",
|
||||
// data: {
|
||||
// name: "数据绑定"
|
||||
// },
|
||||
|
||||
// 不能用箭头函数
|
||||
// data: function () {
|
||||
// return {
|
||||
// name: "数据绑定"
|
||||
// }
|
||||
// }
|
||||
data() {
|
||||
return {
|
||||
name: "数据绑定"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 下面内容可以简写成 v-if形式
|
||||
setTimeout(() => {
|
||||
v.$mount("#app");
|
||||
console.log("app");
|
||||
}, 1000);
|
||||
|
||||
setTimeout(() => {
|
||||
// 正确做法:销毁旧实例,创建新实例
|
||||
v.$destroy();
|
||||
|
||||
const v2 = new Vue({
|
||||
data: {
|
||||
name: "新数据绑定"
|
||||
}
|
||||
});
|
||||
v2.$mount("#root");
|
||||
console.log("root");
|
||||
}, 2000);
|
||||
</script>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,95 @@
|
|||
# Vue2 数据绑定
|
||||
|
||||
本示例展示了 Vue2 中的两种数据绑定方式:
|
||||
- 单向数据绑定 (`v-bind`)
|
||||
- 双向数据绑定 (`v-model`)
|
||||
|
||||
## 核心概念详解
|
||||
|
||||
### 1. 数据绑定类型
|
||||
|
||||
| 类型 | 指令 | 特点 | 示例 |
|
||||
| -------- | --------- | ----------------- | ----------------------------- |
|
||||
| 单向绑定 | `v-bind` | 数据→视图单向流动 | `<input v-bind:value="name">` |
|
||||
| 双向绑定 | `v-model` | 数据⇄视图双向同步 | `<input v-model="name">` |
|
||||
|
||||
### 2. Vue 实例创建方式
|
||||
|
||||
```javascript
|
||||
// 推荐写法 (ES6简写)
|
||||
data() {
|
||||
return {
|
||||
name: "数据绑定"
|
||||
}
|
||||
}
|
||||
|
||||
// 等价于
|
||||
data: function() {
|
||||
return {
|
||||
name: "数据绑定"
|
||||
}
|
||||
}
|
||||
|
||||
// 不推荐在组件中使用
|
||||
data: {
|
||||
name: "数据绑定"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 动态挂载机制
|
||||
|
||||
```javascript
|
||||
// 延迟挂载示例
|
||||
setTimeout(() => {
|
||||
v.$mount("#app"); // 手动挂载到#app
|
||||
}, 1000);
|
||||
|
||||
// 实例销毁与重建
|
||||
setTimeout(() => {
|
||||
v.$destroy(); // 销毁旧实例
|
||||
|
||||
const v2 = new Vue({ // 创建新实例
|
||||
data: { name: "新数据绑定" }
|
||||
});
|
||||
v2.$mount("#root"); // 挂载到新位置
|
||||
}, 2000);
|
||||
```
|
||||
|
||||
1. **数据绑定选择**:
|
||||
- 表单元素使用 `v-model` 实现双向绑定
|
||||
- 普通属性使用 `v-bind` 实现单向绑定
|
||||
|
||||
2. **实例管理**:
|
||||
- 避免在同一个元素上重复挂载不同实例
|
||||
- 切换挂载目标时务必先销毁旧实例
|
||||
|
||||
3. **数据定义**:
|
||||
- 组件中必须使用函数形式返回data对象
|
||||
- 根实例可以使用对象形式
|
||||
|
||||
4. **性能优化**:
|
||||
- 大量数据绑定时考虑使用计算属性
|
||||
- 复杂场景可使用自定义指令优化
|
||||
|
||||
## 扩展说明
|
||||
|
||||
### 1. `v-model` 原理
|
||||
`v-model` 本质上是语法糖,等价于:
|
||||
```html
|
||||
<input
|
||||
:value="name"
|
||||
@input="name = $event.target.value">
|
||||
```
|
||||
|
||||
### 2. 挂载方式对比
|
||||
| 方式 | 示例 | 适用场景 |
|
||||
| ---------- | ------------------- | -------------------- |
|
||||
| el选项 | `el: "#app"` | 初始化时确定挂载点 |
|
||||
| $mount方法 | `vm.$mount("#app")` | 需要延迟或条件挂载时 |
|
||||
|
||||
### 3. 实例生命周期
|
||||
- `new Vue()` 创建实例
|
||||
- `$mount()` 触发挂载流程
|
||||
- `$destroy()` 触发销毁流程
|
||||
|
||||
通过本文档,您可以全面了解 Vue2 的数据绑定机制和实例管理方法,为实际开发提供参考。
|
|
@ -0,0 +1,42 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Object.defineProperty</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
</body>
|
||||
<script>
|
||||
let age = 18
|
||||
const person = {
|
||||
name: "Bunny",
|
||||
sex: "男",
|
||||
// age: 16
|
||||
}
|
||||
|
||||
Object.defineProperty(person, 'age', {
|
||||
// value: 18,// 赋值
|
||||
// enumerable: true,// 控制是否可以被枚举
|
||||
// writable: true,// 控制是否可以被修改
|
||||
// configurable: true,// 控制是否可以被删除
|
||||
|
||||
// 修改属性时触发
|
||||
get() {
|
||||
console.log("修改属性时触发");
|
||||
return age
|
||||
},
|
||||
// 修改age时触发
|
||||
set(value) {
|
||||
console.log("修改age时触发");
|
||||
age = value
|
||||
}
|
||||
})
|
||||
|
||||
console.log(person);
|
||||
</script>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,76 @@
|
|||
# `Object.defineProperty` 方法
|
||||
|
||||
## 一、基本概念
|
||||
|
||||
`Object.defineProperty()` 是 JavaScript 中用于直接在一个对象上定义一个新属性,或者修改一个对象的现有属性的方法。它允许精确控制属性的行为特性。
|
||||
|
||||
## 属性描述符详解
|
||||
|
||||
### 1. 数据描述符(已注释部分)
|
||||
```javascript
|
||||
{
|
||||
value: 18, // 属性值
|
||||
enumerable: true, // 是否可枚举(for...in或Object.keys())
|
||||
writable: true, // 是否可修改
|
||||
configurable: true // 是否可删除或修改特性
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 存取描述符(实际使用部分)
|
||||
```javascript
|
||||
{
|
||||
get() {
|
||||
// 读取属性时调用
|
||||
return age;
|
||||
},
|
||||
set(value) {
|
||||
// 设置属性时调用
|
||||
age = value;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 特性说明
|
||||
|
||||
| 特性 | 类型 | 默认值 | 描述 |
|
||||
| ------------ | ---- | --------- | ------------------------ |
|
||||
| configurable | 布尔 | false | 是否可删除属性或修改特性 |
|
||||
| enumerable | 布尔 | false | 是否出现在枚举属性中 |
|
||||
| value | 任意 | undefined | 属性值 |
|
||||
| writable | 布尔 | false | 是否可被赋值运算符改变 |
|
||||
| get | 函数 | undefined | 读取属性时调用的函数 |
|
||||
| set | 函数 | undefined | 设置属性时调用的函数 |
|
||||
|
||||
## 使用场景
|
||||
|
||||
1. **实现数据响应式**(如Vue2的核心实现)
|
||||
2. **创建私有属性**(通过getter/setter控制访问)
|
||||
3. **属性访问拦截**(在读取或设置时执行额外操作)
|
||||
4. **定义不可枚举属性**(如内置对象的一些方法)
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 数据描述符(value, writable)和存取描述符(get, set)不能同时使用
|
||||
2. 默认情况下,通过defineProperty添加的属性不可枚举、不可写、不可配置
|
||||
3. 在严格模式下,setter必须设置一个参数,否则会抛出错误
|
||||
4. getter不应有副作用(如修改其他属性值)
|
||||
|
||||
**实现简单响应式**
|
||||
|
||||
```javascript
|
||||
function defineReactive(obj, key, val) {
|
||||
Object.defineProperty(obj, key, {
|
||||
get() {
|
||||
console.log(`读取 ${key}: ${val}`);
|
||||
return val;
|
||||
},
|
||||
set(newVal) {
|
||||
console.log(`设置 ${key}: ${newVal}`);
|
||||
val = newVal;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const data = {};
|
||||
defineReactive(data, 'message', 'Hello');
|
||||
```
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>理解数据代理</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
</body>
|
||||
|
||||
<script>
|
||||
let obj1 = { x: 100 }
|
||||
let obj2 = { y: 200 }
|
||||
|
||||
Object.defineProperty(obj2, "x", {
|
||||
get() {
|
||||
return obj1.x
|
||||
},
|
||||
set(value) {
|
||||
obj1.x = value
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,104 @@
|
|||
# JavaScript 数据代理实现文档
|
||||
|
||||
## 一、基本概念
|
||||
|
||||
数据代理是指通过一个对象(代理对象)间接访问和操作另一个对象(目标对象)的属性。本示例展示了如何使用 `Object.defineProperty` 实现简单的数据代理。
|
||||
|
||||
## 二、代码实现解析
|
||||
|
||||
```javascript
|
||||
let obj1 = { x: 100 }; // 目标对象(被代理对象)
|
||||
let obj2 = { y: 200 }; // 代理对象
|
||||
|
||||
// 在obj2上定义x属性的代理
|
||||
Object.defineProperty(obj2, "x", {
|
||||
get() {
|
||||
return obj1.x; // 读取时返回obj1的x属性
|
||||
},
|
||||
set(value) {
|
||||
obj1.x = value; // 设置时修改obj1的x属性
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 三、核心机制说明
|
||||
|
||||
1. **代理原理**:
|
||||
- 通过 `Object.defineProperty` 在代理对象(obj2)上定义新属性
|
||||
- 使用 getter/setter 方法实现对目标对象(obj1)属性的间接访问
|
||||
|
||||
2. **访问流程**:
|
||||
- 读取 `obj2.x` → 触发 getter → 返回 `obj1.x` 的值
|
||||
- 设置 `obj2.x` → 触发 setter → 将值赋给 `obj1.x`
|
||||
|
||||
3. **特性**:
|
||||
- 透明的属性访问(使用者无需知道代理存在)
|
||||
- 可以在访问前后执行额外逻辑(如验证、日志等)
|
||||
|
||||
## 四、应用场景
|
||||
|
||||
| 场景 | 说明 | 示例 |
|
||||
| -------- | -------------------- | ------------------------------ |
|
||||
| 属性转发 | 跨对象访问属性 | 本示例实现 |
|
||||
| 数据验证 | 设置属性前检查有效性 | setter中添加验证逻辑 |
|
||||
| 访问控制 | 限制某些属性的访问 | getter中添加权限检查 |
|
||||
| 日志记录 | 跟踪属性访问 | getter/setter中添加console.log |
|
||||
|
||||
## 五、扩展实现
|
||||
|
||||
### 1. 多属性代理
|
||||
```javascript
|
||||
function proxyProperties(target, source, props) {
|
||||
props.forEach(prop => {
|
||||
Object.defineProperty(target, prop, {
|
||||
get() {
|
||||
return source[prop];
|
||||
},
|
||||
set(value) {
|
||||
source[prop] = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
proxyProperties(obj2, obj1, ['x', 'a', 'b']);
|
||||
```
|
||||
|
||||
### 2. Vue2 风格的数据代理
|
||||
```javascript
|
||||
function observe(obj) {
|
||||
const handler = {
|
||||
get(target, prop) {
|
||||
console.log(`读取 ${prop}`);
|
||||
return target[prop];
|
||||
},
|
||||
set(target, prop, value) {
|
||||
console.log(`设置 ${prop} 为 ${value}`);
|
||||
target[prop] = value;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return new Proxy(obj, handler);
|
||||
}
|
||||
|
||||
const observed = observe(obj1);
|
||||
```
|
||||
|
||||
## 六、注意事项
|
||||
|
||||
1. **性能考虑**:
|
||||
- 每个代理属性都会增加访问开销
|
||||
- 避免在性能关键路径上过度使用
|
||||
|
||||
2. **引用关系**:
|
||||
- 代理对象和目标对象保持独立
|
||||
- 修改代理属性会影响原始对象
|
||||
|
||||
3. **枚举特性**:
|
||||
- 默认情况下代理属性不可枚举
|
||||
- 需要显式设置 `enumerable: true`
|
||||
|
||||
4. **兼容性**:
|
||||
- `Object.defineProperty` 是 ES5 特性
|
||||
- 现代开发可考虑使用 ES6 Proxy
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="js/vue@2.7.16.js"></script>
|
||||
<title>Vue中的数据代理</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
Vue中的数据代理: <span>{{name}}</span>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
name: "代理..."
|
||||
}
|
||||
});
|
||||
|
||||
// 如果要查看可以使用 vm._data 看到name,在_data中做了数据劫持
|
||||
// 验证,data==_data 可以将data定义到外部之后使用 vm._data == data 即可
|
||||
// 通过 Object.defineProperty 对vm中对象进行映射,只要修改了 vm._data 或者 vm.xxx 会触发双向绑定
|
||||
</script>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,146 @@
|
|||
# Vue2 数据代理机制详解
|
||||
|
||||
## 一、核心概念
|
||||
|
||||
Vue2 中的数据代理是指 Vue 实例(vm)代理其 `data` 对象中属性的访问和修改操作。通过这种机制,我们可以直接通过 `vm.xxx` 访问 `data` 中的属性,而不需要写 `vm._data.xxx`。
|
||||
|
||||
## 二、代码示例解析
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
Vue中的数据代理: <span>{{name}}</span>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
name: "代理..."
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## 三、实现原理
|
||||
|
||||
### 1. 数据存储结构
|
||||
- 原始 `data` 对象被存储在 `vm._data` 属性中
|
||||
- 通过 `Object.defineProperty` 将 `data` 的属性代理到 Vue 实例上
|
||||
|
||||
### 2. 验证方法
|
||||
```javascript
|
||||
// 验证代理关系
|
||||
const externalData = { name: "代理..." };
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: externalData
|
||||
});
|
||||
|
||||
console.log(vm._data === externalData); // true
|
||||
console.log(vm.name === vm._data.name); // true
|
||||
```
|
||||
|
||||
### 3. 代理实现机制
|
||||
Vue 内部大致执行了以下操作:
|
||||
```javascript
|
||||
// 伪代码展示代理原理
|
||||
Object.keys(data).forEach(key => {
|
||||
Object.defineProperty(vm, key, {
|
||||
get() {
|
||||
return vm._data[key];
|
||||
},
|
||||
set(value) {
|
||||
vm._data[key] = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## 四、数据流图示
|
||||
|
||||
```
|
||||
模板访问
|
||||
↓
|
||||
vm.name (代理访问)
|
||||
↓
|
||||
vm._data.name (实际数据存储)
|
||||
↓
|
||||
数据劫持 (响应式系统)
|
||||
```
|
||||
|
||||
## 五、关键特性
|
||||
|
||||
| 特性 | 说明 | 示例 |
|
||||
| ---------- | ---------------------- | ------------------------------ |
|
||||
| 直接访问 | 省略 `_data` 前缀 | `vm.name` 代替 `vm._data.name` |
|
||||
| 响应式绑定 | 代理属性也是响应式的 | 修改 `vm.name` 会触发视图更新 |
|
||||
| 数据隔离 | `_data` 保存原始数据 | 防止直接修改破坏响应式 |
|
||||
| 统一入口 | 提供一致的数据访问方式 | 简化模板和方法的编写 |
|
||||
|
||||
## 六、与数据劫持的关系
|
||||
|
||||
1. **数据代理**:
|
||||
- 解决的是访问便捷性问题(`vm.xxx` vs `vm._data.xxx`)
|
||||
- 通过 `Object.defineProperty` 实现属性转发
|
||||
|
||||
2. **数据劫持**:
|
||||
- 解决的是响应式问题(数据变化触发视图更新)
|
||||
- 在 `vm._data` 上实现,通过重写 getter/setter
|
||||
|
||||
3. **协作流程**:
|
||||
- 模板访问 `{{name}}` → 触发代理 getter
|
||||
- 代理 getter 访问 `_data.name` → 触发劫持 getter
|
||||
- 建立依赖收集关系
|
||||
|
||||
## 七、注意事项
|
||||
|
||||
1. **新增属性**:
|
||||
- 直接 `vm.newProp = value` 不会成为响应式
|
||||
- 必须使用 `Vue.set` 或预先声明
|
||||
|
||||
2. **性能影响**:
|
||||
- 每个代理属性都会产生一定的内存开销
|
||||
- 大型项目应考虑分模块管理数据
|
||||
|
||||
3. **调试技巧**:
|
||||
- 通过 `vm._data` 查看原始数据
|
||||
- 使用 Vue Devtools 观察数据变化
|
||||
|
||||
4. **与 Vue3 区别**:
|
||||
- Vue3 使用 Proxy 实现更完善的代理
|
||||
- 可以检测属性添加/删除操作
|
||||
|
||||
## 八、扩展应用
|
||||
|
||||
### 1. 自定义代理逻辑
|
||||
```javascript
|
||||
// 在Vue实例上添加自定义代理
|
||||
created() {
|
||||
Object.defineProperty(this, 'fullName', {
|
||||
get() {
|
||||
return `${this.firstName} ${this.lastName}`;
|
||||
},
|
||||
set(value) {
|
||||
const parts = value.split(' ');
|
||||
this.firstName = parts[0];
|
||||
this.lastName = parts[1] || '';
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 代理模式应用
|
||||
```javascript
|
||||
// 实现组件间的数据代理
|
||||
const proxyMixin = {
|
||||
methods: {
|
||||
proxy(prop) {
|
||||
return {
|
||||
get: () => this[prop],
|
||||
set: (val) => this[prop] = val
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="js/vue@2.7.16.js"></script>
|
||||
<title>事件处理</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>Vue2-事件处理</h1>
|
||||
<button @click="showinfo1">函数不传参</button>
|
||||
<button @click="showinfo2($event,66)">函数传参</button>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
|
||||
},
|
||||
methods: {
|
||||
showinfo1() {
|
||||
alert("函数不传参");
|
||||
},
|
||||
showinfo2(event, val) {
|
||||
alert("函数传参")
|
||||
console.log(event, val);
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,158 @@
|
|||
# Vue2 事件处理机制文档
|
||||
|
||||
## 一、基本概念
|
||||
|
||||
Vue2 提供了 `v-on` 指令(简写为 `@`)用于监听 DOM 事件并执行相应的 JavaScript 代码。本示例展示了 Vue2 中事件处理的基本用法,包括不传参和传参两种场景。
|
||||
|
||||
## 二、代码示例解析
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<h1>Vue2-事件处理</h1>
|
||||
<button @click="showinfo1">函数不传参</button>
|
||||
<button @click="showinfo2($event,66)">函数传参</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
methods: {
|
||||
showinfo1() {
|
||||
alert("函数不传参");
|
||||
},
|
||||
showinfo2(event, val) {
|
||||
alert("函数传参")
|
||||
console.log(event, val);
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## 三、核心特性说明
|
||||
|
||||
### 1. 事件绑定语法
|
||||
|
||||
| 语法形式 | 示例 | 说明 |
|
||||
| -------- | ---------------------- | ----------------- |
|
||||
| 完整写法 | `v-on:click="handler"` | 使用 `v-on:` 前缀 |
|
||||
| 简写形式 | `@click="handler"` | 更简洁的写法 |
|
||||
|
||||
### 2. 方法定义位置
|
||||
|
||||
所有事件处理函数应定义在 Vue 实例的 `methods` 选项中:
|
||||
```javascript
|
||||
methods: {
|
||||
handler1() { /* ... */ },
|
||||
handler2() { /* ... */ }
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 参数传递方式
|
||||
|
||||
| 场景 | 示例 | 说明 |
|
||||
| -------------- | ------------------------------- | ------------------------------ |
|
||||
| 不传参 | `@click="showinfo1"` | 自动传入事件对象 |
|
||||
| 传参 | `@click="showinfo2($event,66)"` | 使用 `$event` 传递原生事件对象 |
|
||||
| 仅传自定义参数 | `@click="showinfo2(66)"` | 事件对象将不可用 |
|
||||
|
||||
## 四、事件对象详解
|
||||
|
||||
### 1. 获取事件对象的方式
|
||||
- **不传参时**:自动作为第一个参数传入
|
||||
```javascript
|
||||
methods: {
|
||||
showinfo1(event) {
|
||||
// event 可用
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **传参时需要**:必须显式传递 `$event`
|
||||
```html
|
||||
<button @click="showinfo2($event,66)">按钮</button>
|
||||
```
|
||||
|
||||
### 2. 常用事件对象属性
|
||||
| 属性/方法 | 类型 | 说明 |
|
||||
| ----------------------- | -------- | -------------- |
|
||||
| event.target | Element | 触发事件的元素 |
|
||||
| event.currentTarget | Element | 绑定事件的元素 |
|
||||
| event.preventDefault() | Function | 阻止默认行为 |
|
||||
| event.stopPropagation() | Function | 停止事件冒泡 |
|
||||
|
||||
## 五、最佳实践建议
|
||||
|
||||
1. **方法命名**:
|
||||
- 使用动词开头(如 `handleClick`、`submitForm`)
|
||||
- 保持名称语义化
|
||||
|
||||
2. **参数处理**:
|
||||
- 需要事件对象时确保正确传递 `$event`
|
||||
- 复杂参数建议使用对象形式:
|
||||
```html
|
||||
<button @click="handleClick({id: 1, name: 'test'})">按钮</button>
|
||||
```
|
||||
|
||||
3. **方法组织**:
|
||||
- 相关功能的方法放在一起
|
||||
- 大型组件可考虑按功能分模块
|
||||
|
||||
## 六、扩展应用
|
||||
|
||||
### 1. 事件修饰符
|
||||
Vue 提供了特殊的事件修饰符:
|
||||
|
||||
```html
|
||||
<!-- 阻止默认行为 -->
|
||||
<form @submit.prevent="onSubmit"></form>
|
||||
|
||||
<!-- 停止事件冒泡 -->
|
||||
<div @click.stop="doThis"></div>
|
||||
|
||||
<!-- 按键修饰符 -->
|
||||
<input @keyup.enter="submit">
|
||||
|
||||
<!-- 串联修饰符 -->
|
||||
<button @click.stop.prevent="doThat"></button>
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 2. 自定义事件
|
||||
|
||||
组件间通信时使用:
|
||||
|
||||
```javascript
|
||||
// 子组件
|
||||
this.$emit('my-event', payload);
|
||||
|
||||
// 父组件
|
||||
<child-component @my-event="handleEvent"></child-component>
|
||||
```
|
||||
|
||||
### 3. 原生事件绑定到组件
|
||||
使用 `.native` 修饰符:
|
||||
|
||||
```html
|
||||
<my-component @click.native="handleClick"></my-component>
|
||||
```
|
||||
|
||||
## 七、注意事项
|
||||
|
||||
1. **避免内联计算**:
|
||||
```html
|
||||
<!-- 不推荐 -->
|
||||
<button @click="counter++">增加</button>
|
||||
|
||||
<!-- 推荐 -->
|
||||
<button @click="increment">增加</button>
|
||||
```
|
||||
|
||||
2. **this 指向**:
|
||||
- methods 中的方法自动绑定到 Vue 实例
|
||||
- 避免使用箭头函数定义方法,会导致 this 指向错误
|
||||
|
||||
3. **性能考虑**:
|
||||
- 频繁触发的事件(如 scroll)建议使用防抖/节流
|
||||
- 大量事件监听应考虑事件委托
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="js/vue@2.7.16.js"></script>
|
||||
<title>键盘事件</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
键盘事件:<input type="text" @keydown.huiche="showinfo">
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
Vue.config.keyCodes.huiche = 13
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data: {},
|
||||
methods: {
|
||||
showinfo() {
|
||||
alert("showinfo")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,153 @@
|
|||
# Vue2 键盘事件处理文档
|
||||
|
||||
## 一、基本概念
|
||||
|
||||
Vue2 提供了对键盘事件的支持,允许开发者监听特定的按键操作。本示例展示了如何自定义键盘事件别名并处理回车键事件。
|
||||
|
||||
## 二、代码示例解析
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
键盘事件:<input type="text" @keydown.huiche="showinfo">
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 自定义按键别名
|
||||
Vue.config.keyCodes.huiche = 13; // 13是回车键的keyCode
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
methods: {
|
||||
showinfo() {
|
||||
alert("回车键被按下");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## 三、核心机制说明
|
||||
|
||||
### 1. 键盘事件绑定语法
|
||||
|
||||
| 语法形式 | 示例 | 说明 |
|
||||
| ---------- | --------------------------- | ------------------ |
|
||||
| 基础写法 | `@keydown="handler"` | 监听所有按键 |
|
||||
| 按键修饰符 | `@keydown.enter="handler"` | 仅监听回车键 |
|
||||
| 自定义别名 | `@keydown.huiche="handler"` | 使用自定义按键别名 |
|
||||
|
||||
### 2. 按键修饰符类型
|
||||
|
||||
Vue 提供了这些常用内置按键别名:
|
||||
- `.enter`
|
||||
- `.tab`
|
||||
- `.delete` (捕获"删除"和"退格"键)
|
||||
- `.esc`
|
||||
- `.space`
|
||||
- `.up`
|
||||
- `.down`
|
||||
- `.left`
|
||||
- `.right`
|
||||
|
||||
### 3. 自定义按键别名
|
||||
|
||||
通过 `Vue.config.keyCodes` 对象添加:
|
||||
```javascript
|
||||
// 语法
|
||||
Vue.config.keyCodes.自定义名称 = 按键keyCode;
|
||||
|
||||
// 示例:将F1键(112)别名为help
|
||||
Vue.config.keyCodes.help = 112;
|
||||
```
|
||||
|
||||
## 四、键盘事件对象
|
||||
|
||||
在方法中可以访问原生事件对象:
|
||||
```javascript
|
||||
methods: {
|
||||
showinfo(event) {
|
||||
console.log(event.key); // 按键名称(如'Enter')
|
||||
console.log(event.keyCode); // 按键代码(如13)
|
||||
console.log(event.target); // 触发事件的元素
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 五、最佳实践建议
|
||||
|
||||
1. **优先使用内置别名**:
|
||||
- 提高代码可读性
|
||||
- 避免记忆keyCode数字
|
||||
|
||||
2. **复杂按键组合**:
|
||||
```html
|
||||
<!-- Ctrl + Enter -->
|
||||
<input @keydown.ctrl.enter="submit">
|
||||
|
||||
<!-- Alt + C -->
|
||||
<input @keydown.alt.67="copy">
|
||||
```
|
||||
|
||||
3. **系统修饰键**:
|
||||
- `.ctrl`
|
||||
- `.alt`
|
||||
- `.shift`
|
||||
- `.meta` (Mac是Command键,Windows是Windows键)
|
||||
|
||||
## 六、扩展应用
|
||||
|
||||
### 1. 自动聚焦示例
|
||||
```html
|
||||
<input @keyup.enter="nextInput" ref="currentInput">
|
||||
|
||||
methods: {
|
||||
nextInput() {
|
||||
this.$refs.nextInput.focus();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 表单提交优化
|
||||
```html
|
||||
<form @submit.prevent>
|
||||
<input @keyup.enter="submit">
|
||||
<button @click="submit">提交</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
### 3. 游戏控制示例
|
||||
```javascript
|
||||
// 监听方向键控制游戏角色
|
||||
created() {
|
||||
window.addEventListener('keyup', this.handleKeyup);
|
||||
},
|
||||
methods: {
|
||||
handleKeyup(e) {
|
||||
switch(e.keyCode) {
|
||||
case 37: this.moveLeft(); break;
|
||||
case 38: this.moveUp(); break;
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 七、注意事项
|
||||
|
||||
1. **keyCode已废弃**:
|
||||
- 现代浏览器建议使用 `event.key` 代替
|
||||
- Vue3 已移除对keyCode的支持
|
||||
|
||||
2. **输入法问题**:
|
||||
- 某些输入法下可能无法正确触发事件
|
||||
- 中文输入时考虑使用 `@keyup` 代替 `@keydown`
|
||||
|
||||
3. **移动端适配**:
|
||||
- 虚拟键盘行为可能不一致
|
||||
- 建议配合触摸事件使用
|
||||
|
||||
4. **事件冒泡**:
|
||||
- 使用 `.stop` 修饰符阻止冒泡
|
||||
```html
|
||||
<div @keydown.enter.stop="handleEnter">
|
||||
```
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="js/vue@2.7.16.js"></script>
|
||||
<title>计算属性</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
姓:<input type="text" v-model="firstName" />
|
||||
名:<input type="text" v-model="lastName" />
|
||||
|
||||
全名:<span>{{fullName}}</span>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
}
|
||||
},
|
||||
methods: {},
|
||||
computed: {
|
||||
fullName: {
|
||||
get() {
|
||||
return `${this.firstName}-${this.lastName}`
|
||||
},
|
||||
set(val) { }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,165 @@
|
|||
# Vue2 计算属性详解文档
|
||||
|
||||
## 一、基本概念
|
||||
|
||||
计算属性(Computed Properties)是 Vue2 中用于声明式地定义派生数据的特性。它们基于响应式依赖进行缓存,只在相关依赖发生改变时才重新计算。
|
||||
|
||||
## 二、代码示例解析
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
姓:<input type="text" v-model="firstName">
|
||||
名:<input type="text" v-model="lastName">
|
||||
全名:<span>{{fullName}}</span>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
firstName: "",
|
||||
lastName: ""
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fullName: {
|
||||
get() {
|
||||
return `${this.firstName}-${this.lastName}`
|
||||
},
|
||||
set(val) {
|
||||
// 可选的setter
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## 三、核心特性
|
||||
|
||||
### 1. 计算属性 vs 方法
|
||||
|
||||
| 特性 | 计算属性 | 方法 |
|
||||
| -------- | -------------------------- | --------------------------- |
|
||||
| 缓存 | 有缓存,依赖不变不重新计算 | 每次调用都执行 |
|
||||
| 调用方式 | 作为属性访问 | 需要调用执行 |
|
||||
| 适用场景 | 派生数据 | 事件处理/需要重复执行的逻辑 |
|
||||
|
||||
### 2. 完整语法结构
|
||||
|
||||
```javascript
|
||||
computed: {
|
||||
属性名: {
|
||||
get() {
|
||||
// 计算逻辑
|
||||
return 派生值
|
||||
},
|
||||
set(value) {
|
||||
// 可选的反向更新逻辑
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 简写形式(只读场景)
|
||||
|
||||
```javascript
|
||||
computed: {
|
||||
fullName() {
|
||||
return `${this.firstName}-${this.lastName}`
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 四、最佳实践
|
||||
|
||||
1. **命名规范**:
|
||||
- 使用名词形式(如 `fullName`)
|
||||
- 避免动词开头(这是方法的命名习惯)
|
||||
|
||||
2. **纯计算逻辑**:
|
||||
- 不要在getter中执行异步操作或副作用
|
||||
- 复杂计算考虑拆分为多个计算属性
|
||||
|
||||
3. **setter使用场景**:
|
||||
- 当需要反向更新依赖数据时
|
||||
- 示例:
|
||||
```javascript
|
||||
set(val) {
|
||||
const parts = val.split('-');
|
||||
this.firstName = parts[0] || '';
|
||||
this.lastName = parts[1] || '';
|
||||
}
|
||||
```
|
||||
|
||||
## 五、高级用法
|
||||
|
||||
### 1. 依赖多个数据源
|
||||
|
||||
```javascript
|
||||
computed: {
|
||||
summary() {
|
||||
return `总计:${this.items.length}件,${this.totalPrice}元`
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 结合过滤器使用
|
||||
|
||||
```javascript
|
||||
computed: {
|
||||
formattedDate() {
|
||||
return dayjs(this.rawDate).format('YYYY-MM-DD')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 计算属性嵌套
|
||||
|
||||
```javascript
|
||||
computed: {
|
||||
baseInfo() {
|
||||
return { ...this.user, age: this.calcAge }
|
||||
},
|
||||
calcAge() {
|
||||
return new Date().getFullYear() - this.user.birthYear
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 六、性能优化
|
||||
|
||||
1. **减少大数组计算**:
|
||||
```javascript
|
||||
computed: {
|
||||
visibleItems() {
|
||||
return this.items.filter(item =>
|
||||
item.name.includes(this.search) &&
|
||||
item.status === 'active'
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **避免频繁计算**:
|
||||
- 对于复杂计算考虑使用 `methods` + 防抖
|
||||
- 或使用 `watch` 手动控制计算时机
|
||||
|
||||
3. **缓存利用**:
|
||||
- 相同依赖多次访问不会重复计算
|
||||
- 模板中可安全多次引用同一计算属性
|
||||
|
||||
## 七、常见问题
|
||||
|
||||
1. **为什么计算属性不更新?**
|
||||
- 检查依赖数据是否是响应式的
|
||||
- 确保没有在getter中意外修改了依赖数据
|
||||
|
||||
2. **何时使用计算属性 vs watch?**
|
||||
- 计算属性:基于多个数据的派生数据
|
||||
- watch:需要在数据变化时执行异步或开销较大的操作
|
||||
|
||||
3. **计算属性能接收参数吗?**
|
||||
- 不能直接接收参数,如需参数化应使用方法
|
||||
- 替代方案:返回函数或使用闭包
|
|
@ -0,0 +1,168 @@
|
|||
# Vue 2 中样式动态绑定和使用文档
|
||||
|
||||
在 Vue 2 中,动态绑定样式是非常常见的需求,可以通过多种方式实现。以下是详细的文档说明:
|
||||
|
||||
## 一、对象语法
|
||||
|
||||
### 1. 基本对象语法
|
||||
|
||||
```html
|
||||
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
|
||||
```
|
||||
|
||||
```javascript
|
||||
data() {
|
||||
return {
|
||||
activeColor: 'red',
|
||||
fontSize: 30
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 样式对象直接绑定
|
||||
|
||||
```html
|
||||
<div :style="styleObject"></div>
|
||||
```
|
||||
|
||||
```javascript
|
||||
data() {
|
||||
return {
|
||||
styleObject: {
|
||||
color: 'red',
|
||||
fontSize: '13px'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 二、数组语法
|
||||
|
||||
可以将多个样式对象应用到同一个元素上:
|
||||
|
||||
```html
|
||||
<div :style="[baseStyles, overridingStyles]"></div>
|
||||
```
|
||||
|
||||
```javascript
|
||||
data() {
|
||||
return {
|
||||
baseStyles: {
|
||||
color: 'blue',
|
||||
fontSize: '14px'
|
||||
},
|
||||
overridingStyles: {
|
||||
color: 'red'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 三、自动前缀
|
||||
|
||||
当使用需要浏览器前缀的 CSS 属性时(如 `transform`),Vue 会自动检测并添加适当的前缀。
|
||||
|
||||
```html
|
||||
<div :style="{ transform: 'scale(' + scale + ')' }"></div>
|
||||
```
|
||||
|
||||
## 四、多重值
|
||||
|
||||
可以为样式属性提供包含多个值的数组,常用于提供多个带前缀的值:
|
||||
|
||||
```html
|
||||
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
|
||||
```
|
||||
|
||||
## 五、绑定 class
|
||||
|
||||
### 1. 对象语法
|
||||
|
||||
```html
|
||||
<div class="static" :class="{ active: isActive, 'text-danger': hasError }"></div>
|
||||
```
|
||||
|
||||
```javascript
|
||||
data() {
|
||||
return {
|
||||
isActive: true,
|
||||
hasError: false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 数组语法
|
||||
|
||||
```html
|
||||
<div :class="[activeClass, errorClass]"></div>
|
||||
```
|
||||
|
||||
```javascript
|
||||
data() {
|
||||
return {
|
||||
activeClass: 'active',
|
||||
errorClass: 'text-danger'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 在组件上使用
|
||||
|
||||
当在自定义组件上使用 `class` 属性时,这些类将被添加到该组件的根元素上,且不会覆盖已有的类。
|
||||
|
||||
```html
|
||||
<my-component class="baz boo" :class="{ active: isActive }"></my-component>
|
||||
```
|
||||
|
||||
## 六、计算属性绑定
|
||||
|
||||
对于复杂的样式逻辑,推荐使用计算属性:
|
||||
|
||||
```html
|
||||
<div :class="classObject"></div>
|
||||
```
|
||||
|
||||
```javascript
|
||||
computed: {
|
||||
classObject() {
|
||||
return {
|
||||
active: this.isActive && !this.error,
|
||||
'text-danger': this.error && this.error.type === 'fatal'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 七、注意事项
|
||||
|
||||
1. **浏览器兼容性**:Vue 会自动添加浏览器前缀,但仍需注意某些 CSS 属性在不同浏览器中的支持情况。
|
||||
|
||||
2. **性能考虑**:频繁修改样式绑定可能会影响性能,特别是在大量元素上使用时。
|
||||
|
||||
3. **优先级**:`:style` 和 `:class` 绑定的样式会与普通样式合并,`:style` 的优先级高于内联样式。
|
||||
|
||||
4. **CSS 变量**:Vue 2.6+ 支持 CSS 变量绑定:
|
||||
|
||||
```html
|
||||
<div :style="{'--color': themeColor}"></div>
|
||||
```
|
||||
|
||||
## 八、最佳实践
|
||||
|
||||
1. 对于简单的样式切换,使用对象语法
|
||||
2. 对于多个条件类,使用计算属性
|
||||
3. 避免在模板中写复杂的样式逻辑
|
||||
4. 考虑使用 CSS Modules 或 Scoped CSS 来管理组件样式
|
||||
|
||||
## 九、与 CSS 预处理器配合
|
||||
|
||||
Vue 支持与 Sass/SCSS、Less、Stylus 等预处理器一起使用:
|
||||
|
||||
```html
|
||||
<style lang="scss">
|
||||
$primary-color: #42b983;
|
||||
.text {
|
||||
color: $primary-color;
|
||||
}
|
||||
</style>
|
||||
```
|
|
@ -0,0 +1,40 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="js/vue@2.7.16.js"></script>
|
||||
<title>监视属性</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2>天气很什么:{{isHot}}</h2>
|
||||
<button @click="changeWeather">切换天气</button>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
isHot: true
|
||||
},
|
||||
methods: {
|
||||
changeWeather() {
|
||||
this.isHot = !this.isHot
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
immediate: true,
|
||||
isHot: {
|
||||
handler(newVal, oldVal) {
|
||||
console.log("值修改", newVal, oldVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,166 @@
|
|||
# Vue2 监视属性(Watch)详解文档
|
||||
|
||||
## 一、基本概念
|
||||
|
||||
监视属性(Watch)是 Vue2 中用于观察和响应数据变化的机制。它允许你在数据变化时执行异步操作或更复杂的逻辑。
|
||||
|
||||
## 二、代码示例解析
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<h2>天气很什么:{{isHot ? '炎热' : '凉爽'}}</h2>
|
||||
<button @click="changeWeather">切换天气</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const vm = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
isHot: true
|
||||
},
|
||||
methods: {
|
||||
changeWeather() {
|
||||
this.isHot = !this.isHot;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isHot: {
|
||||
immediate: true, // 立即执行handler
|
||||
handler(newVal, oldVal) {
|
||||
console.log("天气状态修改", newVal, oldVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## 三、核心特性
|
||||
|
||||
### 1. 基本语法结构
|
||||
|
||||
```javascript
|
||||
watch: {
|
||||
要监视的属性: {
|
||||
handler(newValue, oldValue) {
|
||||
// 响应变化
|
||||
},
|
||||
immediate: false, // 是否立即执行
|
||||
deep: false // 是否深度监视
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 简写形式(不需要配置项时)
|
||||
|
||||
```javascript
|
||||
watch: {
|
||||
isHot(newVal, oldVal) {
|
||||
console.log("天气变化", newVal, oldVal);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 深度监视(deep watch)
|
||||
|
||||
通常监视对象属性。
|
||||
|
||||
```javascript
|
||||
watch: {
|
||||
someObject: {
|
||||
handler(newVal) {
|
||||
console.log("对象内部变化", newVal);
|
||||
},
|
||||
deep: true // 深度监视对象内部值变化
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 四、配置选项说明
|
||||
|
||||
| 选项 | 类型 | 默认值 | 说明 |
|
||||
| --------- | -------- | ------ | ---------------------------- |
|
||||
| handler | Function | 必填 | 数据变化时的回调函数 |
|
||||
| immediate | Boolean | false | 是否立即以当前值执行handler |
|
||||
| deep | Boolean | false | 是否深度观察对象内部值的变化 |
|
||||
|
||||
## 五、最佳实践
|
||||
|
||||
1. **命名规范**:
|
||||
- 监视属性通常以 `watch` 开头命名方法(如 `watchIsHotChange`)
|
||||
- 或者直接使用被监视的属性名
|
||||
|
||||
2. **使用场景**:
|
||||
- 数据变化需要执行异步操作时
|
||||
- 数据变化需要执行开销较大的操作时
|
||||
- 需要观察嵌套数据结构变化时
|
||||
|
||||
3. **性能考虑**:
|
||||
- 避免在handler中执行复杂同步操作
|
||||
- 对于大对象,谨慎使用deep watch
|
||||
|
||||
## 六、高级用法
|
||||
|
||||
### 1. 监视计算属性
|
||||
|
||||
```javascript
|
||||
computed: {
|
||||
weatherDesc() {
|
||||
return this.isHot ? "炎热" : "凉爽";
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
weatherDesc(newVal) {
|
||||
console.log("天气描述变化:", newVal);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 监视路由变化
|
||||
|
||||
```javascript
|
||||
watch: {
|
||||
'$route'(to, from) {
|
||||
console.log("路由变化", to.path, from.path);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 多属性监视
|
||||
|
||||
```javascript
|
||||
watch: {
|
||||
// 监视多个属性
|
||||
'a.b.c': function(newVal) {
|
||||
// 当a.b.c变化时执行
|
||||
},
|
||||
'x.y': 'someMethod' // 直接调用methods中的方法
|
||||
}
|
||||
```
|
||||
|
||||
## 七、与计算属性的比较
|
||||
|
||||
| 特性 | 计算属性 | 监视属性 |
|
||||
| ------ | ------------ | ------------ |
|
||||
| 目的 | 派生新数据 | 响应数据变化 |
|
||||
| 缓存 | 有缓存 | 无缓存 |
|
||||
| 异步 | 不支持 | 支持 |
|
||||
| 返回值 | 必须返回 | 不需要返回 |
|
||||
| 复杂度 | 适合简单计算 | 适合复杂逻辑 |
|
||||
|
||||
## 八、常见问题
|
||||
|
||||
1. **为什么handler没有被调用?**
|
||||
- 检查监视的属性名拼写是否正确
|
||||
- 确认属性值确实发生了变化(对于对象/数组,可能需要深度监视)
|
||||
|
||||
2. **什么时候使用deep watch?**
|
||||
- 当需要检测对象内部属性变化时
|
||||
- 注意性能影响,必要时可以指定具体路径如 `'obj.prop'`
|
||||
|
||||
3. **如何取消监视?**
|
||||
- 使用 `vm.$watch()` 返回的取消函数:
|
||||
```javascript
|
||||
const unwatch = this.$watch('someProp', handler);
|
||||
unwatch(); // 取消监视
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 99 KiB |
|
@ -0,0 +1,481 @@
|
|||
!(function (t, e) {
|
||||
"object" == typeof exports && "undefined" != typeof module
|
||||
? (module.exports = e())
|
||||
: "function" == typeof define && define.amd
|
||||
? define(e)
|
||||
: ((t = "undefined" != typeof globalThis ? globalThis : t || self).dayjs =
|
||||
e());
|
||||
})(this, function () {
|
||||
"use strict";
|
||||
var t = 1e3,
|
||||
e = 6e4,
|
||||
n = 36e5,
|
||||
r = "millisecond",
|
||||
i = "second",
|
||||
s = "minute",
|
||||
u = "hour",
|
||||
a = "day",
|
||||
o = "week",
|
||||
c = "month",
|
||||
f = "quarter",
|
||||
h = "year",
|
||||
d = "date",
|
||||
l = "Invalid Date",
|
||||
$ =
|
||||
/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,
|
||||
y =
|
||||
/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,
|
||||
M = {
|
||||
name: "en",
|
||||
weekdays:
|
||||
"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
|
||||
months:
|
||||
"January_February_March_April_May_June_July_August_September_October_November_December".split(
|
||||
"_"
|
||||
),
|
||||
ordinal: function (t) {
|
||||
var e = ["th", "st", "nd", "rd"],
|
||||
n = t % 100;
|
||||
return "[" + t + (e[(n - 20) % 10] || e[n] || e[0]) + "]";
|
||||
},
|
||||
},
|
||||
m = function (t, e, n) {
|
||||
var r = String(t);
|
||||
return !r || r.length >= e ? t : "" + Array(e + 1 - r.length).join(n) + t;
|
||||
},
|
||||
v = {
|
||||
s: m,
|
||||
z: function (t) {
|
||||
var e = -t.utcOffset(),
|
||||
n = Math.abs(e),
|
||||
r = Math.floor(n / 60),
|
||||
i = n % 60;
|
||||
return (e <= 0 ? "+" : "-") + m(r, 2, "0") + ":" + m(i, 2, "0");
|
||||
},
|
||||
m: function t(e, n) {
|
||||
if (e.date() < n.date()) return -t(n, e);
|
||||
var r = 12 * (n.year() - e.year()) + (n.month() - e.month()),
|
||||
i = e.clone().add(r, c),
|
||||
s = n - i < 0,
|
||||
u = e.clone().add(r + (s ? -1 : 1), c);
|
||||
return +(-(r + (n - i) / (s ? i - u : u - i)) || 0);
|
||||
},
|
||||
a: function (t) {
|
||||
return t < 0 ? Math.ceil(t) || 0 : Math.floor(t);
|
||||
},
|
||||
p: function (t) {
|
||||
return (
|
||||
{ M: c, y: h, w: o, d: a, D: d, h: u, m: s, s: i, ms: r, Q: f }[t] ||
|
||||
String(t || "")
|
||||
.toLowerCase()
|
||||
.replace(/s$/, "")
|
||||
);
|
||||
},
|
||||
u: function (t) {
|
||||
return void 0 === t;
|
||||
},
|
||||
},
|
||||
g = "en",
|
||||
D = {};
|
||||
D[g] = M;
|
||||
var p = "$isDayjsObject",
|
||||
S = function (t) {
|
||||
return t instanceof _ || !(!t || !t[p]);
|
||||
},
|
||||
w = function t(e, n, r) {
|
||||
var i;
|
||||
if (!e) return g;
|
||||
if ("string" == typeof e) {
|
||||
var s = e.toLowerCase();
|
||||
D[s] && (i = s), n && ((D[s] = n), (i = s));
|
||||
var u = e.split("-");
|
||||
if (!i && u.length > 1) return t(u[0]);
|
||||
} else {
|
||||
var a = e.name;
|
||||
(D[a] = e), (i = a);
|
||||
}
|
||||
return !r && i && (g = i), i || (!r && g);
|
||||
},
|
||||
O = function (t, e) {
|
||||
if (S(t)) return t.clone();
|
||||
var n = "object" == typeof e ? e : {};
|
||||
return (n.date = t), (n.args = arguments), new _(n);
|
||||
},
|
||||
b = v;
|
||||
(b.l = w),
|
||||
(b.i = S),
|
||||
(b.w = function (t, e) {
|
||||
return O(t, { locale: e.$L, utc: e.$u, x: e.$x, $offset: e.$offset });
|
||||
});
|
||||
var _ = (function () {
|
||||
function M(t) {
|
||||
(this.$L = w(t.locale, null, !0)),
|
||||
this.parse(t),
|
||||
(this.$x = this.$x || t.x || {}),
|
||||
(this[p] = !0);
|
||||
}
|
||||
var m = M.prototype;
|
||||
return (
|
||||
(m.parse = function (t) {
|
||||
(this.$d = (function (t) {
|
||||
var e = t.date,
|
||||
n = t.utc;
|
||||
if (null === e) return new Date(NaN);
|
||||
if (b.u(e)) return new Date();
|
||||
if (e instanceof Date) return new Date(e);
|
||||
if ("string" == typeof e && !/Z$/i.test(e)) {
|
||||
var r = e.match($);
|
||||
if (r) {
|
||||
var i = r[2] - 1 || 0,
|
||||
s = (r[7] || "0").substring(0, 3);
|
||||
return n
|
||||
? new Date(
|
||||
Date.UTC(
|
||||
r[1],
|
||||
i,
|
||||
r[3] || 1,
|
||||
r[4] || 0,
|
||||
r[5] || 0,
|
||||
r[6] || 0,
|
||||
s
|
||||
)
|
||||
)
|
||||
: new Date(
|
||||
r[1],
|
||||
i,
|
||||
r[3] || 1,
|
||||
r[4] || 0,
|
||||
r[5] || 0,
|
||||
r[6] || 0,
|
||||
s
|
||||
);
|
||||
}
|
||||
}
|
||||
return new Date(e);
|
||||
})(t)),
|
||||
this.init();
|
||||
}),
|
||||
(m.init = function () {
|
||||
var t = this.$d;
|
||||
(this.$y = t.getFullYear()),
|
||||
(this.$M = t.getMonth()),
|
||||
(this.$D = t.getDate()),
|
||||
(this.$W = t.getDay()),
|
||||
(this.$H = t.getHours()),
|
||||
(this.$m = t.getMinutes()),
|
||||
(this.$s = t.getSeconds()),
|
||||
(this.$ms = t.getMilliseconds());
|
||||
}),
|
||||
(m.$utils = function () {
|
||||
return b;
|
||||
}),
|
||||
(m.isValid = function () {
|
||||
return !(this.$d.toString() === l);
|
||||
}),
|
||||
(m.isSame = function (t, e) {
|
||||
var n = O(t);
|
||||
return this.startOf(e) <= n && n <= this.endOf(e);
|
||||
}),
|
||||
(m.isAfter = function (t, e) {
|
||||
return O(t) < this.startOf(e);
|
||||
}),
|
||||
(m.isBefore = function (t, e) {
|
||||
return this.endOf(e) < O(t);
|
||||
}),
|
||||
(m.$g = function (t, e, n) {
|
||||
return b.u(t) ? this[e] : this.set(n, t);
|
||||
}),
|
||||
(m.unix = function () {
|
||||
return Math.floor(this.valueOf() / 1e3);
|
||||
}),
|
||||
(m.valueOf = function () {
|
||||
return this.$d.getTime();
|
||||
}),
|
||||
(m.startOf = function (t, e) {
|
||||
var n = this,
|
||||
r = !!b.u(e) || e,
|
||||
f = b.p(t),
|
||||
l = function (t, e) {
|
||||
var i = b.w(
|
||||
n.$u ? Date.UTC(n.$y, e, t) : new Date(n.$y, e, t),
|
||||
n
|
||||
);
|
||||
return r ? i : i.endOf(a);
|
||||
},
|
||||
$ = function (t, e) {
|
||||
return b.w(
|
||||
n
|
||||
.toDate()
|
||||
[t].apply(
|
||||
n.toDate("s"),
|
||||
(r ? [0, 0, 0, 0] : [23, 59, 59, 999]).slice(e)
|
||||
),
|
||||
n
|
||||
);
|
||||
},
|
||||
y = this.$W,
|
||||
M = this.$M,
|
||||
m = this.$D,
|
||||
v = "set" + (this.$u ? "UTC" : "");
|
||||
switch (f) {
|
||||
case h:
|
||||
return r ? l(1, 0) : l(31, 11);
|
||||
case c:
|
||||
return r ? l(1, M) : l(0, M + 1);
|
||||
case o:
|
||||
var g = this.$locale().weekStart || 0,
|
||||
D = (y < g ? y + 7 : y) - g;
|
||||
return l(r ? m - D : m + (6 - D), M);
|
||||
case a:
|
||||
case d:
|
||||
return $(v + "Hours", 0);
|
||||
case u:
|
||||
return $(v + "Minutes", 1);
|
||||
case s:
|
||||
return $(v + "Seconds", 2);
|
||||
case i:
|
||||
return $(v + "Milliseconds", 3);
|
||||
default:
|
||||
return this.clone();
|
||||
}
|
||||
}),
|
||||
(m.endOf = function (t) {
|
||||
return this.startOf(t, !1);
|
||||
}),
|
||||
(m.$set = function (t, e) {
|
||||
var n,
|
||||
o = b.p(t),
|
||||
f = "set" + (this.$u ? "UTC" : ""),
|
||||
l = ((n = {}),
|
||||
(n[a] = f + "Date"),
|
||||
(n[d] = f + "Date"),
|
||||
(n[c] = f + "Month"),
|
||||
(n[h] = f + "FullYear"),
|
||||
(n[u] = f + "Hours"),
|
||||
(n[s] = f + "Minutes"),
|
||||
(n[i] = f + "Seconds"),
|
||||
(n[r] = f + "Milliseconds"),
|
||||
n)[o],
|
||||
$ = o === a ? this.$D + (e - this.$W) : e;
|
||||
if (o === c || o === h) {
|
||||
var y = this.clone().set(d, 1);
|
||||
y.$d[l]($),
|
||||
y.init(),
|
||||
(this.$d = y.set(d, Math.min(this.$D, y.daysInMonth())).$d);
|
||||
} else l && this.$d[l]($);
|
||||
return this.init(), this;
|
||||
}),
|
||||
(m.set = function (t, e) {
|
||||
return this.clone().$set(t, e);
|
||||
}),
|
||||
(m.get = function (t) {
|
||||
return this[b.p(t)]();
|
||||
}),
|
||||
(m.add = function (r, f) {
|
||||
var d,
|
||||
l = this;
|
||||
r = Number(r);
|
||||
var $ = b.p(f),
|
||||
y = function (t) {
|
||||
var e = O(l);
|
||||
return b.w(e.date(e.date() + Math.round(t * r)), l);
|
||||
};
|
||||
if ($ === c) return this.set(c, this.$M + r);
|
||||
if ($ === h) return this.set(h, this.$y + r);
|
||||
if ($ === a) return y(1);
|
||||
if ($ === o) return y(7);
|
||||
var M = ((d = {}), (d[s] = e), (d[u] = n), (d[i] = t), d)[$] || 1,
|
||||
m = this.$d.getTime() + r * M;
|
||||
return b.w(m, this);
|
||||
}),
|
||||
(m.subtract = function (t, e) {
|
||||
return this.add(-1 * t, e);
|
||||
}),
|
||||
(m.format = function (t) {
|
||||
var e = this,
|
||||
n = this.$locale();
|
||||
if (!this.isValid()) return n.invalidDate || l;
|
||||
var r = t || "YYYY-MM-DDTHH:mm:ssZ",
|
||||
i = b.z(this),
|
||||
s = this.$H,
|
||||
u = this.$m,
|
||||
a = this.$M,
|
||||
o = n.weekdays,
|
||||
c = n.months,
|
||||
f = n.meridiem,
|
||||
h = function (t, n, i, s) {
|
||||
return (t && (t[n] || t(e, r))) || i[n].slice(0, s);
|
||||
},
|
||||
d = function (t) {
|
||||
return b.s(s % 12 || 12, t, "0");
|
||||
},
|
||||
$ =
|
||||
f ||
|
||||
function (t, _e, n) {
|
||||
var r = t < 12 ? "AM" : "PM";
|
||||
return n ? r.toLowerCase() : r;
|
||||
};
|
||||
return r.replace(y, function (t, r) {
|
||||
return (
|
||||
r ||
|
||||
(function (t) {
|
||||
switch (t) {
|
||||
case "YY":
|
||||
return String(e.$y).slice(-2);
|
||||
case "YYYY":
|
||||
return b.s(e.$y, 4, "0");
|
||||
case "M":
|
||||
return a + 1;
|
||||
case "MM":
|
||||
return b.s(a + 1, 2, "0");
|
||||
case "MMM":
|
||||
return h(n.monthsShort, a, c, 3);
|
||||
case "MMMM":
|
||||
return h(c, a);
|
||||
case "D":
|
||||
return e.$D;
|
||||
case "DD":
|
||||
return b.s(e.$D, 2, "0");
|
||||
case "d":
|
||||
return String(e.$W);
|
||||
case "dd":
|
||||
return h(n.weekdaysMin, e.$W, o, 2);
|
||||
case "ddd":
|
||||
return h(n.weekdaysShort, e.$W, o, 3);
|
||||
case "dddd":
|
||||
return o[e.$W];
|
||||
case "H":
|
||||
return String(s);
|
||||
case "HH":
|
||||
return b.s(s, 2, "0");
|
||||
case "h":
|
||||
return d(1);
|
||||
case "hh":
|
||||
return d(2);
|
||||
case "a":
|
||||
return $(s, u, !0);
|
||||
case "A":
|
||||
return $(s, u, !1);
|
||||
case "m":
|
||||
return String(u);
|
||||
case "mm":
|
||||
return b.s(u, 2, "0");
|
||||
case "s":
|
||||
return String(e.$s);
|
||||
case "ss":
|
||||
return b.s(e.$s, 2, "0");
|
||||
case "SSS":
|
||||
return b.s(e.$ms, 3, "0");
|
||||
case "Z":
|
||||
return i;
|
||||
}
|
||||
return null;
|
||||
})(t) ||
|
||||
i.replace(":", "")
|
||||
);
|
||||
});
|
||||
}),
|
||||
(m.utcOffset = function () {
|
||||
return 15 * -Math.round(this.$d.getTimezoneOffset() / 15);
|
||||
}),
|
||||
(m.diff = function (r, d, l) {
|
||||
var $,
|
||||
y = this,
|
||||
M = b.p(d),
|
||||
m = O(r),
|
||||
v = (m.utcOffset() - this.utcOffset()) * e,
|
||||
g = this - m,
|
||||
D = function () {
|
||||
return b.m(y, m);
|
||||
};
|
||||
switch (M) {
|
||||
case h:
|
||||
$ = D() / 12;
|
||||
break;
|
||||
case c:
|
||||
$ = D();
|
||||
break;
|
||||
case f:
|
||||
$ = D() / 3;
|
||||
break;
|
||||
case o:
|
||||
$ = (g - v) / 6048e5;
|
||||
break;
|
||||
case a:
|
||||
$ = (g - v) / 864e5;
|
||||
break;
|
||||
case u:
|
||||
$ = g / n;
|
||||
break;
|
||||
case s:
|
||||
$ = g / e;
|
||||
break;
|
||||
case i:
|
||||
$ = g / t;
|
||||
break;
|
||||
default:
|
||||
$ = g;
|
||||
}
|
||||
return l ? $ : b.a($);
|
||||
}),
|
||||
(m.daysInMonth = function () {
|
||||
return this.endOf(c).$D;
|
||||
}),
|
||||
(m.$locale = function () {
|
||||
return D[this.$L];
|
||||
}),
|
||||
(m.locale = function (t, e) {
|
||||
if (!t) return this.$L;
|
||||
var n = this.clone(),
|
||||
r = w(t, e, !0);
|
||||
return r && (n.$L = r), n;
|
||||
}),
|
||||
(m.clone = function () {
|
||||
return b.w(this.$d, this);
|
||||
}),
|
||||
(m.toDate = function () {
|
||||
return new Date(this.valueOf());
|
||||
}),
|
||||
(m.toJSON = function () {
|
||||
return this.isValid() ? this.toISOString() : null;
|
||||
}),
|
||||
(m.toISOString = function () {
|
||||
return this.$d.toISOString();
|
||||
}),
|
||||
(m.toString = function () {
|
||||
return this.$d.toUTCString();
|
||||
}),
|
||||
M
|
||||
);
|
||||
})(),
|
||||
k = _.prototype;
|
||||
return (
|
||||
(O.prototype = k),
|
||||
[
|
||||
["$ms", r],
|
||||
["$s", i],
|
||||
["$m", s],
|
||||
["$H", u],
|
||||
["$W", a],
|
||||
["$M", c],
|
||||
["$y", h],
|
||||
["$D", d],
|
||||
].forEach(function (t) {
|
||||
k[t[1]] = function (e) {
|
||||
return this.$g(e, t[0], t[1]);
|
||||
};
|
||||
}),
|
||||
(O.extend = function (t, e) {
|
||||
return t.$i || (t(e, _, O), (t.$i = !0)), O;
|
||||
}),
|
||||
(O.locale = w),
|
||||
(O.isDayjs = S),
|
||||
(O.unix = function (t) {
|
||||
return O(1e3 * t);
|
||||
}),
|
||||
(O.en = D[g]),
|
||||
(O.Ls = D),
|
||||
(O.p = {}),
|
||||
O
|
||||
);
|
||||
});
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue