初始提交:一场soul的创业实验-永平 网站与小程序

Made-with: Cursor
This commit is contained in:
卡若
2026-03-07 22:58:43 +08:00
commit b7c35a89b0
513 changed files with 89020 additions and 0 deletions

View File

@@ -0,0 +1,175 @@
# Icon 图标组件
SVG 图标组件,参考 lucide-react 实现,用于在小程序中使用矢量图标。
**技术实现**: 使用 Base64 编码的 SVG + image 组件(小程序不支持直接使用 SVG 标签)
---
## 使用方法
### 1. 在页面 JSON 中引入组件
```json
{
"usingComponents": {
"icon": "/components/icon/icon"
}
}
```
### 2. 在 WXML 中使用
```xml
<!-- 基础用法 -->
<icon name="share" size="48" color="#00CED1"></icon>
<!-- 分享图标 -->
<icon name="share" size="40" color="#ffffff"></icon>
<!-- 箭头图标 -->
<icon name="arrow-up-right" size="32" color="#00CED1"></icon>
<!-- 搜索图标 -->
<icon name="search" size="44" color="#ffffff"></icon>
<!-- 返回图标 -->
<icon name="chevron-left" size="48" color="#ffffff"></icon>
<!-- 心形图标 -->
<icon name="heart" size="40" color="#E91E63"></icon>
```
---
## 属性说明
| 属性 | 类型 | 默认值 | 说明 |
|-----|------|--------|-----|
| name | String | 'share' | 图标名称 |
| size | Number | 48 | 图标大小rpx |
| color | String | 'currentColor' | 图标颜色 |
| customClass | String | '' | 自定义类名 |
| customStyle | String | '' | 自定义样式 |
---
## 可用图标
| 图标名称 | 说明 | 对应 lucide-react |
|---------|------|-------------------|
| `share` | 分享 | `<Share2>` |
| `arrow-up-right` | 右上箭头 | `<ArrowUpRight>` |
| `chevron-left` | 左箭头 | `<ChevronLeft>` |
| `search` | 搜索 | `<Search>` |
| `heart` | 心形 | `<Heart>` |
---
## 添加新图标
`icon.js``getSvgPath` 方法中添加新图标:
```javascript
getSvgPath(name) {
const svgMap = {
'new-icon': '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><!-- SVG path 数据 --></svg>',
// ... 其他图标
}
return svgMap[name] || ''
}
```
**获取 SVG 代码**: 访问 [lucide.dev](https://lucide.dev) 搜索图标,复制 SVG 内容。
**注意**: 颜色使用 `COLOR` 占位符,组件会自动替换。
---
## 样式定制
### 1. 使用 customClass
```xml
<icon name="share" size="48" color="#00CED1" customClass="my-icon-class"></icon>
```
```css
.my-icon-class {
opacity: 0.8;
}
```
### 2. 使用 customStyle
```xml
<icon name="share" size="48" color="#ffffff" customStyle="opacity: 0.8; margin-right: 10rpx;"></icon>
```
---
## 技术说明
### 为什么使用 Base64 + image
1. **矢量图标**:任意缩放不失真
2. **灵活着色**:通过 `COLOR` 占位符动态改变颜色
3. **轻量级**:无需加载字体文件或外部图片
4. **兼容性**:小程序不支持直接使用 SVG 标签image 组件支持 Base64 SVG
### 为什么不用字体图标?
小程序对字体文件有限制Base64 编码字体文件会增加包体积SVG 图标更轻量。
### 与 lucide-react 的对应关系
- **lucide-react**: React 组件库,使用 SVG
- **本组件**: 小程序自定义组件,也使用 SVG
- **SVG path 数据**: 完全相同,从 lucide 官网复制
---
## 示例
### 悬浮分享按钮
```xml
<button class="fab-share" open-type="share">
<icon name="share" size="48" color="#ffffff"></icon>
</button>
```
```css
.fab-share {
position: fixed;
right: 32rpx;
bottom: calc(120rpx + env(safe-area-inset-bottom));
width: 96rpx;
height: 96rpx;
border-radius: 50%;
background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
display: flex;
align-items: center;
justify-content: center;
}
```
---
## 扩展图标库
可以继续添加更多 lucide-react 图标:
- `star` - 星星
- `wallet` - 钱包
- `gift` - 礼物
- `info` - 信息
- `settings` - 设置
- `user` - 用户
- `book-open` - 打开的书
- `eye` - 眼睛
- `clock` - 时钟
- `users` - 用户组
---
**图标组件创建完成!** 🎉

View File

@@ -0,0 +1,83 @@
// components/icon/icon.js
Component({
properties: {
// 图标名称
name: {
type: String,
value: 'share',
observer: 'updateIcon'
},
// 图标大小rpx
size: {
type: Number,
value: 48
},
// 图标颜色
color: {
type: String,
value: '#ffffff',
observer: 'updateIcon'
},
// 自定义类名
customClass: {
type: String,
value: ''
},
// 自定义样式
customStyle: {
type: String,
value: ''
}
},
data: {
svgData: ''
},
lifetimes: {
attached() {
this.updateIcon()
}
},
methods: {
// SVG 图标数据映射
getSvgPath(name) {
const svgMap = {
'share': '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg>',
'arrow-up-right': '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="7" y1="17" x2="17" y2="7"/><polyline points="7 7 17 7 17 17"/></svg>',
'chevron-left': '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>',
'search': '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>',
'heart': '<svg viewBox="0 0 24 24" fill="none" stroke="COLOR" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>'
}
return svgMap[name] || ''
},
// 更新图标
updateIcon() {
const { name, color } = this.data
let svgString = this.getSvgPath(name)
if (svgString) {
// 替换颜色占位符
svgString = svgString.replace(/COLOR/g, color)
// 转换为 Base64 Data URL
const svgData = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`
this.setData({
svgData: svgData
})
} else {
this.setData({
svgData: ''
})
}
}
}
})

View File

@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@@ -0,0 +1,5 @@
<!-- components/icon/icon.wxml -->
<view class="icon icon-{{name}} {{customClass}}" style="width: {{size}}rpx; height: {{size}}rpx; {{customStyle}}">
<image wx:if="{{svgData}}" class="icon-image" src="{{svgData}}" mode="aspectFit" style="width: {{size}}rpx; height: {{size}}rpx;" />
<text wx:else class="icon-text">{{name}}</text>
</view>

View File

@@ -0,0 +1,18 @@
/* components/icon/icon.wxss */
.icon {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.icon-image {
display: block;
width: 100%;
height: 100%;
}
.icon-text {
font-size: 24rpx;
color: currentColor;
}