这篇笔记主要记录uni-icons通过fontFamily自定义图标, 使用的自定义图标来自iconfont, 涉及到的知识点: HTML 实体 vs Unicode 字符,微信小程序v-html会被转为 rich-text
用法
- 选择自定义图标,下载自定义图标文件(这里我选择的是iconfont图标)
- 项目引入图标文件,页面使用
1.选择自定义图标,下载自定义图标文件
这里我以iconfont为例,选择了几个图标,然后点击下载本地
2.项目引入图标文件,页面使用
- 项目加载字体文件,放到
static/fonts文件夹 - App.vue引入字体文件
- 页面使用
项目加载字体文件
App.vue引入字体文件
<style lang="scss">
@import '@/static/fonts/iconfont.css'
</style>
页面使用, 注意这里fontFamily,如果没设置过默认就是iconfont, 然后那个unicode码来自于iconfont网站,我们复制下就行
<uni-icons size="18" color="#111" fontFamily="iconfont">

</uni-icons>
HTML 实体 vs Unicode 字符, 为什么要用"\ue8b2"这种形式
先看一个问题,最后一个图标无法正常显示
<script>
const icon = "\ue8b2";
const icon1 = "";
</script>
<template>
<uni-icons size="18" color="#11f011" fontFamily="iconfont">

