字
字节笔记本
2026年7月20日
用 React 构建一个 Midjourney Prompt 提示词生成器
API中转
¥120
用 React 构建一个 Midjourney Prompt 提示词生成器
Midjourney 的提示词语法有自己的规则,参数多、选项杂。对于刚接触 AI 绘画的人来说,要记住 --v、--niji、--ar、--chaos、--stylize 这些参数的含义和取值范围并不容易。本文介绍如何用 React + shadcn/ui 构建一个可视化的提示词生成器,通过表单选择自动组装规范提示词。
核心功能设计
工具的目标是让用户不需要记任何参数,通过界面操作就能生成规范的 Midjourney 提示词。功能包括:
- 主题描述输入框
- 风格、媒介、光线、画家等分类选项
- 版本和数值参数的滑块/选择
- 开关类参数的切换
- 否定提示词(
--no) - 一键生成、一键复制
状态管理
用一个聚合对象管理所有参数,比多个独立 useState 更清晰:
javascript
const [parameters, setParameters] = useState({
prompt: '',
version: '6.1',
nijiVersion: '6',
aspectRatio: '1:1',
chaos: 0,
stylize: 100,
seed: 0,
quality: 1,
weird: 0,
imageWeight: 25,
negativePrompt: '',
});
const [toggles, setToggles] = useState({
uplight: false,
beta: false,
hd: false,
srefRandom: false,
});
const [selectedOptions, setSelectedOptions] = useState({
medium: '',
lighting: '',
artist: '',
style: '',
});选项数据结构
每个选项用 { value, label } 对象数组定义,方便后续扩展和国际化:
javascript
const artMediums = [
{ value: 'acrylic', label: '丙烯' },
{ value: 'watercolor', label: '水彩' },
{ value: 'oil painting', label: '油画' },
{ value: 'digital art', label: '数字艺术' },
{ value: 'pencil sketch', label: '铅笔素描' },
{ value: 'ink drawing', label: '水墨画' },
{ value: 'photography', label: '摄影' },
{ value: '3d render', label: '3D 渲染' },
];
const lightings = [
{ value: 'golden hour', label: '黄金时刻' },
{ value: 'cinematic lighting', label: '电影光效' },
{ value: 'studio lighting', label: '棚拍光' },
{ value: 'neon lighting', label: '霓虹灯光' },
{ value: 'natural light', label: '自然光' },
{ value: 'dramatic lighting', label: '戏剧光效' },
{ value: 'soft lighting', label: '柔光' },
{ value: 'backlight', label: '逆光' },
];提示词生成逻辑
核心是字符串拼接,只有当参数偏离默认值时才写入提示词:
javascript
function generatePrompt() {
let prompt = parameters.prompt;
// 追加风格相关选项
if (selectedOptions.medium) prompt += `, ${selectedOptions.medium}`;
if (selectedOptions.lighting) prompt += `, ${selectedOptions.lighting}`;
if (selectedOptions.artist) prompt += `, by ${selectedOptions.artist}`;
if (selectedOptions.style) prompt += `, ${selectedOptions.style}`;
// 收集参数
let paramString = '';
// 版本参数(MJ 和 Niji 互斥)
if (parameters.useNiji) {
paramString += ` --niji ${parameters.nijiVersion}`;
} else {
paramString += ` --v ${parameters.version}`;
}
// 宽高比(非默认 1:1 时才添加)
if (parameters.aspectRatio !== '1:1') {
paramString += ` --ar ${parameters.aspectRatio}`;
}
// 数值参数(偏离默认值时添加)
if (parameters.chaos > 0) paramString += ` --chaos ${parameters.chaos}`;
if (parameters.stylize !== 100) paramString += ` --s ${parameters.stylize}`;
if (parameters.quality !== 1) paramString += ` --q ${parameters.quality}`;
if (parameters.weird > 0) paramString += ` --weird ${parameters.weird}`;
if (parameters.seed !== 0) paramString += ` --seed ${parameters.seed}`;
// 图像权重
if (parameters.imageWeight !== 25) {
paramString += ` --iw ${parameters.imageWeight / 100}`;
}
// 开关参数
if (toggles.uplight) paramString += ' --uplight';
if (toggles.beta) paramString += ' --beta';
if (toggles.hd) paramString += ' --hd';
if (toggles.srefRandom) paramString += ' --sref random';
// 否定提示词
if (parameters.negativePrompt) {
paramString += ` --no ${parameters.negativePrompt}`;
}
return (prompt + paramString).trim();
}UI 布局
用 Tabs 将选项分成四个区域,避免页面过长:
基础设置
jsx
<TabsContent value="basic">
<div className="space-y-4">
<div>
<Label>主题描述</Label>
<Textarea
placeholder="描述你想要生成的画面..."
value={parameters.prompt}
onChange={(e) => updateParam('prompt', e.target.value)}
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label>MJ 版本</Label>
<Select value={parameters.version}
onValueChange={(v) => updateParam('version', v)}>
<SelectItem value="6.1">V6.1 (推荐)</SelectItem>
<SelectItem value="6.0">V6.0</SelectItem>
<SelectItem value="5.2">V5.2</SelectItem>
</Select>
</div>
<div>
<Label>Niji 版本</Label>
<Select value={parameters.nijiVersion}
onValueChange={(v) => updateParam('nijiVersion', v)}>
<SelectItem value="6">Niji 6</SelectItem>
<SelectItem value="5">Niji 5</SelectItem>
</Select>
</div>
</div>
<div>
<Label>宽高比</Label>
<div className="grid grid-cols-4 gap-2">
{['1:1', '16:9', '9:16', '4:3'].map(ratio => (
<Button key={ratio}
variant={parameters.aspectRatio === ratio ? 'default' : 'outline'}
onClick={() => updateParam('aspectRatio', ratio)}>
{ratio}
</Button>
))}
</div>
</div>
</div>
</TabsContent>风格与效果
jsx
<TabsContent value="style">
<div className="space-y-4">
<div>
<Label>艺术媒介</Label>
<Select value={selectedOptions.medium}
onValueChange={(v) => updateOption('medium', v)}>
{artMediums.map(item => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</Select>
</div>
<div>
<Label>光线效果</Label>
<Select value={selectedOptions.lighting}
onValueChange={(v) => updateOption('lighting', v)}>
{lightings.map(item => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</Select>
</div>
</div>
</TabsContent>技术参数
数值参数用 Slider 组件:
jsx
<TabsContent value="params">
<div className="space-y-6">
<div>
<Label>Chaos (混乱度): {parameters.chaos}</Label>
<Slider min={0} max={100} step={1}
value={[parameters.chaos]}
onValueChange={([v]) => updateParam('chaos', v)} />
<p className="text-sm text-muted-foreground">
值越高,结果越不可预测。默认 0。
</p>
</div>
<div>
<Label>Stylize (风格化): {parameters.stylize}</Label>
<Slider min={0} max={1000} step={10}
value={[parameters.stylize]}
onValueChange={([v]) => updateParam('stylize', v)} />
<p className="text-sm text-muted-foreground">
低值更贴近提示词,高值更偏 Midjourney 自己的美学。默认 100。
</p>
</div>
<div>
<Label>Weird (奇特度): {parameters.weird}</Label>
<Slider min={0} max={3000} step={10}
value={[parameters.weird]}
onValueChange={([v]) => updateParam('weird', v)} />
<p className="text-sm text-muted-foreground">
V5.2+ 可用,值越高越出格。默认 0。
</p>
</div>
</div>
</TabsContent>结果区域
jsx
<Card className="mt-6">
<CardHeader>
<CardTitle>生成结果</CardTitle>
</CardHeader>
<CardContent>
<div className="bg-muted p-4 rounded-lg font-mono text-sm break-all">
{generatedPrompt || '请填写主题描述'}
</div>
<div className="flex gap-2 mt-4">
<Button onClick={() => setGeneratedPrompt(generatePrompt())}>
生成提示词
</Button>
<Button variant="outline" onClick={handleCopy}>
复制到剪贴板
</Button>
</div>
</CardContent>
</Card>复制功能
javascript
async function handleCopy() {
try {
await navigator.clipboard.writeText(generatedPrompt);
// 可以加一个短暂的反馈提示
} catch {
// fallback: textarea + execCommand
const textarea = document.createElement('textarea');
textarea.value = generatedPrompt;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}
}Midjourney 常用参数速查
| 参数 | 说明 | 默认值 | 范围 |
|---|---|---|---|
--v | MJ 版本 | 6.1 | 5.2 / 6.0 / 6.1 |
--niji | Niji 二次元版本 | 6 | 5 / 6 |
--ar | 宽高比 | 1:1 | 任意比例 |
--chaos | 混乱度 | 0 | 0-100 |
--stylize | 风格化程度 | 100 | 0-1000 |
--weird | 奇特度 | 0 | 0-3000 |
--seed | 随机种子 | 随机 | 0-4294967295 |
--iw | 图像权重 | 0.25 | 0-2 |
--q | 质量 | 1 | 0.25 / 0.5 / 1 / 2 |
--no | 否定提示词 | 无 | 文本 |
--uplight | Upscale Light 模式 | off | 开关 |
--sref random | V6.1 风格随机化 | off | 开关 |
注意 --v 和 --niji 是互斥的,不能同时使用。
扩展思路
- 把选项数据抽成独立的 JSON 文件,方便维护和更新
- 加入提示词历史记录,用
localStorage持久化 - 支持从已有提示词反向解析到表单
- 预设一些常用的风格组合(如"赛博朋克"、"吉卜力风格"等),一键填入
- 加一个随机组合按钮,帮助探索新风格
分享: