摘要:之前在做網站換膚,所以今天想聊聊網站換膚的實現。一般實現如上圖,我們會看到在某些網站的右上角會出現這么幾個顏色塊,點擊不同的顏色塊,網站的整體顏色就被替換了。
之前在做網站換膚,所以今天想聊聊網站換膚的實現。網頁換膚就是修改顏色值,因此重點就在于怎么來替換。
一般實現
如上圖,我們會看到在某些網站的右上角會出現這么幾個顏色塊,點擊不同的顏色塊,網站的整體顏色就被替換了。要實現它,我們考慮最簡單的方式:點擊不同的按鈕切換不同的樣式表 ,如:
theme-green.css
theme-red.css
theme-yellow.css
可以看出,我們需要為每個顏色塊編寫樣式表,那如果我要實現幾百種或者讓用戶自定義呢,顯而易見這種方式十本笨拙,且拓展性并不高,另外,如果考慮加載的成本,那其實這種方式并不可取。
ElementUI 的實現ElementUI 的實現比上面的實現高了好幾個level,它能讓用戶自定義顏色值,而且展示效果也更加優雅。當前我的實現就是基于它的思路來實現。
我們來看看他是怎么實現的(這里引用的是官方的實現解釋):
先把默認主題文件中涉及到顏色的 CSS 值替換成關鍵詞:https://github.com/ElementUI/theme-preview/blob/master/src/app.vue#L250-L274
根據用戶選擇的主題色生成一系列對應的顏色值: https://github.com/ElementUI/theme-preview/blob/master/src/utils/formula.json
把關鍵詞再換回剛剛生成的相應的顏色值:https://github.com/ElementUI/theme-preview/blob/master/src/utils/color.js
直接在頁面上加 style 標簽,把生成的樣式填進去:https://github.com/ElementUI/theme-preview/blob/master/src/app.vue#L198-L211
下面我具體講下我參考它的原理的實現過程 (我們的css 編寫是基于 postcss 來編寫的):
先確定一個主題色,其他需在在換膚過程中隨主題色一起修改的顏色值就根據主題色來調用例如(上面已經說到了我們是基于postcss來編寫的,所以就使用了如下函數來計算顏色值): tint(var(--color-primary), 20%) ,darken(var(--color-primary), 15%) ,shade(var(--color-primary), 5%) 等。這也類似就實現了上面的第一步
然后根據用戶選擇的顏色值來生成新的一輪對應的一系列顏色值:
這里我先把全部css文件中可以通過主題色來計算出其他顏色的顏色值匯總在一起,如下:
// formula.js const formula = [ { name: "hoverPrimary", exp: "color(primary l(66%))", }, { name: "clickPrimary", exp: "color(primary l(15%))", }, { name: "treeBg", exp: "color(primary l(95%))", }, { name: "treeHoverBg", exp: "color(primary h(+1) l(94%))", }, { name: "treeNodeContent", exp: "color(primary tint(90%))", }, { name: "navBar", exp: "color(primary h(-1) s(87%) l(82%))", } ]; export default formula;
這里的color函數 是后面我們調用了 css-color-function 這個包,其api使然。
既然對應關系匯總好了,那我們就來進行顏色值的替換。在一開始進入網頁的時候,我就先根據默認的主題色根據 formula.js 中的 計算顏色匯總表 生成對應的顏色,以便后面的替換,在這過程中使用了css-color-function 這個包,
import Color from "css-color-function"; componentDidMount(){ this.initColorCluster = ["#ff571a", ...this.generateColors("#ff571a")]; // 拿到所有初始值之后,因為我們要做的是字符串替換,所以這里利用了正則,結果值如圖2: this.initStyleReg = this.initColorCluster .join("|") .replace(/(/g, "(") // 括號的轉義 .replace(/)/g, ")") .replace(/0./g, "."); // 這里替換是因為默認的css中計算出來的值透明度會缺省0,所以索性就直接全部去掉0 } generateColors = primary => { return formula.map(f => { const value = f.exp.replace(/primary/g, primary); // 將字符串中的primary 關鍵字替換為實際值,以便下一步調用 `Color.convert` return Color.convert(value); // 生成一連串的顏色值,見下圖1,可以看見計算值全部變為了`rgb/rgba` 值 }); };
圖1:
圖2,黑色字即為顏色正則表達式:
好了,當我們拿到了原始值之后,就可以開始進行替換了,這里的替換源是什么?由于我們的網頁是通過如下 內嵌style標簽 的,所以替換原就是所有的style標簽,而 element 是直接去請求網頁 打包好的的css文件:
注:并不是每次都需要查找所有的 style 標簽,只需要一次,然后,后面的替換只要在前一次的替換而生成的 style 標簽(使用so-ui-react-theme來做標記)中做替換
下面是核心代碼:
changeTheme = color => { // 這里防止兩次替換顏色值相同,省的造成不必要的替換,同時驗證顏色值的合法性 if (color !== this.state.themeColor && (ABBRRE.test(color) || HEXRE.test(color))) { const styles = document.querySelectorAll(".so-ui-react-theme").length > 0 ? Array.from(document.querySelectorAll(".so-ui-react-theme")) // 這里就是上說到的 : Array.from(document.querySelectorAll("style")).filter(style => { // 找到需要進行替換的style標簽 const text = style.innerText; const re = new RegExp(`${this.initStyleReg}`, "i"); return re.test(text); }); const oldColorCluster = this.initColorCluster.slice(); const re = new RegExp(`${this.initStyleReg}`, "ig"); // 老的顏色簇正則,全局替換,且不區分大小寫 this.clusterDeal(color); // 此時 initColorCluster 已是新的顏色簇 styles.forEach(style => { const { innerText } = style; style.innerHTML = innerText.replace(re, match => { let index = oldColorCluster.indexOf(match.toLowerCase().replace(".", "0.")); if (index === -1) index = oldColorCluster.indexOf(match.toUpperCase().replace(".", "0.")); // 進行替換 return this.initColorCluster[index].toLowerCase().replace(/0./g, "."); }); style.setAttribute("class", "so-ui-react-theme"); }); this.setState({ themeColor: color, }); } };
效果如下:
至此,我們的顏色值替換已經完成了。正如官方所說,實現原理十分暴力
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102779.html
摘要:所以今天,就和大家一起聊一聊前端的安全那些事兒。我們就聊一聊前端工程師們需要注意的那些安全知識。殊不知,這不僅僅是違反了的標準而已,也同樣會被黑客所利用。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/blog... 隨著互聯網的發達,各種WEB應用也變得越來越復雜,滿足了用戶的各種需求...
摘要:歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面不僅僅是代碼作為現代應用,的大量使用,使得前端工程師們日常的開發少不了拼裝模板,渲染模板。我們今天就來聊聊,拼裝與渲染模板的那些事兒。一改俱改,一板兩用。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/blog...
摘要:歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面不僅僅是代碼作為現代應用,的大量使用,使得前端工程師們日常的開發少不了拼裝模板,渲染模板。我們今天就來聊聊,拼裝與渲染模板的那些事兒。一改俱改,一板兩用。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/blog...
摘要:歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面不僅僅是代碼作為現代應用,的大量使用,使得前端工程師們日常的開發少不了拼裝模板,渲染模板。我們今天就來聊聊,拼裝與渲染模板的那些事兒。一改俱改,一板兩用。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/blog...
摘要:歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面不僅僅是代碼什么是功能統計作為一名開發,我們的產品發布出去之后,無論是產品還是運營,其實都是想及時了解產品對用戶產生的影響的。下一章,我們將繼續聊聊速度統計。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/bl...
閱讀 882·2021-11-15 11:38
閱讀 2512·2021-09-08 09:45
閱讀 2812·2021-09-04 16:48
閱讀 2563·2019-08-30 15:54
閱讀 929·2019-08-30 13:57
閱讀 1617·2019-08-29 15:39
閱讀 495·2019-08-29 12:46
閱讀 3519·2019-08-26 13:39