前言
虎年春节快到了,首先祝大家新年快乐,轻松暴富。
最近在网上经常看到生成春联的文章,不过这些小demo要么功能简陋,要么UI特别‘程序员’,满足不了我挑剔的眼光。干脆我自己做一个吧,顺便简单体验一下vite+vue3。(因为页面相对简单,vue组件风格还是使用选项式api,重点还是想把产品快速做出来。)
产品构思
包含手写春节
和生成春联
两大功能:
-
手写春联
- 模拟用笔写字的字迹
- 选择画笔颜色
- 调整画笔大小
- 清空画布
- 撤回笔画
- 切换上、下联、横批、福字
- 随机切换对联提示
- 预览图片和下载
- 贴春联海报和下载
-
生成模式
- 选择画笔颜色
- 挑选生成的对联
- 输入对联
- 随机切换对联
- 贴春联海报和下载
-
其他
- 快速切换模式按钮
- 可控制的背景音乐
- 微信分享网页
设计
开发
- 技术栈
- vite (打包&构建)
- vue3 (页面开发)
- vant(ui)
- sass (css)
- smooth-signature.js (带笔锋手写库)
<template>
<div class="wrap" :class="'mode-' + mode" @touchstart="handleTouchstart">
<!-- 切换模式按钮 -->
<div class="toggle-mode-btn" @click="toggleMode">
{
{
mode === 1 ? '手写' : '生成' }}
<i class="iconfont icon-qiehuan"></i>
</div>
<!-- 工具栏 -->
<div
class="actions"
:style="{ borderTopRightRadius: colorListVisibility ? '0' : '5px' }"
>
<!-- 手写模式显示 -->
<template v-if="mode === 1">
<!-- 调色板 -->
<div class="palette btn-block">
<div
class="cur-color"
@click="togglePalette"
:style="{ background: colorList[curColorIndex] }"
></div>
<ul class="colorList" v-show="colorListVisibility">
<li
v-for="(item, index) in colorList"
:key="item"
:style="{ background: item }"
@click="selectColor(index)"
></li>
</ul>
</div>
<!-- 滑块 -->
<div class="slider-box btn-block">
<van-slider
v-model="progress"
vertical
@change="changeProgress"
bar-height="28"
active-color="transparent"
:min="50"
:max="150"
>
<template #button>
<div class="custom-button"></div>
</template>
</van-slider>
</div>
<!-- 清空 -->
<div class="btn" @click="handleClear">
<i class="iconfont icon-lajitong"></i>
</div>
<!-- 撤销 -->
<div class="btn" @click="handleUndo">
<i class="iconfont icon-fanhui"></i>
</div>
<div class="line"></div>
<!-- 切换画布的按钮 -->
<div
class="btn"
:class="{ 'cur-active': curCanvasIndex === index }"
v-for="(item, index) in canvasList"
:key="item.name"
@click="changeCanvas(index)"
>
{
{
item.name }}
</div>
<div class="line"></div>
<div class="btn prominent" @click="handlePreview">预览</div>
<div class="btn prominent" @click="openPosters">贴联</div>
</template>
<!-- 生成模式显示 -->
<template v-else>
<!-- 选颜色 -->
<div
class="color-list-quick"
:class="{ active: curColorIndex === index }"
v-for="(item, index) in colorList"
:key="item"
:style="{ background: item }"
@click="selectColor(index)"
></div>
<div class="line"></div>
<div class="btn" @click="showPickBox = true">挑选</div>
<div class="btn" @click="showInputBox = true">输入</div>
<!-- 挑选对联弹窗 -->
<van-action-sheet v-model:show="showPickBox" title="请挑选对联">
<ul class="duilian-list">
<li
v-for="(item, index) in duilianList"
:key="index"
@click="handlePickDuilian(item)"
>
<span>{
{
item.shang }}</span
>, <span>{
{
item.xia }}</span
>。
<span>{
{
item.heng }}</span>
</li>
</ul>
</van-action-sheet>
<!-- 输入对联弹窗 -->
<van-action-sheet v-model:show="showInputBox" title="请输入对联">
<van-form @submit="handleSubmitInput">
<van-cell-group inset>
<van-field
v-model="shanglian"
name="shang"
label="上联"
placeholder="上联"
:rules="[
{
required: true,
message: '请输入7位汉字上联',
pattern: /^[\u4e00-\u9fa5]{7}$/
}
]"
clearable
/>
<van-field
v-model="xialian"
name="xia"
label="下联"
placeholder="下联"
:rules="[
{
required: true,
message: '请输入7位汉字下联',
pattern: /^[\u4e00-\u9fa5]{7}$/
}
]"
clearable
/>
<van-field
v-model="hengpi"
name="heng"
label="横批"
placeholder="横批"
:rules="[
{
required