自用大模型评测问题(持续更新中)

背景

一直有新的大模型出现,每个都很好,但是很多都是宣传没输过,体验(相对于 GPT-4o 和 Claude 3.5 Sonnet)没赢过

一直有各种宣传骗我去体验,所以就直接准备几个个人实际使用中的,有一点难度的问题,看看大模型会怎么反馈,这里姑且记录一下

为了防止官网降智,我都尽量用 api 输出答案

目前 ChatGPT-Next-Web 对 o1-preview 的支持坏了,稍后等它修了再补一点 o1-preview 的答案

每个回答下面,附上了使用的具体模型和测试时间

为了方便复制问题进行复现,所有问题的原文都放在代码块里了

问题

问题一

1
cloudflare如何在wrangler.toml中使用.dev.vars中的变量

GPT-4o

gpt-4o-2024-08-06, 20250101


在使用 Cloudflare Wrangler 时,你可以通过在 wrangler.toml 文件中引用 .dev.vars 文件中的变量来管理你的环境变量。以下是如何设置和使用这些变量的步骤:

  1. 创建 .dev.vars 文件:

    • 在你的项目根目录下创建一个名为 .dev.vars 的文件。
    • 在这个文件中,定义你的环境变量,每行一个,格式为 KEY="value"
    1
    2
    API_KEY="your_api_key"
    SECRET="your_secret_value"
  2. 配置 wrangler.toml 文件:

    • wrangler.toml 文件中,确保你有以下配置来指示 Wrangler 使用 .dev.vars 文件。
    1
    2
    3
    4
    5
    name = "your-worker-name"
    type = "javascript"

    [env.dev]
    vars = { file = ".dev.vars" }
  3. 使用这些变量:

    • 在你的 Worker 代码中,你可以通过 env 对象来访问这些变量。
    1
    2
    3
    4
    5
    6
    7
    8
    export default {
    async fetch(request, env) {
    const apiKey = env.API_KEY;
    const secret = env.SECRET;
    // 使用变量进行你的业务逻辑
    return new Response(`API Key: ${apiKey}, Secret: ${secret}`);
    }
    }
  4. 运行你的 Worker:

    • 使用 wrangler dev --env dev 来启动你的开发环境,确保它加载 .dev.vars 中的变量。

这样,你就可以在本地开发环境中使用 .dev.vars 文件来管理和加载你的环境变量。

o1-preview

o1-preview-2024-09-12, 20250105


要在 Cloudflare 的 Wrangler 项目中使用 .dev.vars 文件中的变量,您可以按照以下步骤操作:

  1. 创建 .dev.vars 文件:

    在您项目的根目录下创建一个名为 .dev.vars 的文件,用于存储开发环境的变量。文件内容应采用 KEY=VALUE 的格式,每行一个变量。例如:

    1
    2
    API_KEY=abc123
    SECRET_TOKEN=def456
  2. 在代码中访问变量:

    在您的 Worker 代码中,您可以通过 env 对象访问这些变量。env 参数通常在 fetch 事件处理程序或模块导出的对象中提供。

    1
    2
    3
    4
    5
    6
    7
    export default {
    async fetch(request, env) {
    const apiKey = env.API_KEY;
    const secretToken = env.SECRET_TOKEN;
    // 使用变量执行您的逻辑
    }
    }
  3. 运行 wrangler dev

    当您运行 wrangler dev 命令时,Wrangler 会自动加载 .dev.vars 文件中的变量,并在本地开发环境中提供给您的 Worker。这些变量不会在生产环境中使用,适用于本地开发和调试。

    1
    wrangler dev

注意:

  • 您不需要在 wrangler.toml 文件中引用或包含 .dev.vars 文件。Wrangler 会自动处理它。
  • .dev.vars 文件通常不应该提交到版本控制系统(如 Git)。建议将其添加到 .gitignore 文件中,以防止敏感信息泄露。
  • 如果您需要在生产环境使用变量,应在 wrangler.toml 文件中使用 vars 字段或设置环境变量。

示例 wrangler.toml

1
2
3
4
5
name = "your-worker-name"
compatibility_date = "2023-10-20"
# 生产环境的变量可以在这里定义
# [vars]
# PRODUCTION_VAR = "value"

通过以上步骤,您就可以在 Cloudflare Workers 的本地开发环境中使用 .dev.vars 文件中的变量,而无需在 wrangler.toml 中进行额外配置。

Claude 3.5 Sonnet

claude-3-5-sonnet-20241022, 20250101


在 Cloudflare Workers 的 wrangler.toml 中使用 .dev.vars 变量的方法如下:

  1. 首先创建 .dev.vars 文件:
1
2
3
# .dev.vars
API_KEY=your_api_key_here
DATABASE_URL=your_database_url
  1. 在 wrangler.toml 中引用这些变量:
1
2
3
4
5
6
7
8
9
name = "your-worker-name"
main = "src/index.ts"
compatibility_date = "2023-01-01"

[vars]
# 这些是生产环境变量

[dev]
# 开发环境将自动从 .dev.vars 加载变量
  1. 在代码中访问变量:
1
2
3
4
5
6
7
export default {
async fetch(request: Request, env: Env) {
// 访问环境变量
const apiKey = env.API_KEY;
const dbUrl = env.DATABASE_URL;
}
}

重要说明:

  • .dev.vars 文件应该添加到 .gitignore 中,不要提交到版本控制
  • .dev.vars 中的变量只在本地开发时生效
  • 使用 wrangler dev 命令时会自动加载 .dev.vars 中的变量
  • 生产环境的变量需要通过 Cloudflare Dashboard 或 wrangler secret 命令设置

设置生产环境变量的命令:

1
2
wrangler secret put API_KEY
wrangler secret put DATABASE_URL

TypeScript 类型定义:

1
2
3
4
interface Env {
API_KEY: string;
DATABASE_URL: string;
}

这样可以在开发环境中使用 .dev.vars 的变量,同时在生产环境中使用正式的环境变量。

DeepSeek-V3

网页版,20250101


在 Cloudflare Workers 中,wrangler.toml 是配置文件,而 .dev.vars 文件用于存储环境变量,尤其是在开发环境中。要在 wrangler.toml 中使用 .dev.vars 中的变量,可以按照以下步骤操作:


1. 创建 .dev.vars 文件

在项目根目录下创建 .dev.vars 文件,并定义你的环境变量。例如:

1
2
API_KEY=your_api_key_here
SECRET_VALUE=your_secret_value_here

2. 在 wrangler.toml 中引用变量

wrangler.toml 中,可以通过 env 配置块来引用 .dev.vars 中的变量。例如:

1
2
3
4
5
6
name = "my-worker"
main = "src/index.js"
compatibility_date = "2023-10-01"

[env.dev]
vars = { API_KEY = "${API_KEY}", SECRET_VALUE = "${SECRET_VALUE}" }

3. 在 Worker 代码中使用变量

在你的 Worker 代码中,可以通过 env 对象访问这些变量。例如:

1
2
3
4
5
6
7
8
export default {
async fetch(request, env) {
const apiKey = env.API_KEY;
const secretValue = env.SECRET_VALUE;

return new Response(`API Key: ${apiKey}, Secret Value: ${secretValue}`);
},
};

4. 运行 Worker

使用 wrangler dev 启动开发服务器,.dev.vars 中的变量会自动注入到环境中:

1
wrangler dev

注意事项

  • .dev.vars 文件通常用于开发环境,不要将其提交到版本控制(例如 Git),以避免泄露敏感信息。可以将 .dev.vars 添加到 .gitignore 文件中。
  • 对于生产环境,建议使用 wrangler secret put 命令将变量存储为加密的 secret。

通过以上步骤,你可以在 wrangler.toml 中成功使用 .dev.vars 中的变量。

DeepSeek-V3

网页版深度思考,20250101


在 Cloudflare Workers 中,你可以通过 wrangler.toml 文件配置你的项目,并且可以在其中使用环境变量。.dev.vars 文件用于存储开发环境的变量,这些变量在开发模式下会被自动加载。

要在一个 wrangler.toml 文件中使用 .dev.vars 中定义的变量,你可以按照以下步骤进行操作:

  1. 创建或编辑 .dev.vars 文件

    在你的项目根目录下创建一个 .dev.vars 文件,并添加你的环境变量。例如:

    1
    2
    API_KEY=your_api_key
    API_SECRET=your_api_secret
  2. wrangler.toml 中引用这些变量

    你可以在 wrangler.toml 文件中使用 ${VARIABLE_NAME} 语法来引用这些变量。例如:

    1
    2
    3
    [vars]
    api_key = "${API_KEY}"
    api_secret = "${API_SECRET}"
  3. 在代码中使用这些变量

    你可以在你的 Worker 代码中通过 env 对象访问这些变量:

    1
    2
    3
    4
    5
    6
    7
    export default {
    async fetch(request, env) {
    let apiKey = env.api_key;
    let apiSecret = env.api_secret;
    // 使用这些变量进行操作
    }
    };
  4. 运行开发服务器

    使用 wrangler 开发服务器时,它会自动加载 .dev.vars 文件中的变量:

    1
    wrangler dev

    这样,你在 wrangler.toml 中引用的变量就会被正确替换。

注意事项

  • 变量作用域:确保 .dev.vars 文件中的变量在开发模式下被正确加载。.dev.vars 文件中的变量仅在开发模式下(即使用 wrangler dev 命令时)生效。

  • 生产环境配置:在生产环境中,你应该通过 Cloudflare Dashboard 或 wrangler secrets 命令来设置变量,而不是使用 .dev.vars 文件。

  • 变量覆盖:如果你在 wrangler.toml 中定义了相同的变量,它们可能会覆盖 .dev.vars 中的值,具体取决于变量的加载顺序和配置。

参考文档

通过以上步骤,你可以在 wrangler.toml 文件中成功使用 .dev.vars 中定义的变量。

答案评价

这其实是一个描述不是很清楚的问题,真实的意图是,有一些 secrets,比如云服务的 API_KEY,如果想在本地开发使用这些环境变量,同时它们不能上传到 GitHub,在 .dev.varswrangler.toml 中如何定义,在代码中如何使用

从文字描述来说,o1-preview 是做得最好的,其他的差不多

这里 o1-preview > GPT-4o ≈ Claude 3.5 Sonnet ≈ DeepSeek-V3

创建 .dev.vars 文件和里面内容的格式,gpt-4o 是最好的,严格按照官网文档描述,其他的差不多

这里 GPT-4o > o1-preview ≈ Claude 3.5 Sonnet ≈ DeepSeek-V3

关于 wrangler.toml 文件,o1-preview 是说得最好的,因为在本地使用 .dev.vars 文件里的变量,确实不需要 wrangler.toml 的参与

GPT-4o 错误的描述了使用条件,.dev.vars 文件无需任何设置,就会覆盖 wrangler.toml 中的变量

Claude 3.5 Sonnet 简单进行了说明,有点画蛇添足,但是没有错误

DeepSeek-V3 同样错误描述了使用条件,并且生成了一个 wrangler.toml 不支持的引用语法

这里 o1-preview > Claude 3.5 Sonnet > GPT-4o ≈ DeepSeek-V3

关于使用这些变量,模型都片面地在标准地 cloudflare workers 中使用,没有考虑不在 workers 中用 process.env 使用的情况,或者使用 getRequestContext 这种更推荐的方式,做得都不够好

这里 o1-preview ≈ Claude 3.5 Sonnet ≈ GPT-4o ≈ DeepSeek-V3

综合来看,o1-preview > Claude 3.5 Sonnet > GPT-4o ≈ DeepSeek-V3

问题二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
下面是shadcn/ui中的calendar组件,如何在切换月份的按钮之外再增加两个切换年份的按钮

"use client"

import * as React from "react"
import { ChevronLeft, ChevronRight } from "lucide-react"
import { DayPicker } from "react-day-picker"

import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"

export type CalendarProps = React.ComponentProps<typeof DayPicker>

function Calendar({
className,
classNames,
showOutsideDays = true,
...props
}: CalendarProps) {
return (
<DayPicker
showOutsideDays={showOutsideDays}
className={cn("p-3", className)}
classNames={{
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
month: "space-y-4",
caption: "flex justify-center pt-1 relative items-center",
caption_label: "text-sm font-medium",
nav: "space-x-1 flex items-center",
nav_button: cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
),
nav_button_previous: "absolute left-1",
nav_button_next: "absolute right-1",
table: "w-full border-collapse space-y-1",
head_row: "flex",
head_cell:
"text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
row: "flex w-full mt-2",
cell: cn(
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md",
props.mode === "range"
? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
: "[&:has([aria-selected])]:rounded-md"
),
day: cn(
buttonVariants({ variant: "ghost" }),
"h-8 w-8 p-0 font-normal aria-selected:opacity-100"
),
day_range_start: "day-range-start",
day_range_end: "day-range-end",
day_selected:
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
day_today: "bg-accent text-accent-foreground",
day_outside:
"day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground",
day_disabled: "text-muted-foreground opacity-50",
day_range_middle:
"aria-selected:bg-accent aria-selected:text-accent-foreground",
day_hidden: "invisible",
...classNames,
}}
components={{
IconLeft: ({ className, ...props }) => (
<ChevronLeft className={cn("h-4 w-4", className)} {...props} />
),
IconRight: ({ className, ...props }) => (
<ChevronRight className={cn("h-4 w-4", className)} {...props} />
),
}}
{...props}
/>
)
}
Calendar.displayName = "Calendar"

