是否可以根據某些值部分填充 svg 圖示?用例:星級
svg{
fill: red;
}
<!DOCTYPE html>
<html lang="en">
<title></title>
<script src="https://unpkg.com/feather-icons"></script>
<body>
<!-- example icon -->
<i data-feather="star"></i>
<i data-feather="star"></i>
<i data-feather="star"></i>
<script>
feather.replace()
</script>
</body>
</html>
uj5u.com熱心網友回復:
假設您不能直接編輯原始路徑,您可以操縱 SVG 的 dom 插入帶有 ID 的漸變標簽,然后在 CSS 中使用fill : url(#gradient);. 這似乎有點hacky,但它有效:
svg.full {
fill:red;
}
svg#half {
fill : url(#gradient);
}
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<script src="https://unpkg.com/feather-icons"></script>
</head>
<body>
<!-- example icon -->
<i class="full" data-feather="star"></i>
<i id="half" data-feather="star"></i>
<i data-feather="star"></i>
<script type="text/javascript">
feather.replace();
// create the defs SVG tag
// it is important to use createElementNS in that case
const defs = document.createElementNS("http://www.w3.org/2000/svg", 'defs');
defs.innerHTML = '<linearGradient id="gradient"><stop offset="50%" stop-color="#F00"></stop><stop offset="50%" stop-color="transparent" ></stop></linearGradient>';
// Here I'm targeting only the middle start by ID
// You should modify the code to target all half-stars
document.getElementById('half').append(defs);
</script>
</body>
</html>
PS:通過使用<stop>tags屬性,可以實作一些原創效果。
uj5u.com熱心網友回復:
你可以在一個 SVG 中做到
- 我放棄了 Font-Awesome 圖示
- 在https://iconmeister.github.io/上的 7000 多個圖示中搜索“star” (首次加載需要一分鐘)
- 拿起星形圖示與最佳d路徑(凈度圖示集:
cl-social-star-solid) - 只復制了 d 路徑
- 將https://yqnn.github.io/svg-path-editor/ 中的 d-path 編輯為100x100 viewBox/grid
- 通過添加到路徑使其成為逆星
M0 0h100v100h-100v-100 - 在
0 0 300 100viewBox 中創建了一個新的 SVG 檔案以適合 3 顆星..見下文 - 添加了背景矩形設定金色評級
width="50%" - 使用了3 個逆星,每個都在 x 偏移處
- 添加了6 個 覆寫所有半星的矩形
- 在每個“半星”上設定行內事件
(點擊在這個 SO 片段中有效,但 SO 增加了很長的延遲)
概念證明
<svg viewBox="0 0 300 100" width="500px">
<rect id="rating" width="50%" fill="gold" height="100%" />
<path id="star" fill="green"
d="M0 0h100v100h-100v-100m91 42a6 6 90 00-4-10l-22-1a1 1 90 01-1
0l-8-21a6 6 90 00-11 0l-8 21a1 1 90 01-1 1l-22 1a6 6 90 00-4
10l18 14a1 1 90 010 1l-6 22a6 6 90 008 6l19-13a1 1 90 011 0l19
13a6 6 90 006 0a6 6 90 002-6l-6-22a1 1 90 010-1z"/>
<use href="#star" x="100" />
<use href="#star" x="200" />
<rect id="c" width="16.66%" height="100%" fill="transparent" stroke="red"
onclick="console.log(this)" />
<use href="#c" x="50" />
<use href="#c" x="100" />
<use href="#c" x="150" />
<use href="#c" x="200" />
<use href="#c" x="250" />
</svg>
星級評定組件 <star-rating stars=N >
您不想手動創建所有這些 SVG……幾行 JavaScript 就可以為任意數量的星星創建 SVG
這里使用了一個W3C 標準的 Web Component,因為它運行在這個頁面中,不像 React Component 那樣復雜。
https://developer.mozilla.org/en-US/docs/Web/Web_Components
- Not using
<use>, just duplicate all paths and rects with axoffset - mouseover events set the background % color
- click shows the index of the clicked halfstar (0 )
- Rating can be set with values or percentage;
document.querySelector('[stars="5"]').rating="90%"(4.5 stars) - might needs extra work for your use case
All required HTML & JavaScript:
<star-rating stars=5 rating="3.5"
bgcolor="green" nocolor="grey" color="gold"></star-rating>
<star-rating stars=7 rating="50%"
bgcolor="rebeccapurple" nocolor="beige" color="goldenrod"></star-rating>
<script>
document.addEventListener("click", (evt) => console.log(evt.target.getAttribute("n")))
customElements.define("star-rating", class extends HTMLElement {
set rating( rate ) {
if (!String(rate).includes("%")) rate = Number(rate) / this.stars * 100 "%";
this.querySelector("#rating").setAttribute("width", rate);
}
connectedCallback() {
let { bgcolor, stars, nocolor, color, rating } = this.attributes;
this.stars = ~~stars.value || 5;
this.innerHTML =
`<svg viewBox="0 0 ${this.stars*100} 100" style="cursor:pointer;width:300px">`
`<rect width="100%" height="100" fill="${nocolor.value}"/>`
`<rect id="rating" height="100" fill="${color.value}" />`
Array( this.stars ).fill()
.map((i, n) => `<path fill="${bgcolor.value}" d="M${ n*100 } 0h102v100h-102v-100m91 42a6 6 90 00-4-10l-22-1a1 1 90 01-1 0l-8-21a6 6 90 00-11 0l-8 21a1 1 90 01-1 1l-22 1a6 6 90 00-4 10l18 14a1 1 90 010 1l-6 22a6 6 90 008 6l19-13a1 1 90 011 0l19 13a6 6 90 006 0a6 6 90 002-6l-6-22a1 1 90 010-1z"/>`)
.join("")
Array( this.stars * 2 ).fill()
.map((i, n) => `<rect x="${ n*50 }" n="${n}" opacity="0" width="50" height="100"`
` onclick="dispatchEvent(new Event('click'))" `
` onm ouseover="this.closest('star-rating').rating = ${(n 1)/2}"/>`)
.join("")
"</svg>";
this.rating = rating.value;
}
});
</script>
Notes:
- This native
<star-rating>Component (also called Custom Element because NO shadowDOM is involved) has ZERO dependencies- no libraries
- no external SVG
- native components are not self-closing tags and must contain a hyphen, so notation is:
<star-rating></star-rating> - Changed the star to
M0 0h102v100h-102v-100(2 pixel overlap) to cover SVG rounding issues
Supported in all Frameworks... except...
React doesn't support this modern W3C Web Components Standard yet.
React scores just 71% on https://custom-elements-everywhere.com/
All other Frameworks (Angular, Vue, Svelte) have 100% support
You have to do some extra work to handle native DOM Elements and Events in React; but the Custom Element isn't complex.. it creates SVG; should be easy to replicate as a React Component.
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/359356.html
上一篇:反轉svg折線
下一篇:antd:添加自定義svg圖示