</uni-icons>
<uni-icons size="18" color="#11f011" fontFamily="iconfont">
"\ue8b2"
</uni-icons>
<uni-icons size="18" color="#111" fontFamily="iconfont">
""
</uni-icons>
<uni-icons size="18" color="#11f011" fontFamily="iconfont">
{{ icon }}
</uni-icons>
<uni-icons size="18" color="#111" fontFamily="iconfont">
{{ icon1 }}
</uni-icons>
</template>
原因就是vue 的模版表达式{{}}会直接转成字符串,不会把当成HTML实体去渲染
HTML 实体(HTML Entity)是一种在 HTML 文档中表示特殊字符的编码方式。当你想在 HTML 中显示某些特殊字符(例如 <、>、& 等),或者是某些不能直接在 HTML 源码中输入的字符时,使用 HTML 实体来代替这些字符。HTML 实体通常以 & 开头,以 ; 结尾。实体有两种类型:命名实体和数字字符引用
1. 命名实体(Named Entity)
命名实体使用特定的名称来表示一些常见的符号或字符。它们的格式是 &name;,例如: < 表示<,
> 表示 >, &表示 &, 这些符号在 HTML 里通常有特殊含义,所以使用命名实体来避免与 HTML 标签冲突。
2. 数字字符引用(Numeric Character Reference)
当某个字符没有命名实体,或者你希望使用某个特定的 Unicode 字符时,可以使用数字字符引用来表示它。数字字符引用有两种形式:
- 十进制格式:&#number;,number 是字符的 Unicode 码点。 例如:
< 表示 <(Unicode 码点为 60) - 十六进制格式:&#xhexnumber;,hexnumber 是字符的 Unicode 码点的十六进制形式,x 表示十六进制。例如:
< 表示 <(十六进制为 3C)
是一种 字符引用,也叫 字符实体,但它不同于常见的 HTML 实体(如 < 表示 <、& 表示 &)。这种形式实际上是 十六进制的字符编码,表示的是一个 Unicode 码点,也可以被称为 数字字符引用。
那我们用v-html去渲染好了,试试
<uni-icons size="18" color="#e71111" fontFamily="iconfont"
v-html="icon1">
我们发现h5可以正常渲染,小程序不行,
看uni-appvue文档, 使用v-html会把组件转为rich-text, 肯定就没法正常显示icon了
App端和H5端支持
v-html,微信小程序会被转为rich-text,其他端不支持v-html
还有一个疑问, 为什么{{ "" }}这样可以解析,{{ unicode }}这样不行, unicode=""
这是因为当我们直接在模板中写 ,Vue 将它当作模板中的 HTML 实体,浏览器会在渲染时自动解析这个 HTML 实体为图标。这与变量插值不同,因为在模板的 HTML 内容中,浏览器会直接处理 HTML 实体,而 Vue 不会干涉这种处理。
将 unicode = '' 赋值给变量时,插值语法 {{ unicode }} 仍然会将 unicode 变量的内容作为纯文本进行插入。这意味着浏览器直接展示了字符串 ,而不会去解析它为 HTML 实体。
我们现在知道了,如果在script定义变量,变量一定要用"\ue8b2"这种形式, 看下官方文档,用的都是这种形式
怎么把""转成这种 "\ue8ad"
"" 和 "\ue8ad" 是两种不同的表示方式,它们的主要区别在于它们的编码格式和使用场景:
-
"":- 这是一个 HTML 实体编码(HTML Character Entity Reference),通常在 HTML 或 XML 中使用。它表示的是一个字符的 Unicode 代码点。
中的 e8ad 是十六进制的 Unicode 编码。- HTML 解析器在渲染时会将其转换为对应的字符。
-
"\ue8ad" :
- 这是 JavaScript 中的 Unicode 转义序列。它直接表示字符,不依赖于 HTML 解析器。
- 在 JavaScript 中,\u 后面跟四个十六进制数字(在此案例中,e8ad 是十六进制数)表示对应的 Unicode 字符。
- JavaScript 解释器将其解析为字符,通常用于字符串中。
转换方法
要将 HTML 实体编码转换为 JavaScript Unicode 转义序列,可以按照以下步骤进行:
- 提取十六进制值:从
中提取出 e8ad。 - 添加 \u 前缀:将其转换为 \ue8ad。
转换示例
const htmlEntities = [
"",
"",
"",
"",
"",
""
];
// 转换为 JavaScript Unicode 表示
const unicodeCharacters = htmlEntities.map(entity => {
// 使用正则表达式提取十六进制数字
const hex = entity.match(/&#x([0-9A-Fa-f]+);/)[1];
return `\\u${hex}`; // 返回以 \u 开头的格式
});
// 输出结果
console.log(unicodeCharacters); // [ '\ue8ad', '\ue602', '\ue8bc', '\ue8b2', '\ue8b4', '\ue8bd' ]
假设我们有一个数组包含 HTML 实体编码,我们可以使用 JavaScript 的字符串处理函数进行转换。
看下我们要实现的效果
<template>
<view class="self">
<view :style="{ height: getNavBarHeight() + 'px' }"></view>
<view class="userinfo">
<view class="left">
<view class="avatar">
<image src="../../static/logo.png" mode=""></image>
</view>
<view class="info">
<view class="username">编辑资料</view>
<view class="text">创作的第109天</view>
</view>
</view>
<view class="right">
<view class="text">编辑资料</view>
<view class="icon">
<uni-icons type="right" size="20" color="#999"></uni-icons>
</view>
</view>
</view>
<view class="cardLayout">
<view class="list">
<view
class="item"
v-for="(item, index) in sentenceList"
:key="item.unicode">
<view class="left">
<view class="icon" :style="{ background: generateGradient(index) }">
<uni-icons size="18" color="#ffffff" fontFamily="iconfont">
{{ item.unicode }}
</uni-icons>
</view>
<view class="name">{{ item.name }}</view>
</view>
<view class="right">
<view class="text">{{ item.count }}</view>
<uni-icons type="right" size="20" color="#999"></uni-icons>
</view>
</view>
</view>
</view>
<view class="cardLayout">
<view class="list">
<view
class="item"
v-for="(item, index) in sentenceList1"
:key="item.unicode">
<view class="left">
<view class="icon" :style="{ background: generateGradient(index+6) }">
<uni-icons
size="18"
color="#ffffff"
:type="item.type"></uni-icons>
</view>
<view class="name">{{ item.name }}</view>
</view>
<view class="right">
<view class="text">{{ item.count }}</view>
<uni-icons type="right" size="20" color="#999"></uni-icons>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { onMounted, ref } from "vue";
import { getNavBarHeight } from "@/utils/system.js";
const icon = "\ue8b2";
const icon1 = "";
const sentenceList = [
{
name: "随手记",
unicode: "\ue8ad", // 转换为 Unicode 字符
},
{
name: "审核",
unicode: "\ue602", // 转换为 Unicode 字符
count: 9,
},
{
name: "收藏",
unicode: "\ue8bc", // 转换为 Unicode 字符
count: 99,
},
{
name: "积分",
unicode: "\ue8b2", // 转换为 Unicode 字符
count: 199,
},
{
name: "句子森林",
unicode: "\ue8b4", // 转换为 Unicode 字符
},
{
name: "联系我们",
unicode: "\ue8bd", // 转换为 Unicode 字符
},
];
const sentenceList1 = ref([
{
name: "偏好设置",
type: "tune",
},
{
name: "退出登录",
type: "contact;",
},
]);
// Function to generate unique gradients
const generateGradient = (index) => {
const gradients = [
"linear-gradient(to right, #ff7e5f, #feb47b)", // Gradient 1
"linear-gradient(to right, #43cea2, #185a9d)", // Gradient 2
"linear-gradient(to right, #ff6a00, #ee0979)", // Gradient 3
"linear-gradient(to right, #00c6ff, #0072ff)", // Gradient 4
"linear-gradient(to right, #f7971e, #ffd200)", // Gradient 5
"linear-gradient(to right, #ad5389, #3c1053)", // Gradient 6
"linear-gradient(to right, #8e2de2, #4a00e0)",
"linear-gradient(to right, #ffe000, #799f0c)",
];
return gradients[index % gradients.length];
};
const queryDatabase = async () => {
uni.navigateTo({
url: "/pages/chore/add",
});
};
// Define onShareAppMessage function
onMounted(() => {});
</script>
<style lang="scss">
.self {
background: $page-bg-color;
min-height: 100vh;
padding-bottom: 30rpx;
.userinfo {
display: flex;
justify-content: space-between;
align-items: center;
padding: 50rpx;
.left {
display: flex;
align-items: center;
.avatar {
width: 120rpx;
height: 120rpx;
border: 3px solid #fff;
border-radius: 50%;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
.info {
padding-left: 20rpx;
.username {
font-size: 38rpx;
font-weight: 600;
color: #111;
}
.text {
font-size: 26rpx;
font-weight: 100;
color: $text-font-color-3;
padding-top: 10rpx;
}
}
}
.right {
display: flex;
align-items: center;
.text {
font-size: 28rpx;
color: #999;
}
}
}
.cardLayout {
width: 690rpx;
background: #fff;
margin: 30rpx auto;
border-radius: 20rpx;
.list {
padding: 30rpx;
.item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 34rpx 0;
border-bottom: 1px solid $border-color-light;
&:last-child {
border: none;
}
.left {
display: flex;
.icon {
width: 50rpx;
height: 50rpx;
background: #ccc;
border-radius: 50%;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
.name {
font-size: 38rpx;
padding-left: 20rpx;
}
}
.right {
display: flex;
align-items: center;
font-size: 26rpx;
color: #999;
}
}
}
}
}
</style>