export { Calendar }

GPT-4o

poe GPT-4o, 20250106

第一次的回答无法渲染,直接报错

第二次的回答直接把需要的功能所在的区域干没了

把报错返回给它后,第三次输出可用的答案如下


问题的原因是 react-day-pickerCaption 组件的 Props 类型已经发生变化。在 react-day-picker 的新版本(v8+)中,Caption 组件的 props 不再直接包含 dateclassName,而是通过其他方式传递数据。我们需要调整代码以适配新的 react-day-picker API。

以下是修复后的代码:


修复后的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
"use client"

import * as React from "react"
import { ChevronLeft, ChevronRight } from "lucide-react"
import { DayPicker } from "react-day-picker"

import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"

export type CalendarProps = React.ComponentProps<typeof DayPicker>

function Calendar({
className,
classNames,
showOutsideDays = true,
...props
}: CalendarProps) {
const [month, setMonth] = React.useState(new Date())

const handlePreviousYear = () => {
setMonth((prev) => {
const newDate = new Date(prev)
newDate.setFullYear(newDate.getFullYear() - 1)
return newDate
})
}

const handleNextYear = () => {
setMonth((prev) => {
const newDate = new Date(prev)
newDate.setFullYear(newDate.getFullYear() + 1)
return newDate
})
}

const handlePreviousMonth = () => {
setMonth((prev) => {
const newDate = new Date(prev)
newDate.setMonth(newDate.getMonth() - 1)
return newDate
})
}

const handleNextMonth = () => {
setMonth((prev) => {
const newDate = new Date(prev)
newDate.setMonth(newDate.getMonth() + 1)
return newDate
})
}

return (
<DayPicker
month={month}
onMonthChange={setMonth}
showOutsideDays={showOutsideDays}
className={cn("p-3", className)}
classNames={{
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
month: "space-y-4",
caption: "flex justify-center pt-1 relative items-center",
caption_label: "text-sm font-medium",
nav: "space-x-1 flex items-center",
nav_button: cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
),
nav_button_previous: "absolute left-1",
nav_button_next: "absolute right-1",
table: "w-full border-collapse space-y-1",
head_row: "flex",
head_cell:
"text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
row: "flex w-full mt-2",
cell: cn(
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md",
props.mode === "range"
? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
: "[&:has([aria-selected])]:rounded-md"
),
day: cn(
buttonVariants({ variant: "ghost" }),
"h-8 w-8 p-0 font-normal aria-selected:opacity-100"
),
day_range_start: "day-range-start",
day_range_end: "day-range-end",
day_selected:
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
day_today: "bg-accent text-accent-foreground",
day_outside:
"day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground",
day_disabled: "text-muted-foreground opacity-50",
day_range_middle:
"aria-selected:bg-accent aria-selected:text-accent-foreground",
day_hidden: "invisible",
...classNames,
}}
components={{
Caption: ({ displayMonth }) => (
<div className="flex items-center justify-between">
<button
type="button"
onClick={handlePreviousYear}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
)}
>
{"<<"}
</button>
<button
type="button"
onClick={handlePreviousMonth}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
)}
>
<ChevronLeft className="h-4 w-4" />
</button>
<span className="text-sm font-medium">
{displayMonth.toLocaleString("default", {
month: "long",
year: "numeric",
})}
</span>
<button
type="button"
onClick={handleNextMonth}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
)}
>
<ChevronRight className="h-4 w-4" />
</button>
<button
type="button"
onClick={handleNextYear}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
)}
>
{">>"}
</button>
</div>
),
}}
{...props}
/>
)
}
Calendar.displayName = "Calendar"

export { Calendar }

修复内容

  1. CaptionProps 类型

    • react-day-picker 的新版本中,Caption 组件的 props 不再直接传递 dateclassName
    • 新的 props 中包含了 displayMonth,表示当前显示的月份。
  2. 替换 datedisplayMonth

    • Caption 组件中的 date 替换为 displayMonth
    • 使用 displayMonth.toLocaleString 来显示当前的月份和年份。
  3. 移除 className

    • 如果需要额外的样式,可以直接在 div 标签上添加 className

