最近在做的一个几月vue的移动端小demo,其中有一块是实现各个页面的统一换肤功能的。想着写一篇文章,来写一写实现过程中遇到的一些问题。

项目在线demo

项目在线演示demo(切换到移动端调试模式哦)

项目github地址

项目github地址

一 先看一下实现效果吧

设置主题颜色
讲道理这么一个功能,我觉得这么几点可以说下,分步实现:
1. 色值的选取
2. scss 的一些小众用法(多变量CSS值的批量设置)
3. 全局事件巴士的应用

1 色值的选取和原则

推荐大家看下蚂蚁金服的设计指引,里面对常见的交互和界面设计有一套不错的指引和建议,喜欢看书的也可以看看《写给大家看的设计书》。
对于界面中的色彩元素,我们一般要保持视觉的连续性,即同一套色彩,尽量采取同一个色环上的色值

同一个圆环上的色值作为一套颜色会显得更协调

所以这里采取ant design 的建议,取某一列色值作为我们的系列主题颜色(具体色值参照它的官网吧~)

而在某些特殊场合,需要表现出颜色的差异,如抛硬币页面的两个颜色,

2 将格式色值转换成十六进制颜色值

这里我们通过设置主题颜色的透明度来实现区分不同颜色, 然后我们是通过存储一个诸如#123456的16进制颜色全局变量作为我们主题,这里就需要我们把这样一个格式的色值转化成 rgba 表示的颜色值啦,代码如下,备用

  hexToRgba (hex, opacity = 0.3) {let color = []let rgb = []hex = hex.replace(/#/, '')for (let i = 0; i < 3; i++) {color[i] = '0x' + hex.substr(i * 2, 2)rgb.push(parseInt(Number(color[i])))}return `rgba(${rgb.join(',')},${opacity})`}复制代码

##3 scss 的一些小众用法
我们最终拿到这么一串我们想要的主题颜色

$colors: #f04134, #00a854, #108ee9, #f5317f, #f56a00, #7265e6, #ffbf00, #00a2ae, #2e3238;复制代码

一个很直接的思路,我们需要在各个view页面里面,去定义我们需要设置主题的元素的颜色,比如文字和icon的color, 以及头部的background 等。 于是我们在app 里面定义一个color变量,派发到各个view组件里面去,通过这个全局的变量来控制所有路由页面的颜色,以实现不同的主题效果。
派发的实现在下一个部分说,这里我们先来完成我们的第一步,我们可以容易提取出我们的需求:
4 设置并保存一个全局颜色
界面的小事:
我在首页直接实现这个功能,项目中我引入了mint-ui 框架(饿了么团队的移动端框架,稍微遗憾使用感觉没有element.ui 的舒服), 设置的交互就用弹层 mt-popup 的形式好了,然后直接点击色块便设置对应颜色值

 <!-- 設置顏色 --><mt-popup v-model="changColor" position="bottom" class="color-panel"><div class="color-items"><span class="color-item" v-for="(item, $index) in colors"  :key="$index" @click="chooseColor(item)"><span class="color-cycle" :class="'bg-color' + ($index + 1)"></span></span></div></mt-popup>复制代码

接着就是色块div的呈现,从上面代码发现,我会很容易出现类似这样的css样式表

.bg-color1 {background: #f04134}
.bg-color2 {background: #f04134}
.bg-color3 {background: #f04134}
.bg-color4 {background: #f04134}
···复制代码

写代码时候如果我们一般发现,一件类似的东西重复出现了,就总隐隐觉得可以开始表演了,然后可预见的是,这样的情况意味着在项目增长后,还可能出现许多单一设置字体颜色或border颜色的样式表,诸如color1, borderColor1···,这样每种形式的表现我们都需要根据我们主题颜色的数组去逐条书写,修改成本也会变高 。于是我的书写风格是这样的,

// mixin.scss:
$colors: #f04134, #00a854, #108ee9, #f5317f, #f56a00, #7265e6, #ffbf00, #00a2ae, #2e3238;// setColor.vue:
@import '~@/assets/mixin.scss';
···
@for $i from 1 to 10 {.bg-color#{$i} {background-color: nth($colors, $i)}}复制代码

scss 除了常用的类名嵌套书写外,还有许多···低调奢华的语法, 对于这类需要重复书写的样式类型,我的约定是添加一个scss变量在mixin 文件中, 在需要书写重复循环样式时候作为变量引入,并在书写样式时候,利用sass的循环,引用其中对应的值,这样无论设置颜色的样式怎么拓展和变化,变成颜色背景边框都好,我都只需要维护一份mixin的的文件里的色值就行了, 同样的实践也可以应用于项目里面字体大小和间距值的统一之类,总之我们多尝试体验下吧

5 逻辑的小事

这个项目里面localstorage 基本被当成数据库使用了,所以点击色块设置主题时候,我们假装发出请求,在localstorage存储我们改变的颜色就好了( ./static/api.json 是一个返回helloword 的json, 为了写实在这里这么用,$bus 事件巴士下面说, 作用就是设置全局的主题颜色变量,localStorage 模拟我们把设置存储到后台,每次重新打开页面就去获取这些设置值), 目前为止,我们的设置页面就大致完成了

// 假装调用接口设置颜色chooseColor (color) {this.$axios.get('./static/api.json').then((data) => {this.$bus.$emit('set-theme', color)this.changColor = falselocalStorage.setItem('themeColor', color)}).catch((data) => {console.log(data)})}复制代码

6 事件巴士的运用

在上一步最后我们有个关键的东西没完成, this.$bus.$emit('set-theme', color),将选取的颜色设置到全局,我的代码结构是这样的

子组件

<setColor>home 页面的一个子组件,而在一开始我们已经说了,我们想在我们在app.vue (home.vue和其他view的父组件) 里面定义一个color变量,派发到各个view组件里面去。 于是这其实就是个,从setColor 触发app.vue的设置颜色事件, 子组件向父组件通信的问题。

我们可以很直接地用绑定事件配合emit()的做法,在app.vue 定义一个setglobalColor方法, 并绑定到router-view(包含了home.vue),接着在home组件继续定义一个setglobalColor方法, 实现的功能就是 emit('setglobalColor') 去触发app.vue的方法, 并把home.vue的这个setglobalColor继续绑定到组件, 组件里面点选颜色时候,直接emit这个方法就行了。
为什么我想用事件巴士 .vue 的事件巴士和 vuex, 在一些有追求的程序员手里总是小心翼翼的,我也一样,因为作为涉及全局的东西,一般觉得能不用就不用,代码能精简就精简,我们经常用一个词,不提倡。
可是有朝一日我经常在想,代码的可读性可维护性,和性能以及“风险”相对比,到底哪个更重要。对于事件巴士和vuex 这类全局性质的方案的主要担忧大部分在于, 他们是全局的,可能因为一个事件名变量名一致就造成冲突,在小型项目还会造成冗余和额外开销。 但事实上,事件和变量的命名我们都可以通过约定去规范,而在表现上,使用了事件巴士和vuex的项目,在性能上和直接props传递数据,emit 回调事件的项目相比,其实并没有太大区别,反而是无止境的props 和 emit,给人一种麻烦难以维护的感觉。 像上述的setglobalColor, 仅仅是跨越了两层组件, 过程就显得繁琐了。所以我建议在出现两级以上组件层次,数据流稍微多的项目中都可以这么去做,定义一个全局的事件巴士

export default (Vue) => {let eventHub = new Vue()Vue.prototype.$bus = {$on (...arg) {eventHub.$on(...arg)},$off (...arg) {eventHub.$off(...arg)},$emit (...arg) {eventHub.$emit(...arg)}}
}复制代码

将事件巴士绑定到当前vue对象,使用时候只需要:

this.$bus.$on('set-theme', (color) => {··· })
this.$bus.$emit('set-theme', '#000000')复制代码

在这个demo中,我在app.vue 绑定了

this.$bus.$on('set-theme', (color) => {this.loadingColor = colorthis.userinfo.color = color})复制代码

而在setColor.vue则在点击颜色块时候触发 this.$bus.$emit('set-theme', color), 则能实现我们设置全局颜色的效果。这样的好处在于,对于跨了多个层次,或者兄弟组件的通信,我们不再需要太繁琐的props,比如我在header.vue 也绑定了this.$bus.$on('set-theme', (color) => { }),在 this.$bus.$emit发生时候,header 的背景颜色就能直接改变,而不需要等待app.vue 将 全局的color值props传递到header.vue里面(仅做示例,这里header.vue只是app.vue的下一层级,通过props数据流会更清晰)
而对于其他路由页面组件,和app.vue 都是直接上下级关系,我们依然采用props保持一个清晰的数据流向下传递,demo里我是将color存在userinfo(以后还有其他数据), userinfo传到每个子路由, 最后,每个页面在创建时候,通过拿到这个全局的颜色,再用dom去更改对应的样式就好啦,例如

mounted () {this.$nextTick(() => {// 绑定设置主题的事件,一旦触发修改主题,则将当前字体颜色改为对应颜色this.$el.querySelector('.myTitle').style.color = this.userinfo.colorthis.$el.querySelector('.weui-btn_primary').style.backgroundColor = this.userinfo.colorthis.$el.querySelector('.add_icon').style.color = this.userinfo.color})}复制代码

详细的实现请参照项目代码,这里我只挑一些比较清奇的点出来讨论,项目和代码的一些规范和习惯还是挺重要的,希望有好的实践能互相借鉴进步~

我是KimyAndKath ,希望好东西一起分享。

项目在线demo

项目在线演示demo(切换到移动端调试模式哦)

项目github地址

项目github地址

vue移动助手实践(一)——基于vue的换肤功能相关推荐

  1. VUE+ElementUI项目换肤功能

    VUE+ElementUI项目换肤功能 一.固定多套主题换肤 设置页面 (views/layout.vue) themes.js (@/utils/themes) main.js css相关结构及内容 ...

  2. vue 实现换肤功能

    公司项目要实现vue项目换肤功能,要求一套深色,一套浅色,考虑到最节省时间的就是写两套css,一套light.css,一套dark.css,然后切换css 一.实现思路:切换选中的皮肤状态(light ...

  3. Element UI主题换肤功能(基于vue-element-admin框架)

    环境信息: 日期:2022-08-05 node版本:v14.15.4 "sass": "1.26.8", "sass-loader": & ...

  4. 基于vue前端聊天插件_基于Vue聊天的实现

    基于vue前端聊天插件 基本视频聊天 (basic-vue-chat) Easy to use VueJS chat. 易于使用的VueJS聊天. 安装 (Installation) You can ...

  5. vue时间天气插件_基于vue.js 2.0的百度天气应用 – vue-weather

    vue-weather 基于vue.js 2.0的百度天气应用. 说明 初学vue,在看完一个简单的视频教程和走两遍完官方文档之后仍然感觉云里雾里,知其然不知其所以然(虽然现在好了点).请教了高手之后 ...

  6. vue 音乐盒app_VBox 一款基于vue开发的音乐盒 序章

    自己基于vue写了一个 Mplayer, 只有简单的搜索播放随心听功能,样式适配上也很差, 路由就两个,数据都走vuex,数据转发是用nodejs自己转发,而且只是PC能比较好的展现,之后不了了之,偶 ...

  7. vue划入划出事件_基于vue中对鼠标划过事件的处理方式详解

    鼠标事件进行监听 需求中,在一个table(组件)表中,对于其中一列(该列为图片列),当鼠标划过该列的某个单元格子(图片)时,需要展示出该单元格子对应的遮罩层 翻阅了一些博客,发现好多都提到了mous ...

  8. vue连线 插件_基于Vue的任务节点图绘制插件(vue-task-node)

    简介: vue-task-node 是一个基于Vue的任务节点图绘制插件(vue-task-node is a Vue based task node mapping plug-in) 此篇博客会随插 ...

  9. vue的一键换肤功能

    由于项目是已经写好了的,需要突然加一个一键换肤的功能,切换黑白两个皮肤,但是最好不要大量改动代码- 1.sass+vue 这种方法需要安装一个插件,webpack-theme-color-replac ...

最新文章

  1. ai取代程序员_你现在从事的程序员还有多久会消失?牛津大学研究员帮你算了算...
  2. 实验9 结构程序设计 6-1 计算两个复数之积
  3. 操作系统磁盘空闲管理之位示图法
  4. 酷乐Emlog新春特别版coolappy2.2开源
  5. h5离线缓存与浏览器缓存的区别
  6. 介绍一个小技巧,如何实现ssh免密登录
  7. 4WRLE27Q3-600M-4X/MXY/24A1比例先导方向阀
  8. JAVA开发常见单词(*)
  9. js监听移动端手机横竖屏事件
  10. matlab图片处理基本知识,Matlab图像处理基础知识
  11. DTOI 10.24 测试(被爆屠) orz IcePrincess_1968
  12. 关于程序员的非技术面试题全在这里。
  13. P4720 【模板】扩展卢卡斯
  14. python3携程_python携程
  15. 西安交通大学大计基第十四周练习题
  16. matlab expma,现代科学运算—MATLAB语言与应用-中国大学mooc-题库零氪
  17. 在Excel工作簿中显示网络图片
  18. 总结餐饮行业现状痛点
  19. C语言 % x的作用,关于c语言%#X意思大全
  20. 产品需求分析与市场分析方法汇总(SWOT+PDCA+波士顿矩阵BCG+5W2H分析法+STAR关键事件分析法+目标管理SMART+时间管理紧急重要矩阵+WBS任务分解法)

热门文章

  1. 玩转ChatGPT:论文翻译润色
  2. A_A02_001 CH340驱动安装
  3. Windows便捷长时间检测网络丢包
  4. mysql函数编写格式_MySQL函数基础——字符串函数详解
  5. 南开大学 软件学院 计算机网络 2021秋季 复习
  6. asp.net网页版斗地主(当前版本1.0 未完待续 最后更新时间2010-06-21)
  7. 悼念巨人:著名科学家、上海大学校长钱伟长
  8. Au 入门系列之八:包络与自动控制
  9. 浮点数的规格化表示 非规格化表示
  10. Delphi菜单设计.4