沒想到(css的幾種引入方式)引入css,【總結(jié)】1736- 利用這個(gè) css 屬性,你也能輕松實(shí)現(xiàn)一個(gè)新手引導(dǎo)庫,陳銘生原型照片,
目錄:
1.引入css的方式有幾種
2.引入css的三種方法
3.css引入的方式有哪些和區(qū)別
4.css的三種引入方式的優(yōu)缺點(diǎn)
5.css三種引入方式是哪些
6.簡述引入css樣式的幾種方法
7.引入css的4種方式
8.引入css的四種方式
9.css的引入方式有哪三種
10.css引入方式有哪些
1.引入css的方式有幾種
相信大家或多或少都在各種網(wǎng)站上使用過新手引導(dǎo),當(dāng)網(wǎng)站提供的功能有點(diǎn)復(fù)雜時(shí),這是一個(gè)對(duì)新手非常友好的功能,可以跟隨新手引導(dǎo)一步一步了解網(wǎng)站的各種功能,我們要做的只是點(diǎn)擊下一步或者上一步,網(wǎng)站就能滾動(dòng)到指定位置,然后高亮頁面的一部分,并且配以一些圖文介紹。
2.引入css的三種方法
目前有很多幫你實(shí)普門品全文念誦及回向儀軌現(xiàn)這種功能的開源庫,當(dāng)然,自己實(shí)現(xiàn)一個(gè)也不難,而且核心就是一個(gè)簡單的css樣式,不信你接著往下看基本思路假設(shè)我們的新手引導(dǎo)庫是一個(gè)類,名為NoviceGuide,我們可以這樣使用它:new
3.css引入的方式有哪些和區(qū)別
NoviceGuide({ steps: [ { element: ,// 頁面上的元素,可以是節(jié)點(diǎn),也可以是節(jié)點(diǎn)的選擇器 text:
4.css的三種引入方式的優(yōu)缺點(diǎn)
我是第一步, img: 我是第一步的圖片 }, { element: , 普門品全文念誦及回向儀軌 text: 我是第二步 }
5.css三種引入方式是哪些
]}).start()我們稍微思考一下就會(huì)發(fā)現(xiàn),實(shí)現(xiàn)原理其實(shí)很簡單,只要找到某一步指定節(jié)點(diǎn)的位置和寬高,然后將頁面滾動(dòng)到該節(jié)點(diǎn)的位置,最后高亮它,并且在旁邊顯示信息即可我們的類基本結(jié)構(gòu)如下:class
6.簡述引入css樣式的幾種方法
NoviceGuide {constructor(options) {this.options = options// 步驟數(shù)據(jù)this.steps = []// 當(dāng)前所在步驟this.currentStepIndex =
7.引入css的4種方式
-1// 處理步驟數(shù)據(jù)this.in普門品全文念誦及回向儀軌itSteps() } initSteps() {this.options.steps.forEach((step) => {this.steps.push({ ...step,
8.引入css的四種方式
element:typeof step.element === "string" ? document.querySelector(step.element) : step.element,
9.css的引入方式有哪三種
}) }) } start() {this.next() } next() {}}滾動(dòng)到目標(biāo)元素獲取到當(dāng)普門品全文念誦及回向儀軌前步驟的元素,然后再獲取它的位置,最后再滾動(dòng)頁面,讓目標(biāo)元素居中即可class
10.css引入方式有哪些
NoviceGuide { next() {// 已經(jīng)是最后一步,那么結(jié)束引導(dǎo)if (this.currentStepIndex + 1 >= this.steps.length) {return
this.done() }this.currentStepIndex++this.to() } to() {// 當(dāng)前步驟const currentStep = this.steps[
this.currentStepIndex]// 當(dāng)前步驟元素的尺寸和位置信息con普門品全文念誦及回向儀軌st rect = currentStep.element.getBoundingClientRect()const windowHeight =
window.innerHeight// 瀏覽器窗口滾動(dòng)到元素所在位置window.scrollBy(0, rect.top - (windowHeight / 2 - rect.height / 2))
} done() {}}使用window.scrollBy滾動(dòng)相對(duì)距離,距離的計(jì)算可以參考下圖:
不過如果元素已經(jīng)在可視窗口內(nèi),其實(shí)不需要將它居中,否則如果多個(gè)步驟都在一個(gè)窗口內(nèi),那么切換步驟會(huì)頻繁的滾動(dòng)頁面,體驗(yàn)反而不好,所以先判斷一下元素是否普門品全文念誦及回向儀軌在視口內(nèi):classNoviceGuide { to() {
const currentStep = this.steps[this.currentStepIndex]const rect = currentStep.element.getBoundingClientRect()
const windowHeight = window.innerHeightif (!this.elementIsInView(currentStep.element)) {window.scrollBy(
0, rect.top - (windowHeight - rect.height) / 2) 普門品全文念誦及回向儀軌 } } elementIsInView(el) {const rect = el.getBoundingClientRect()
return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= window.innerHeight &&
rect.right <= window.innerWidth ) }}高亮元素目標(biāo)元素可見了,接下來要做的是高亮它,具體的效果就是頁面上只有目標(biāo)元素是亮的,其他地方都是暗的,這個(gè)實(shí)現(xiàn)方式我考慮過使用
svg、ca普門品全文念誦及回向儀軌nvas等,比如canvas實(shí)現(xiàn):classNoviceGuide { to() {// ...this.highlightElement(currentStep.element) }
highlightElement(el) {const rect = el.getBoundingClientRect();const canvas = document.createElement(
canvas)document.body.appendChild(canvas)const ctx = canvas.getContext(2d) canvas.width = window普門品全文念誦及回向儀軌
.innerWidth canvas.height = window.innerHeight canvas.style.cssText = ` position: fixed;
left: 0; top: 0; z-index: 99999999; ` ctx.fillStyle =
rgba(0, 0, 0, 0.5) ctx.fillRect(0, 0, window.innerWidth, window.innerHeight) ctx普門品全文念誦及回向儀軌.clearRect(rect.left, rect.top, rect.width, rect.height)
}}原理很簡單,創(chuàng)建一個(gè)和窗口一樣大的canvas,然后全部填充成半透明,最后再清除掉目標(biāo)元素所在位置的繪制,就達(dá)到了高亮的效果:
不過這種方式想要效果更好一點(diǎn)比較麻煩,后來在其他庫中看到一個(gè)很簡單的實(shí)現(xiàn),使用一個(gè)box-shadow屬性即可:classNoviceGuide { highlightElement(el) {const
rect = el.getBoundingClientRect()if (!this.highlightEl) {this.highlightEl 普門品全文念誦及回向儀軌= document.createElement("div"
)this.highlightEl.style.cssText = ` position: absolute; box-shadow: 0 0 0 5000px rgba(0, 0, 0, 0.5);
z-index: 99999999; border-radius: 5px; transition: all 0.3s ease-out;
`document.body.appendChild(this.highlight普門品全文念誦及回向儀軌El) }this.highlightEl.style.left = rect.left +
window.pageXOffset + "px"this.highlightEl.style.top = rect.top + window.pageYOffset + "px"this.highlightEl.style.width = rect.width +
"px"this.highlightEl.style.height = rect.height + "px" }}核心就是box-shadow: 0 0 0 5000px rgba(0, 0, 0, 0.5);
這一行樣式,普門品全文念誦及回向儀軌創(chuàng)建一個(gè)和目標(biāo)元素一樣大小的元素,然后蓋在它上面,然后把這個(gè)元素的陰影大小設(shè)置成非常大,這樣除了這個(gè)元素的內(nèi)部,頁面其他地方都是它的陰影,就達(dá)到了高亮的效果,果然是css學(xué)的好,每天下班早使用
DOM簡單很多,修改樣式比較方便,另外只要設(shè)置transition,就能輕松實(shí)現(xiàn)切換步驟時(shí)高亮的過渡動(dòng)畫效果另外為什么這里沒有使用固定定位,而是使用絕對(duì)定位,其實(shí)是因?yàn)槿绻褂霉潭ǘㄎ?,頁面可以滾動(dòng),但是高亮框并不會(huì)滾動(dòng),那么就對(duì)不上了。
切換步驟接下來,我們創(chuàng)建一個(gè)新元素用來存放信息和上一步下一步的按鈕:classNoviceGuide {constructor(options) {// ...this.普門品全文念誦及回向儀軌infoEl = null }
to() {// ...this.showStepInfo(currentStep) } showStepInfo(step) {if (!this.infoEl) {this.infoEl =
document.createElement("div")this.infoEl.style.cssText = ` position: absolute; z-index: 99999999;
background-color: #fff; border-radius: 5px; 普門品全文念誦及回向儀軌 `document.body.appendChild(this.infoEl)
// 綁定單擊事件this.infoEl.addEventListener("click", (e) => {let type = e.target.getAttribute("data-type")if
(type) {if (type === "prev") {this.prev() }if (type === "next") {this.next() }
} }) }this.inf普門品全文念誦及回向儀軌oEl.innerHTML = `
`
`: }
下一步
this.infoEl.style.left = rect.left + window.pageXOffset + "px"this.infoEl.style.top = rect.bottom + window
.pageXOffset + "px" }}很簡單,同樣是創(chuàng)建一個(gè)絕對(duì)定位的元素,里面存放信息、圖片、按普門品全文念誦及回向儀軌鈕,然后監(jiān)聽一下點(diǎn)擊事件,判斷點(diǎn)擊的是上一步還是下一步,補(bǔ)充一下上一步和結(jié)束的邏輯:class
NoviceGuide { prev() {if (this.currentStepIndex - 1 < 0) {return }this.currentStepIndex--this
.to() } done() {document.body.removeChild(this.highlightEl)document.body.removeChild(this.infoEl)
this.currentStepIndex = -1 }}結(jié)束的話直接刪除創(chuàng)建的兩個(gè)元素普門品全文念誦及回向儀軌就可以了,看看目前的效果:
優(yōu)化加點(diǎn)內(nèi)邊距目前視覺上不是很好看,高亮框和目標(biāo)元素大小是完全一樣的,高亮框和信息框完全挨著,信息框沒有內(nèi)邊距,所以優(yōu)化一下:classNoviceGuide {constructor(options) {
this.options = Object.assign( { padding: 10, margin: 10 },
options ) } highlightElement(el) {// ...let { padding } = thi普門品全文念誦及回向儀軌s.optionsthis.highlightEl.style.left = rect.left +
window.pageXOffset - padding + "px"this.highlightEl.style.top = rect.top + window.pageYOffset - padding +
"px"this.highlightEl.style.width = rect.width + padding * 2 + "px"this.highlightEl.style.height = rect.height + padding *
2 + "px" } showSte普門品全文念誦及回向儀軌pInfo(step) {let { padding, margin } = this.optionsif (!this.infoEl) {this.infoEl.style.cssText =
` padding: ${padding}px; ` }// ...this.infoEl.style.left = rect.left + window.pageXOffset - padding +
"px"this.infoEl.style.top = rect.bottom + window.pageYOffset + padding + margin + "px" 普門品全文念誦及回向儀軌 }}
支持某個(gè)步驟沒有元素某些步驟可能是純信息,不需要元素,這種情況直接顯示在頁面中間即可:classNoviceGuide { to() {const currentStep = this.steps[
this.currentStepIndex]if (!currentStep.element) {// 當(dāng)前步驟沒有元素this.highlightElement()this.showStepInfo(currentStep)
return }// ... } highlightElement(el) {// ...if (el) {const rect = el普門品全文念誦及回向儀軌.getBoundingClientRect()
let { padding } = this.options// ...// 原有邏輯 } else {// 當(dāng)前步驟沒有元素高亮元素的寬高設(shè)置成0,并且直接定位在窗口中間this.highlightEl.style.left =
window.innerWidth / 2 + window.pageXOffset + "px"this.highlightEl.style.top = window.innerHeight / 2 +
window.pageYOffset + "px"this.highlightEl.style.widt普門品全文念誦及回向儀軌h = 0 + "px"this.highlightEl.style.height = 0 + "px"
} } showStepInfo(step) {// ...if (step.element) {const rect = step.element.getBoundingClientRect()
// ...// 原有邏輯 } else {// 當(dāng)前步驟沒有元素,信息框定位在窗口中間const rect = this.infoEl.getBoundingClientRect()this
.infoEl.style.left = (window.innerWidth -普門品全文念誦及回向儀軌 rect.width) / 2 + window.pageXOffset + "px"this.infoEl.style.top = (
window.innerHeight - rect.height) / 2 + window.pageYOffset + "px" } }}
當(dāng)然,上述實(shí)現(xiàn)還是有點(diǎn)問題的,比如網(wǎng)速慢的時(shí)候,或者圖片比較大時(shí),圖片還沒加載出來,那么獲取到的信息框的大小是不對(duì)的,導(dǎo)致定位會(huì)出現(xiàn)偏差,這個(gè)問題本文就不考慮了動(dòng)態(tài)計(jì)算信息的位置目前我們的信息框是默認(rèn)顯示在高亮元素下方的,這樣顯然是有問題的,比如高亮元素剛好在屏幕底部,或者信息框的高度很高,底部無法完普門品全文念誦及回向儀軌全顯示,這種情況,我們就需要改成動(dòng)態(tài)計(jì)算的方式,具體來說就是依次判斷信息框能否在高亮元素下方、上方、左方、右方四個(gè)方向顯示,如果都不行的話,還要嘗試調(diào)整頁面滾動(dòng)的位置使高亮框和信息框都能顯示。
classNoviceGuide { showStepInfo(step) {// ...if (step.element) {this.computeInfoPosition(step) }
else {// ... } }}計(jì)算的邏輯我們放到一個(gè)新函數(shù)里:classNoviceGuide { computeInfoPosition(step) {const 普門品全文念誦及回向儀軌{ padding, margin } =
this.optionsconst windowWidth = window.innerWidthconst windowHeight = window.innerHeightconst windowPageXOffset =
window.pageXOffsetconst windowPageYOffset = window.pageYOffsetconst rect = step.element.getBoundingClientRect()
const infoRect = this.infoEl.getBoundingClientRect()// 普門品全文念誦及回向儀軌... }}獲取和保存一些基本信息,繼續(xù):classNoviceGuide { computeInfoPosition(step) {
let left = 0let top = 0const adjustLeft = () => {// 優(yōu)先和高亮框左對(duì)齊if (windowWidth - rect.left - padding >= infoRect.width) {
return rect.left - padding + windowPageXOffset } else {// 否則水平居中顯示return (windowWidth - infoRect.普門品全文念誦及回向儀軌width) /
2 + windowPageXOffset } };if ( rect.bottom + padding + margin + infoRect.height <= windowHeight &&
// 下方寬度可以容納 infoRect.width <= windowWidth // 信息框?qū)挾缺葹g覽器窗口小 ) {// 可以在下方顯示 left = adjustLeft()
top = rect.bottom + padding + margin + window普門品全文念誦及回向儀軌PageYOffset } elseif ( rect.top - padding - margin >= infoRect.height &&
infoRect.width <= windowWidth ) {// 可以在上方顯示 left = adjustLeft() top = rect.top - padding - margin - infoRect.height + windowPageYOffset
}// 省略后續(xù)兩個(gè)判斷 }}判斷高亮框的下方和上方的剩余空間能否容納信息框,另外還要普門品全文念誦及回向儀軌判斷一下信息框的寬度是否比瀏覽器窗口小對(duì)于信息框的水平位置,我們優(yōu)先讓它和高亮框左對(duì)齊,如果空間不夠,那么就讓信息框在瀏覽器窗口水平居中。
對(duì)于左側(cè)和右側(cè)的判斷也是類似的,完整代碼可以去文末的倉庫里查看當(dāng)上下左右四個(gè)方向都無法滿足條件時(shí),我們還可以再檢查一種情況,也就是高亮框和信息框的總高度是否比瀏覽器窗口高度小,是的話我們可以通過滾動(dòng)頁面位置來達(dá)到完整顯示的目的:。
classNoviceGuide { computeInfoPosition(step) {// ...else {// 否則檢查高亮框高度+信息框高度是否小于窗口高度let totalHeightLessThenWindow普門品全文念誦及回向儀軌 =
rect.height + padding * 2 + margin + infoRect.height <= windowHeightif ( totalHeightLessThenWindow &&
Math.max(rect.width + padding * 2, infoRect.width) <= windowWidth ) {// 上下排列可以放置// 滾動(dòng)頁面,居中顯示兩者整體
let newTop = (windowHeight - (rect.h普門品全文念誦及回向儀軌eight + padding * 2 + margin + infoRect.height)) /
2window.scrollBy(0, rect.top - newTop) } else {// 恕我無能為力// 回到默認(rèn)位置 } left = adjustLeft()
top = rect.bottom + padding + margin + windowPageYOffset }this.infoEl.style.left = left +
"px"this.infoEl.style.top = top + 普門品全文念誦及回向儀軌"px" }}如果總高度小于窗口高度,那么可以調(diào)整頁面滾動(dòng)位置,否則就不做任何處理,這兩種情況對(duì)于信息框來說,都是顯示在高亮框下方。
如果目標(biāo)元素位于可滾動(dòng)元素內(nèi)這個(gè)問題是什么意思呢,比如我們想高亮下圖中紅框內(nèi)的元素:
它所在的可滾動(dòng)父元素并不是document.body,事實(shí)上這個(gè)頁面body元素壓根無法滾動(dòng),寬高是和窗口寬高一致的,而我們的實(shí)現(xiàn)邏輯是通過滾動(dòng)body來使元素可見的,那么我們就做不到讓這個(gè)元素出現(xiàn)在視口。
解決這個(gè)問題可以這么考慮,我們先找到目標(biāo)元素的最近的可滾動(dòng)的祖先元素,如果元素不在該祖先元素的可視區(qū)域內(nèi),那么就滾動(dòng)父元素讓元素可見,當(dāng)然這樣還沒完,因?yàn)樵撟嫦仍匾部赡艽?a style="color: red;">普門品全文念誦及回向儀軌在一個(gè)可滾動(dòng)的祖先元素,它也不一定是在它的祖先元素內(nèi)可見,所以還得判斷和讓它可見,很明顯,這是一個(gè)向上遞歸的過程,一直檢查到
body元素為止先來寫一個(gè)獲取最近的可滾動(dòng)祖先元素的方法:classNoviceGuide { getScrollAncestor(el) {let style = window.getComputedStyle(el)。
const isAbsolute = style.position === absoluteconst isFixed = style.position === fixedconst reg = /(auto|scroll)/
// 如果元素是固定定普門品全文念誦及回向儀軌位,那么可滾動(dòng)祖先元素為bodyif (isFixed) returndocument.bodylet parent = el.parentElementwhile (parent) {
style = window.getComputedStyle(parent)// 如果是絕對(duì)定位,那么可滾動(dòng)的祖先元素必須是有定位的才行if (!(isAbsolute && style.position ===
static)) {// 如果某個(gè)祖先元素的overflow屬性為auto或scroll則代表是可滾動(dòng)的if (reg.test(style.overflow + style.overflowX + 普門品全文念誦及回向儀軌style.overflowY)) {
return parent } } parent = parent.parentElement }returndocument
.body }}就是不斷向上遞歸,接下來修改一下to方法,在獲取目標(biāo)元素尺寸位置信息之前先讓它可見:classNoviceGuide { to() {// ...this.scrollAncestorToElement(currentStep.element)
const rect = currentStep.element.getBo普門品全文念誦及回向儀軌undingClientRect()// ... } scrollAncestorToElement(element) {
// 獲取可滾動(dòng)的祖先元素const parent = this.getScrollAncestor(element)if (parent === document.body) return// 祖先元素和目標(biāo)元素的尺寸位置信息
let parentRect = parent.getBoundingClientRect()let rect = element.getBoundingClientRect()// 滾動(dòng)祖先元素,讓目標(biāo)元素可見
parent.scroll普門品全文念誦及回向儀軌Top = parent.scrollTop + rect.top - parentRect.top// 繼續(xù)向上遞歸this.scrollAncestorToElement(parent)
}}
結(jié)尾本文詳細(xì)的介紹了如何實(shí)現(xiàn)一個(gè)新手引導(dǎo)的功能,可能還有沒有考慮到的問題或者實(shí)現(xiàn)上的缺陷,歡迎留言指出完整代碼:https://github.com/wanglin2/simple-novice-guide。
在線示例:https://wanglin2.github.io/simple-novice-guide/往期回顧#如何使用 TypeScript 開發(fā) React 函數(shù)式組件?#11 個(gè)需要避免的 普門品全文念誦及回向儀軌React 錯(cuò)誤用法。
#6 個(gè) Vue3 開發(fā)必備的 VSCode 插件#3 款非常實(shí)用的 Node.js 版本管理工具#6 個(gè)你必須明白 Vue3 的 ref 和 reactive 問題#6 個(gè)意想不到的 JavaScript 問題
#試著換個(gè)角度理解低代碼平臺(tái)設(shè)計(jì)的本質(zhì)
回復(fù)“加群”,一起學(xué)習(xí)進(jìn)步