关键点

  • displayMonth

    • react-day-picker 将当前显示的月份传递给 Caption 组件的 displayMonth 属性。
    • 这是一个 Date 对象,表示当前的月份。
  • 按钮逻辑

    • 按钮逻辑保持不变,仍然通过 month 状态和 setMonth 方法管理当前视图。

效果

修复后的代码可以正常运行。新增的年份切换按钮(<<>>)可以正常工作,同时月份切换逻辑(左右箭头)也能正常运作。

  • 年份切换:点击 << 切换到上一年,>> 切换到下一年。
  • 月份切换:点击左箭头切换到上个月,右箭头切换到下个月。

o1-preview

o1-preview-2024-09-12, 20250106

由于回答太长就不放上来了,第一次的答案会报错,但是在保持原本组件功能的同时,已经有另外两个按钮的样式出现

把报错提供给它之后,第二次的答案修复了第一次的报错,但是还有报错

再次把报错提供给它之后,第三次提供了基本可用的正常答案:


抱歉给您带来了困扰。您遇到的错误:

1
TypeError: props.onNextMonthClick is not a function

这是因为在 CaptionProps 中并没有 onNextMonthClickonPrevMonthClick 这两个属性。

要解决这个问题,我们需要修改自定义的 CustomCaption 组件,使用 useNavigation 提供的导航函数来处理月份的切换。

以下是详细的解决方案:


1. 使用 useNavigation 来导航月份

首先,从 react-day-picker 导入 useNavigation

1
import { useNavigation } from "react-day-picker"

然后,在 CustomCaption 组件中,使用 useNavigation 获取 goToMonth 函数。

2. 更新 CustomCaption 组件

完整的更新后的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { format } from "date-fns"
import { CaptionProps, useNavigation } from "react-day-picker"
import { ChevronLeft, ChevronRight } from "lucide-react"

// 假设您已经定义了 cn 和 buttonVariants 函数,根据您的实际情况调整

function CustomCaption(props: CaptionProps) {
const { displayMonth, locale } = props
const { goToMonth } = useNavigation()

// 处理前一个月
const handlePrevMonth = () => {
const prevMonth = new Date(displayMonth)
prevMonth.setMonth(prevMonth.getMonth() - 1)
goToMonth(prevMonth)
}

// 处理后一个月
const handleNextMonth = () => {
const nextMonth = new Date(displayMonth)
nextMonth.setMonth(nextMonth.getMonth() + 1)
goToMonth(nextMonth)
}

// 处理前一年
const handlePrevYear = () => {
const prevYear = new Date(displayMonth)
prevYear.setFullYear(prevYear.getFullYear() - 1)
goToMonth(prevYear)
}

// 处理后一年
const handleNextYear = () => {
const nextYear = new Date(displayMonth)
nextYear.setFullYear(nextYear.getFullYear() + 1)
goToMonth(nextYear)
}

return (
<div className="flex items-center justify-between pt-1">
<div className="flex items-center">
{/* 前一年按钮 */}
<button
type="button"
onClick={handlePrevYear}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 mr-2"
)}
>
{"<<"}
</button>
{/* 前一个月按钮 */}
<button
type="button"
onClick={handlePrevMonth}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
)}
>
<ChevronLeft className="h-4 w-4" />
</button>
</div>
{/* 显示当前月份和年份 */}
<div className="text-sm font-medium">
{format(displayMonth, "LLLL yyyy", { locale })}
</div>
<div className="flex items-center">
{/* 下一个月按钮 */}
<button
type="button"
onClick={handleNextMonth}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
)}
>
<ChevronRight className="h-4 w-4" />
</button>
{/* 下一年按钮 */}
<button
type="button"
onClick={handleNextYear}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 ml-2"
)}
>
{">>"}
</button>
</div>
</div>
)
}

3. 解释

  • 问题原因CaptionProps 并不包含 onNextMonthClickonPrevMonthClick 方法,所以直接调用 props.onNextMonthClick 会导致报错。

  • 解决方案:使用 useNavigation 提供的 goToMonth 函数来导航月份。同样地,我们可以定义 handlePrevMonthhandleNextMonth 方法,在这些方法中计算上一个月或下一个月的日期,然后调用 goToMonth 进行导航。

  • 导航年份handlePrevYearhandleNextYear 方法与之前一致,使用 goToMonth 来导航年份。

