初始提交:一场soul的创业实验-永平 网站与小程序
Made-with: Cursor
This commit is contained in:
175
miniprogram/components/icon/README.md
Normal file
175
miniprogram/components/icon/README.md
Normal 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` - 用户组
|
||||
|
||||
---
|
||||
|
||||
**图标组件创建完成!** 🎉
|
||||
83
miniprogram/components/icon/icon.js
Normal file
83
miniprogram/components/icon/icon.js
Normal 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: ''
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
4
miniprogram/components/icon/icon.json
Normal file
4
miniprogram/components/icon/icon.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
5
miniprogram/components/icon/icon.wxml
Normal file
5
miniprogram/components/icon/icon.wxml
Normal 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>
|
||||
18
miniprogram/components/icon/icon.wxss
Normal file
18
miniprogram/components/icon/icon.wxss
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user