4. 不需要修改 Calendar 组件

因为您只需要修改 CustomCaption 组件即可,Calendar 组件不需要进一步修改。


完整示例

以下是完整的代码,包括 CustomCaptionCalendar 组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { DayPicker, DateRange, useNavigation } from "react-day-picker"
import { format } from "date-fns"
import { ChevronLeft, ChevronRight } from "lucide-react"

// 假设您已经定义了 cn 和 buttonVariants 函数,根据您的实际情况调整

// 自定义的 Caption 组件
function CustomCaption(props: CaptionProps) {
const { displayMonth, locale } = props
const { goToMonth } = useNavigation()

const handlePrevMonth = () => {
const prevMonth = new Date(displayMonth)
prevMonth.setMonth(prevMonth.getMonth() - 1)
goToMonth(prevMonth)
}

const handleNextMonth = () => {
const nextMonth = new Date(displayMonth)
nextMonth.setMonth(nextMonth.getMonth() + 1)
goToMonth(nextMonth)
}

const handlePrevYear = () => {
const prevYear = new Date(displayMonth)
prevYear.setFullYear(prevYear.getFullYear() - 1)
goToMonth(prevYear)
}

const handleNextYear = () => {
const nextYear = new Date(displayMonth)
nextYear.setFullYear(nextYear.getFullYear() + 1)
goToMonth(nextYear)
}

return (
<div className="flex items-center justify-between pt-1">
<div className="flex items-center">
{/* 前一年按钮 */}
<button
type="button"
onClick={handlePrevYear}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 mr-2"
)}
>
{"<<"}
</button>
{/* 前一个月按钮 */}
<button
type="button"
onClick={handlePrevMonth}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
)}
>
<ChevronLeft className="h-4 w-4" />
</button>
</div>
{/* 显示当前月份和年份 */}
<div className="text-sm font-medium">
{format(displayMonth, "LLLL yyyy", { locale })}
</div>
<div className="flex items-center">
{/* 下一个月按钮 */}
<button
type="button"
onClick={handleNextMonth}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
)}
>
<ChevronRight className="h-4 w-4" />
</button>
{/* 下一年按钮 */}
<button
type="button"
onClick={handleNextYear}
className={cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 ml-2"
)}
>
{">>"}
</button>
</div>
</div>
)
}

// Calendar 组件
function Calendar({
className,
classNames,
showOutsideDays = true,
...props
}: CalendarProps) {
return (
<DayPicker
showOutsideDays={showOutsideDays}
className={cn("p-3", className)}
classNames={{
// 您现有的 classNames 配置
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
month: "space-y

Claude 3.5 Sonnet

claude-3-5-sonnet-20241022, 20250106

第一次的回答会有报错,不仅没有实现需要的功能,而且破坏了原本的样式

将报错提供给它后,第二次的回答呈现出需要的功能,但是会有报错

再次提供报错后,第三次的回答又回到了类似第一次的样子,没有需要的功能,而且破坏了原本的样式

节约空间,回答不再呈现

DeepSeek-V3

网页版,20250106

第一次回答把原本 caption 中的其他内容都搞没了,点击按钮还会报错

提供现象和报错信息后,第二次的回答直接无法渲染

再次提供现象和报错信息后,第三次的回答直接无法渲染

DeepSeek-V3

网页版深度思考,20250106

第一次答案直接变成英文的了,可能是 CoT 用的是英文,影响了最后的输出,回答没有产生任何改变,样式和功能上都没有

第二次的答案无法编译,虚构了一个库中不存在的函数

第三次还是一样

答案评价

综合来看,o1-preview > GPT-4o >> Claude 3.5 Sonnet > DeepSeek-V3 > DeepSeek-V3 深度思考

o1-preview 和 GPT-4o 是唯二完成了问题的模型,以往在代码上表现一直很出色的 Claude 3.5 Sonnet 反而没有,这还是挺意外的

问题三

1
用鼠标中间点击一个链接,实际上是什么,会触发click事件吗?

GPT-4o

gpt-4o-poe, 20250114


用鼠标中键点击一个链接时,浏览器的行为和是否触发 click 事件取决于具体的情况。以下是详细的解答:


1. 鼠标中键点击的默认行为

  • 在浏览器中:

    • 鼠标中键点击链接时,链接通常会在 新标签页中打开(如果是超链接 <a> 元素并且设置了 href 属性)。
    • 这种行为是浏览器的原生功能,属于默认行为,与 JavaScript 的事件无关。
  • 鼠标中键的常规作用:

    • 鼠标中键点击通常也会触发滚动功能(比如在空白区域中点击,启动滚动模式)。

2. 是否会触发 click 事件?

鼠标中键点击链接时,是否触发 click 事件,取决于以下因素:

标准行为

  • 根据 W3C 的规范,鼠标点击事件分为三种鼠标按钮:

    • 左键:button === 0
    • 中键:button === 1
    • 右键:button === 2
  • 当你用鼠标中键点击链接时:

    • 不会触发 click 事件,因为 click 事件通常与鼠标左键(button === 0)相关联。
    • 中键点击时会触发 mousedownmouseup 事件,但浏览器不会触发 click

事件监听的行为

如果你显式监听了其他鼠标事件,比如 mousedownmouseup 或者用 addEventListener 捕获所有鼠标事件,你可以检测鼠标中键的点击:

1
2
3
4
5
document.addEventListener('mousedown', (event) => {
if (event.button === 1) {
console.log('鼠标中键点击了!');
}
});

用户阻止默认行为

如果你阻止了链接的默认行为,鼠标中键点击可能会被视为普通事件。例如:

1
2
3
4
5
// 阻止默认行为
document.querySelector('a').addEventListener('click', (event) => {
event.preventDefault(); // 阻止新标签页打开
console.log('链接被点击了');
});

即使鼠标中键点击了链接,preventDefault 会阻止默认行为(新标签页打开),但仍然不会触发 click 事件。


3. 总结

  • 鼠标中键点击链接时的默认行为:

    • 在新标签页中打开链接(浏览器默认)。
    • 不会触发 click 事件。
  • 可触发的事件:

    • 中键点击会触发 mousedownmouseup 事件。
  • 如何检测中键点击?

    • 通过检查事件对象中的 event.button === 1
  • 如何阻止默认行为?

    • 使用 event.preventDefault() 可以阻止鼠标中键点击链接在新标签页中打开。

补充代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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>
<a href="https://example.com" target="_blank">点击我</a>

<script>
const link = document.querySelector('a');

// 检测中键点击
link.addEventListener('mousedown', (event) => {
if (event.button === 1) {
console.log('鼠标中键点击了链接');
}
});

// 阻止默认行为
link.addEventListener('click', (event) => {
event.preventDefault();
console.log('链接点击事件触发,但阻止了默认行为');
});
</script>
</body>
</html>

o1-preview

o1-preview-2024-09-12, 20250114


当你用鼠标中键点击一个链接时,浏览器通常会在新标签页中打开该链接,这是浏览器对鼠标中键点击的默认行为。

从JavaScript的角度来看,鼠标中键点击并不会触发元素的click事件click事件通常仅由鼠标左键点击触发。

然而,鼠标中键点击时会触发其他事件:

  1. mousedownmouseup事件:鼠标任何按钮的按下和释放都会触发这两个事件。你可以通过事件对象的button属性来判断是哪个鼠标按钮:

    • event.button === 0:左键
    • event.button === 1:中键
    • event.button === 2:右键
  2. auxclick事件:这是专门为处理非左键点击(如中键、右键)而设计的事件。鼠标中键点击会触发auxclick事件,你可以监听这个事件来捕获中键点击。

示例:

1
2
3
4
5
6
7
8
9
10
11
document.addEventListener('mousedown', function(event) {
if (event.button === 1) {
console.log('鼠标中键按下');
}
});

document.addEventListener('auxclick', function(event) {
if (event.button === 1) {
console.log('鼠标中键点击');
}
});

注意事项:

  • 默认行为:中键点击链接的默认行为是打开新标签页。如果你想阻止这个默认行为,可以在事件处理函数中调用event.preventDefault()

    1
    2
    3
    4
    5
    6
    document.addEventListener('auxclick', function(event) {
    if (event.button === 1) {
    event.preventDefault(); // 阻止打开新标签页
    console.log('中键点击被捕获,默认行为已阻止');
    }
    });
  • 兼容性:并非所有浏览器都支持auxclick事件。为确保兼容性,最好同时监听mousedownmouseup事件,并结合event.button进行判断。

总结:鼠标中键点击不会触发click事件,但会触发mousedownmouseupauxclick等事件。因此,如果你需要在中键点击时执行特定逻辑,建议监听auxclick事件,并根据需要阻止默认行为。

Claude 3.5 Sonnet

claude-3-5-sonnet-20241022, 20250114


鼠标中键(滚轮按下)点击链接的行为:

  1. 默认行为:
  • 在新标签页打开链接
  • 不会切换到新打开的标签页(保持在当前页面)
  1. 事件触发:
  • 不会触发标准的 click 事件
  • 会触发 mouseup 和 mousedown 事件
  • 具体触发 auxclick 事件(auxiliary button click)

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
link.addEventListener('click', (e) => {
console.log('click'); // 中键点击不会触发
});

link.addEventListener('auxclick', (e) => {
console.log('auxclick'); // 中键点击会触发
if (e.button === 1) { // button值为1表示中键
// 处理中键点击
}
});

link.addEventListener('mouseup', (e) => {
console.log('mouseup'); // 中键点击会触发
});
  1. 阻止默认行为:
1
2
3
4
5
6
7
8
9
10
11
12
link.addEventListener('auxclick', (e) => {
if (e.button === 1) {
e.preventDefault(); // 阻止在新标签页打开
}
});

// 或者
link.addEventListener('mousedown', (e) => {
if (e.button === 1) {
e.preventDefault();
}
});
  1. 鼠标按键对应的button值:
  • 左键:0
  • 中键:1
  • 右键:2

注意:

  • 中键点击的这个默认行为是浏览器级别的,不是JavaScript标准事件模型的一部分
  • 不同浏览器可能有细微的实现差异
  • 如果要处理中键点击,建议使用 auxclick 事件而不是 click 事件

DeepSeek-V3

网页版,20250114


用鼠标中键点击链接时,通常会在新标签页中打开链接,但不会触发标准的 click 事件。

具体行为如下:

  1. 新标签页打开:浏览器默认会在新标签页中打开链接。
  2. click 事件:不会触发标准的 click 事件。click 事件通常由左键点击触发。
  3. auxclick 事件:会触发 auxclick 事件,专门用于处理非左键点击(如中键或右键)。

示例代码

1
2
3
4
5
document.addEventListener('auxclick', function(event) {
if (event.button === 1) { // 1 表示中键
console.log('中键点击');
}
});

总结

  • 中键点击:不会触发 click 事件,但会触发 auxclick 事件。
  • 默认行为:在新标签页中打开链接。

如果你需要处理中键点击,应监听 auxclick 事件。

DeepSeek-V3

网页版深度思考,20250114


使用鼠标中间键(通常是滚轮点击)点击一个链接时,具体行为取决于浏览器的设置和操作系统的配置。在大多数情况下,中键点击一个链接会在新的标签页或窗口中打开该链接,但并不一定会触发JavaScript的click事件。

浏览器行为

  • Firefox: 中键点击通常会新开一个标签页并加载链接,但可能不会触发click事件。
  • Chrome: 中键点击可能会在新的标签页中打开链接,但行为可能因系统设置而异。
  • 其他浏览器: 行为可能有所不同,但通常与上述类似。

是否触发click事件

  • 在某些浏览器中,中键点击可能不会触发click事件。
  • 在其他浏览器中,可能会触发click事件,但具体情况因浏览器而异。

如何检测

你可以通过编写一个简单的HTML页面来测试:

1
2
3
4
5
6
7
8
<a href="https://www.example.com" id="testLink">测试链接</a>

<script>
document.getElementById('testLink').addEventListener('click', function(event) {
alert('click事件被触发了!');
event.preventDefault(); // 阻止默认行为
});
</script>

然后用中键点击链接,看看是否弹出提示框。

鼠标事件的button属性

在JavaScript中,MouseEvent.button 属性可以用来判断是哪个鼠标按钮被点击:

  • 0: 左键
  • 1: 中键(滚轮)
  • 2: 右键

你可以通过以下代码来检测是哪个按钮被点击:

1
2
3
4
document.getElementById('testLink').addEventListener('click', function(event) {
console.log('按钮:', event.button);
// 其他代码
});

总结

  • 中键点击链接通常会在新的标签页或窗口中打开链接。
  • 是否触发click事件取决于浏览器的实现。
  • 可以通过检测event.button的值来确定是哪个鼠标按钮被点击。

答案评价

少见的 deepseek 表现很好的问题,还是挺惊喜的

o1-preview > DeepSeek-V3 > Claude 3.5 Sonnet ≈ GPT-4o > DeepSeek-V3 深度思考