Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 亚洲国产精品91,91高清在线观看,好男人视频社区精品免费

          整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          HTML代碼中的空格和空行

          子1:(文本內(nèi)容中的連續(xù)空格)

          <p>這段文本中,輸入連續(xù)的空格          大概輸入了十個。</p>

          顯示效果:“格”和“大” 之間的是個空格顯示出來只是一個空格。

          這段文本中,輸入連續(xù)的空格 大概輸入了十個。

          例子2:(代碼之間的連續(xù)空格)

          <span>span是一個行內(nèi)標簽</span>               <span>和前面的span元素之間隔了很多個空格</span>

          顯示效果:兩個span元素之間連續(xù)的空格,顯示出來即"簽"與“和”之間的空格,只有一個空格。

          span是一個行內(nèi)標簽 和前面的span元素之間隔了很多個空格

          上面兩個例子證明:HTML代碼中連續(xù)的空格在顯示時會顯示為一個空格,其余的多余的空格會被移除或者說被忽略。

          段落文本其實也是HTML代碼的一部分,只不過它在p標簽內(nèi)部,而例子2的空格是在兩個span標簽之間。


          理解了空格,現(xiàn)在看看空行,同理

          例子3:(文本內(nèi)容中的空行)

          <p>這段文本中,輸入連續(xù)的空行
          
          
          
          
          
          大概輸入了五行。</p>

          顯示效果:如我們所見,文本代碼中的五行空行,顯示出來也只是一個空格。

          這段文本中,輸入連續(xù)的空行 大概輸入了五行。

          例子4:(元素之間/標簽之間的空行),只要把例子2中的空格換成空行就可以了,顯示效果和例子2的一樣,多行空行都只會顯示為一個空格。

          <span>span是一個行內(nèi)標簽</span>
          
          
          
          
          
          <span>和前面的span元素之間隔了很多空行</span>


          span是一個行內(nèi)標簽 和前面的span元素之間隔了很多空行

          得證:HTML 代碼中的所有連續(xù)的空格或空行(換行)都會被顯示為一個空格。


          既然如此,如果我們希望擴大兩個字符之間的間距,讓代碼中的連續(xù)空格或空行顯示出來的結(jié)果也是連續(xù)的空格或空行,那該怎么辦?其實很簡單。

          方法一:我們可以用預(yù)格式化標簽<pre>,無論是空格或空行都適用。

          <pre>
          這是
          預(yù)格式文本。
          它保留了      空格
          和換行。
          </pre>

          顯示效果

          這是
          預(yù)格式文本。
          它保留了      空格
          和換行。


          方法二:我們可以用空格實體符 代替空格,用換行標簽<br/>代替空行。雖然這種方法可以得到我們想要的顯示效果,但是對搜索引擎不是最友好的方式,因為 和<br/>在HTML中都是沒有語義的。所以建議盡量少用。另外需要注意的是, 必須小寫,而且最后面的分號是不能省略的。


          方法三:(適合空格)使用全角空格

          全角空格被解釋為漢字,所以不會被被解釋為HTML分隔符,可以按照實際的空格數(shù)顯示。

          問題:怎么使用全角輸入法?

          以搜狗輸入法為例,我們通常使用的是半角輸入,其狀態(tài)欄中有個月亮的標志,就說明正在使用的是半角輸入,如果是太陽的標志,就說明使用的是全角輸入。全角/半角的切換可以通過點擊標志,也可以通過快捷鍵 Shift+Space(空格符)切換。

          半角輸入(月亮)

          全角輸入(太陽)

          方法四:使用CSS樣式中字間隔屬性控制,CSS中的word-spacing 屬性可以改變字(單詞)之間的標準間隔。我們知道英文中兩個單詞之間是通過空格隔開的,所以我們視覺上可以這樣認為,word-spacing改變了(拉長或縮短)單詞之間那個空格的寬度。

          方法五:使用CSS樣式中的white-space 屬性,這個屬性聲明如何處理元素內(nèi)的空白符。

          描述

          normal

          默認。空白會被瀏覽器忽略。

          pre

          空白會被瀏覽器保留。其行為方式類似 HTML 中的 <pre> 標簽。

          nowrap

          文本不會換行,文本會在在同一行上繼續(xù),直到遇到 <br> 標簽為止。

          pre-wrap

          保留空白符序列,但是正常地進行換行。

          pre-line

          合并空白符序列,但是保留換行符。


          white-space:normal;就是正常,和不設(shè)置一樣,連續(xù)空格和空行都只會顯示一個空格。

          white-space:nowrap;不換行是什么意思呢?正常情況下,當(dāng)我們的文本超出了文本域,文本就會自動折行,這個設(shè)置就是說不自動折行了,而是碰到換行標簽<br />才換

          white-space:pre;和方法一相同,將文本原樣輸出顯示。當(dāng)文本超出文本域時,不換行,會產(chǎn)生滾動條。

          white-space:pre-wrap;保留空格和空行,但當(dāng)文本超出文本域時,會自動換行。

          white-space:pre-line;連續(xù)的空格會顯示為一個空格,但保留連續(xù)的空行。

          S 鼠標框選(頁面選擇)時返回對應(yīng)的 HTML 或文案內(nèi)容

          一、需求背景

          1、項目需求

          當(dāng)用戶進行鼠標框選選擇了頁面上的內(nèi)容時,把選擇的內(nèi)容進行上報。

          2、需求解析

          雖然這需求就一句話的事,但是很顯然,沒那么簡單...

          因為鼠標框選說起來簡單,就是選擇的內(nèi)容,但是這包含很多中情況,比如:只選擇文案、選擇圖片、選擇輸入框、輸入框中的內(nèi)容選擇、iframe、等。

          簡單總結(jié),分為以下幾點:

          1. 選擇文案時
          2. 選擇圖片、svg、iframe、video、audio 等標簽時
          3. 選擇 input、select、textarea 等標簽時
          4. 選擇 input、textarea 標簽內(nèi)容時
          5. 選擇類似 字符時
          6. 鍵盤全選時
          7. 鼠標右鍵選擇
          8. 以上各模塊結(jié)合時
          9. 當(dāng)包含標簽的時候,返回 html 結(jié)構(gòu),只有文本時返回文本內(nèi)容

          二、技術(shù)要點

          鼠標框選包含以下幾點:

          1. debounce 防抖
          2. addEventListener 事件監(jiān)聽
          3. Range 對象
          4. Selection 對象

          1、debounce

          老生常談的技術(shù)點了,這里不能用節(jié)流,因為肯定不能你鼠標選擇的時候,隔一段時間返回一段內(nèi)容,肯定是選擇之后一起返回。

          這里用 debounce 主要也是用在事件監(jiān)聽和事件處理上。

          • 【debounce 掘金】
          • 【debounce CSDN】

          2、addEventListener

          事件監(jiān)聽,因為鼠標選擇,不僅僅是鼠標按下到鼠標抬起,還包括雙擊、右鍵、全選。

          需要使用事件監(jiān)聽對事件作處理。

          • 【addEventListener MDN】

          3、Range

          Range 接口表示一個包含節(jié)點與文本節(jié)點的一部分的文檔片段。

          Range 是瀏覽器原生的對象。

          3.1. 創(chuàng)建 Range 實例,并設(shè)置起始位置

          <body>
            <ul>
              <li>Vite</li>
              <li>Vue</li>
              <li>React</li>
              <li>VitePress</li>
              <li>NaiveUI</li>
            </ul>
          </body>
          <script>
            // 創(chuàng)建 Range 對象
            const range = new Range()
            const liDoms = document.querySelectorAll("li");
            // Range 起始位置在 li 2
            range.setStartBefore(liDoms[1]);
            // Range 結(jié)束位置在 li 3
            range.setEndAfter(liDoms[2]);
            // 獲取 selection 對象
            const selection = window.getSelection();
            // 添加光標選擇的范圍
            selection.addRange(range);
          </script>


          可以看到,選擇內(nèi)容為第二行和第三行

          3.1.1 瀏覽器兼容情況


          3.2. Range 屬性

          1. startContainer:起始節(jié)點。
          2. startOffset:起始節(jié)點偏移量。
          3. endContainer:結(jié)束節(jié)點。
          4. endOffset:結(jié)束節(jié)點偏移量。
          5. collapsed:范圍的開始和結(jié)束是否為同一點。
          6. commonAncestorContainer:返回完整包含 startContainer 和 endContainer 的最深一級的節(jié)點。

          3.2.1. 用我們上面創(chuàng)建的實例來看下 range 屬性的值


          3.2.2. 如果我們只選擇文本內(nèi)容時

          只選擇 li 中的 itePres


          可以看出 range 屬性對應(yīng)的值


          3.3. Range 方法

          1. cloneContents():復(fù)制范圍內(nèi)容,并將復(fù)制的內(nèi)容作為 DocumentFragment 返回。
          2. cloneRange():創(chuàng)建一個具有相同起點/終點的新范圍, 非引用,可以隨意改變,不會影響另一方。
          3. collapse(toStart):如果 toStart=true 則設(shè)置 end=start,否則設(shè)置 start=end,從而折疊范圍。
          4. compareBoundaryPoints(how, sourceRange):兩個范圍邊界點進行比較,返回一個數(shù)字 -1、0、1。
          5. comparePoint(referenceNode, offset):返回-1、0、1具體取決于 是 referenceNode 在 之前、相同還是之后。
          6. createContextualFragment(tagString):返回一個 DocumentFragment。
          7. deleteContents():刪除框選的內(nèi)容。
          8. extractContents():從文檔中刪除范圍內(nèi)容,并將刪除的內(nèi)容作為 DocumentFragment 返回。
          9. getBoundingClientRect():和 dom 一樣,返回 DOMRect 對象。
          10. getClientRects():返回可迭代的對象序列 DOMRect。
          11. insertNode(node):在范圍的起始處將 node 插入文檔。
          12. intersectsNode(referenceNode):判斷與給定的 node 是否相交。
          13. selectNode(node):設(shè)置范圍以選擇整個 node。
          14. selectNodeContents(node):設(shè)置范圍以選擇整個 node 的內(nèi)容。
          15. setStart(startNode, startOffset):設(shè)置起點。
          16. setEnd(endNode, endOffset):設(shè)置終點。
          17. setStartBefore(node):將起點設(shè)置在 node 前面。
          18. setStartAfter(node):將起點設(shè)置在 node 后面。
          19. setEndBefore(node):將終點設(shè)置為 node 前面。
          20. setEndAfter(node):將終點設(shè)置為 node 后面。
          21. surroundContents(node):使用 node 將所選范圍內(nèi)容包裹起來。

          3.4. 創(chuàng)建 Range 的方法

          3.4.1. Document.createRange

          const range = document.createRange();

          3.4.2. Selection 的 getRangeAt() 方法

          const range = window.getSelection().getRangeAt(0)

          3.4.3. caretRangeFromPoint() 方法

          if (document.caretRangeFromPoint) {
              range = document.caretRangeFromPoint(e.clientX, e.clientY);
          }

          3.4.4. Range() 構(gòu)造函數(shù)

          const range = new Range()

          3.5. Range 兼容性


          4、Selection

          Selection 對象表示用戶選擇的文本范圍或插入符號的當(dāng)前位置。它代表頁面中的文本選區(qū),可能橫跨多個元素。

          4.1. 獲取文本對象

          window.getSelection()



          4.2. Selection 術(shù)語

          4.2.1. 錨點 (anchor)

          錨指的是一個選區(qū)的起始點(不同于 HTML 中的錨點鏈接)。當(dāng)我們使用鼠標框選一個區(qū)域的時候,錨點就是我們鼠標按下瞬間的那個點。在用戶拖動鼠標時,錨點是不會變的。

          4.2.2. 焦點 (focus)

          選區(qū)的焦點是該選區(qū)的終點,當(dāng)你用鼠標框選一個選區(qū)的時候,焦點是你的鼠標松開瞬間所記錄的那個點。隨著用戶拖動鼠標,焦點的位置會隨著改變。

          4.2.3. 范圍 (range)

          范圍指的是文檔中連續(xù)的一部分。一個范圍包括整個節(jié)點,也可以包含節(jié)點的一部分,例如文本節(jié)點的一部分。用戶通常下只能選擇一個范圍,但是有的時候用戶也有可能選擇多個范圍。

          4.2.4. 可編輯元素 (editing host)

          一個用戶可編輯的元素(例如一個使用 contenteditable 的 HTML 元素,或是在啟用了 designMode 的 Document 的子元素)。

          4.3. Selection 的屬性

          首先要清楚,選擇的起點稱為錨點(anchor),終點稱為焦點(focus)。

          1. anchorNode:選擇的起始節(jié)點。
          2. anchorOffset:選擇開始的 anchorNode 中的偏移量。
          3. focusNode:選擇的結(jié)束節(jié)點。
          4. focusOffset:選擇開始處 focusNode 的偏移量。
          5. isCollapsed:如果未選擇任何內(nèi)容(空范圍)或不存在,則為 true。
          6. rangeCount:選擇中的范圍數(shù),之前說過,除 Firefox 外,其他瀏覽器最多為1。
          7. type:類型:None、Caret、Range

          4.4. Selection 方法

          1. addRange(range): 將一個 Range 對象添加到當(dāng)前選區(qū)。
          2. collapse(node, offset): 將選區(qū)折疊到指定的節(jié)點和偏移位置。
          3. collapseToEnd(): 將選區(qū)折疊到當(dāng)前選區(qū)的末尾。
          4. collapseToStart(): 將選區(qū)折疊到當(dāng)前選區(qū)的起始位置。
          5. containsNode(node, partlyContained): 判斷選區(qū)是否包含指定的節(jié)點,可以選擇是否部分包含。
          6. deleteFromDocument(): 從文檔中刪除選區(qū)內(nèi)容。
          7. empty(): 從選區(qū)中移除所有范圍(同 `removeAllRanges()``,已廢棄)。
          8. extend(node, offset): 將選區(qū)的焦點節(jié)點擴展到指定的節(jié)點和偏移位置。
          9. getRangeAt(index): 返回選區(qū)中指定索引處的 Range 對象。
          10. removeAllRanges(): 移除所有選區(qū)中的范圍。
          11. removeRange(range): 從選區(qū)中移除指定的 Range 對象。
          12. selectAllChildren(node): 選中指定節(jié)點的所有子節(jié)點。
          13. setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset): 設(shè)置選區(qū)的起始和結(jié)束節(jié)點及偏移位置。
          14. setPosition(node, offset):collapse 的別名

          4.5. Selection 兼容性


          三、項目實現(xiàn)

          1、實現(xiàn)思路

          1. 先獲取選擇的內(nèi)容,開發(fā) getSelectContent 函數(shù)
          2. 對獲取的內(nèi)容進行判斷,是否存在 selection 實例,沒有直接返回 null
          3. 判斷 selection 實例的 isCollapsed 屬性 沒有選中,對 selection 進行 toString().trim() 操作,判斷內(nèi)容 有內(nèi)容,直接返回 text 類型 無內(nèi)容,返回 null 有選中,則判斷內(nèi)容
          4. 判斷選中的內(nèi)容有沒有節(jié)點 沒有節(jié)點,則和沒有選中一樣處理,進行 toString().trim() 操作,判斷內(nèi)容 有內(nèi)容,直接返回 text 類型 無內(nèi)容,返回 null 有節(jié)點,進行 toString().trim() 操作,判斷內(nèi)容 沒有內(nèi)容,判斷是否有特殊節(jié)點 有 'iframe', 'svg', 'img', 'audio', 'video' 節(jié)點,返回 html 類型 有 'input', 'textarea', 'select',判斷 value 值,是否存在 存在:返回 html 類型 不存在:返回 null 沒有特殊節(jié)點,返回 null 有內(nèi)容,返回 html 類型
          5. 對鼠標 mousedown、mouseup 事件和 selectionchange、contextmenu、dblclick 事件進行監(jiān)聽,觸發(fā) getSelectContent 函數(shù)
          6. 在需要的地方進行 debounce 防抖處理

          2、簡易流程圖


          2、Debounce 方法實現(xiàn)

          2.1. JS

          function debounce (fn, time = 500) {
            let timeout = null; // 創(chuàng)建一個標記用來存放定時器的返回值
            return function () {
              clearTimeout(timeout) // 每當(dāng)觸發(fā)時,把前一個 定時器 clear 掉
              timeout = setTimeout(() => { // 創(chuàng)建一個新的 定時器,并賦值給 timeout
                fn.apply(this, arguments)
              }, time)
            }
          }

          2.2. TS

          /**
           * debounce 函數(shù)類型
           */
          type DebouncedFunction<F extends (...args: any[]) => any> = (...args: Parameters<F>) => void
          /**
           * debounce 防抖函數(shù)
           * @param {Function} func 函數(shù)
           * @param {number} wait 等待時間
           * @param {false} immediate 是否立即執(zhí)行
           * @returns {DebouncedFunction}
           */
          function debounce<F extends (...args: any[]) => any>(
            func: F,
            wait = 500,
            immediate = false
          ): DebouncedFunction<F> {
            let timeout: ReturnType<typeof setTimeout> | null
            return function (this: ThisParameterType<F>, ...args: Parameters<F>) {
              // eslint-disable-next-line @typescript-eslint/no-this-alias
              const context = this
              const later = function () {
                timeout = null
                if (!immediate) {
                  func.apply(context, args)
                }
              }
              const callNow = immediate && !timeout
              if (timeout) {
                clearTimeout(timeout)
              }
              timeout = setTimeout(later, wait)
              if (callNow) {
                func.apply(context, args)
              }
            }
          }

          3、獲取選擇的文本/html 元素

          3.1. 獲取文本/html 元素

          nterface IGetSelectContentProps {
            type: 'html' | 'text'
            content: string
          }
          /**
           * 獲取選擇的內(nèi)容
           * @returns {null | IGetSelectContentProps} 返回選擇的內(nèi)容
           */
          const getSelectContent = (): null | IGetSelectContentProps => {
            const selection = window.getSelection()
            if (selection) {
              // 1. 是焦點在 input 輸入框
              // 2. 沒有選中
              // 3. 選擇的是輸入框
              if (selection.isCollapsed) {
                return selection.toString().trim().length
                  ? {
                      type: 'text',
                      content: selection.toString().trim()
                    }
                  : null
              }
              // 獲取選擇范圍
              const range = selection.getRangeAt(0)
              // 獲取選擇內(nèi)容
              const rangeClone = range.cloneContents()
              // 判斷選擇內(nèi)容里面有沒有節(jié)點
              if (rangeClone.childElementCount > 0) {
                // 創(chuàng)建 div 標簽
                const container = document.createElement('div')
                // div 標簽 append 復(fù)制節(jié)點
                container.appendChild(rangeClone)
                // 如果復(fù)制的內(nèi)容長度為 0
                if (!selection.toString().trim().length) {
                  // 判斷是否有選擇特殊節(jié)點
                  const isSpNode = hasSpNode(container)
                  return isSpNode
                    ? {
                        type: 'html',
                        content: container.innerHTML
                      }
                    : null
                }
                return {
                  type: 'html',
                  content: container.innerHTML
                }
              } else {
                return selection.toString().trim().length
                  ? {
                      type: 'text',
                      content: selection.toString().trim()
                    }
                  : null
              }
            } else {
              return null
            }
          }
          /**
           * 判斷是否包含特殊元素
           * @param {Element} parent 父元素
           * @returns {boolean} 是否包含特殊元素
           */
          const hasSpNode = (parent: Element): boolean => {
            const nodeNameList = ['iframe', 'svg', 'img', 'audio', 'video']
            const inpList = ['input', 'textarea', 'select']
            return Array.from(parent.children).some((node) => {
              if (nodeNameList.includes(node.nodeName.toLocaleLowerCase())) return true
              if (
                inpList.includes(node.nodeName.toLocaleLowerCase()) &&
                (node as HTMLInputElement).value.trim().length
              )
                return true
              if (node.children) {
                return hasSpNode(node)
              }
              return false
            })
          }

          3.2. 只需要文本

          /**
           * 獲取框選的文案內(nèi)容
           * @returns {string} 返回框選的內(nèi)容
           */
          const getSelectTextContent = (): string => {
            const selection = window.getSelection()
            return selection?.toString().trim() || ''
          }

          4、添加事件監(jiān)聽

          // 是否時鼠標點擊動作
          let selectionchangeMouseTrack: boolean = false
          const selectionChangeFun = debounce(() => {
            const selectContent = getSelectContent()
            console.log('selectContent', selectContent)
            // todo... 處理上報
            selectionchangeMouseTrack = false
          })
          // 添加 mousedown 監(jiān)聽事件
          document.addEventListener('mousedown', () => {
            selectionchangeMouseTrack = true
          })
          // 添加 mouseup 監(jiān)聽事件
          document.addEventListener(
            'mouseup',
            debounce(() => {
              selectionChangeFun()
            }, 100)
          )
          // 添加 selectionchange 監(jiān)聽事件
          document.addEventListener(
            'selectionchange',
            debounce(() => {
              if (selectionchangeMouseTrack) return
              selectionChangeFun()
            })
          )
          // 添加 dblclick 監(jiān)聽事件
          document.addEventListener('dblclick', () => {
            selectionChangeFun()
          })
          // 添加 contextmenu 監(jiān)聽事件
          document.addEventListener(
            'contextmenu',
            debounce(() => {
              selectionChangeFun()
            })
          )

          也可以進行封裝

          /**
           * addEventlistener function 類型
           */
          export interface IEventHandlerProps {
            [eventName: string]: EventListenerOrEventListenerObject
          }
          
          let selectionchangeMouseTrack: boolean = false
          const eventHandlers: IEventHandlerProps = {
            // 鼠標 down 事件
            mousedown: () => {
              selectionchangeMouseTrack = true
            },
            // 鼠標 up 事件
            mouseup: debounce(() => selectionChangeFun(), 100),
            // 選擇事件
            selectionchange:  debounce(() => {
              if (selectionchangeMouseTrack) return
              selectionChangeFun()
            }),
            // 雙擊事件
            dblclick: () => selectionChangeFun(),
            // 右鍵事件
            contextmenu: debounce(() => selectionChangeFun())
          }
          Object.keys(eventHandlers).forEach((event) => {
            document.addEventListener(event, eventHandlers[event])
          })

          5、返回內(nèi)容

          5.1. 純文本內(nèi)容


          5.2. html 格式


          6. 完整 JS 代碼

          function debounce (fn, time = 500) {
            let timeout = null; // 創(chuàng)建一個標記用來存放定時器的返回值
            return function () {
              clearTimeout(timeout) // 每當(dāng)觸發(fā)時,把前一個 定時器 clear 掉
              timeout = setTimeout(() => { // 創(chuàng)建一個新的 定時器,并賦值給 timeout
                fn.apply(this, arguments)
              }, time)
            }
          }
          
          let selectionchangeMouseTrack = false
          document.addEventListener('mousedown', (e) => {
            selectionchangeMouseTrack = true
            console.log('mousedown', e)
          })
          document.addEventListener('mouseup', debounce((e) => {
            console.log('mouseup', e)
            selectionChangeFun()
          }, 100))
          document.addEventListener('selectionchange', debounce((e) => {
            console.log('selectionchange', e)
            if (selectionchangeMouseTrack) return
            selectionChangeFun()
          }))
          document.addEventListener('dblclick', (e) => {
            console.log('dblclick', e)
            selectionChangeFun()
          })
          document.addEventListener('contextmenu',debounce(() => {
            selectionChangeFun()
          }))
          
          const selectionChangeFun = debounce(() => {
            const selectContent = getSelectContent()
            selectionchangeMouseTrack = false
            console.log('selectContent', selectContent)
          })
          
          const getSelectContent = () => {
            const selection = window.getSelection();
            if (selection) {
              // 1. 是焦點在 input 輸入框
              // 2. 沒有選中
              // 3. 選擇的是輸入框
              if (selection.isCollapsed) {
                return selection.toString().trim().length ? {
                  type: 'text',
                  content: selection.toString().trim()
                } : null
              }
              // 獲取選擇范圍
              const range = selection.getRangeAt(0);
              // 獲取選擇內(nèi)容
              const rangeClone = range.cloneContents()
              // 判斷選擇內(nèi)容里面有沒有節(jié)點
              if (rangeClone.childElementCount > 0) {
                const container = document.createElement('div');
                container.appendChild(rangeClone);
                if (!selection.toString().trim().length) {
                  const hasSpNode = getSpNode(container)
                  return hasSpNode ? {
                    type: 'html',
                    content: container.innerHTML
                  } : null
                }
                return {
                  type: 'html',
                  content: container.innerHTML
                }
              } else {
                return selection.toString().trim().length ? {
                  type: 'text',
                  content: selection.toString().trim()
                } : null
              }
            } else {
              return null
            }
          }
          
          const getSpNode = (parent) => {
            const nodeNameList = ['iframe', 'svg', 'img', 'audio', 'video']
            const inpList = ['input', 'textarea', 'select']
            return Array.from(parent.children).some((node) => {
              if (nodeNameList.includes(node.nodeName.toLocaleLowerCase())) return true
              if (inpList.includes(node.nodeName.toLocaleLowerCase()) && node.value.trim().length) return true
              if (node.children) {
                return getSpNode(node)
              }
              return false
            })
          }

          四、總結(jié)

          1. 鼠標框選上報能監(jiān)控用戶在頁面的行為,能為后續(xù)的數(shù)據(jù)分析等提供便利
          2. 基于 JS 中的 Selection 和 Range 實現(xiàn)的,使用原生 JS
          3. 涉及到的操作比較多,包含鍵盤、鼠標右鍵、全選等
          4. 能對框選的內(nèi)容進行分類,區(qū)別 html 和 text,更方便的看出用戶選擇了哪些內(nèi)容

          接上文

          上面我們做到了這一步

          第三步

          將標題居中

          需要新學(xué)一個屬性:

          align 屬性規(guī)定內(nèi)容的水平對齊方式。

          align 屬性有3個值:

          當(dāng) align="center" 的時候,就是居中對齊內(nèi)容;當(dāng) align="left" 的時候,就是左對齊內(nèi)容;當(dāng) align="right" 的時候,就是右對齊內(nèi)容。

          在 <h1>、<p> 標簽中添加 align 屬性,如下:

          <h1 align="center">俄媒盤點三大性價較高的度假勝地</h2>
          	<p align="center"><font size="2" color="#545454">2020-08-20 00:02:38 來源:環(huán)球時報</font></p>


          標題居中對齊了

          總結(jié):align的值:center:居中;left:左對齊;right:右對齊。

          第四步

          在標題下面有一條橫線,我們可以用 <hr/> 這個單標簽實現(xiàn):

          <hr> 標簽用于在 HTML 頁面中創(chuàng)建一條水平線


          再加入 <hr/> 后可以看到,只需要一個 <hr/> 即可在瀏覽器中顯示一條水平線,這就是單標簽和雙標簽區(qū)別,它只需要一個。不僅如此,我們還可以定義這條橫線的長短、粗細、顏色。

          可以試試看在 <hr/> 里面加入以下內(nèi)容:

          <hr size="2" width=200px color="red"/>

          中間紅色的線就是加屬性后的<hr/>

          size:規(guī)定 hr 元素的厚度;width:規(guī)定 hr 元素的寬度(px是像素的意思,例如100px是100像素); color:規(guī)定 hr 元素呈現(xiàn)的顏色。

          第五步

          最后一步,把文字寫進<p>標簽里面

          <p>世界上有許多美麗的國家,去那里旅游無需辦理繁瑣的證件手續(xù),而且還可以欣賞到不一樣的風(fēng)景。 俄羅斯“健康生活網(wǎng)”與旅游門戶網(wǎng)站“摩登門”為大家推薦一些經(jīng)濟實惠、性價比比較高的旅游國度,讓大家好好暢游一番。
          	</p>
          	<p>1.亞美尼亞</p>
          <p>2.黑山共和國</p>
          <p>3.摩洛哥</p>


          細心的你可能會發(fā)現(xiàn),為什么成品圖3個國家名字的行高間隔很小,而上面的行高卻間隔很大

          這時我們需要認識一個新標簽<br/>

          <br/> 可以插入一個換行符,它與<p>標簽區(qū)別是:<p>標簽在換行時,還會在相鄰的段落之間插入一些垂直的行間距(行高)。這個標簽和上面的<hr/>同樣屬于單標簽。

          所以我們稍微修改一下,并加入顏色:

          <p><font color="#f00">1.亞美尼亞<br/>2.黑山共和國<br/>3.摩洛哥</font></p>


          完全一樣了

          以下是完整html代碼:


          END

          你學(xué)到了<h1> - <h6>標簽、<font>標簽、<!--注釋-->、align 屬性、<hr/>標簽、<br/>標簽。

          你已經(jīng)能自己做出一個簡單的網(wǎng)頁了。


          主站蜘蛛池模板: 中文字幕色AV一区二区三区| 中文字幕一区在线观看| 亚洲国产一区二区视频网站| 精品人妻一区二区三区毛片| 国产怡春院无码一区二区| 中文字幕日本精品一区二区三区| 欧美日韩精品一区二区在线视频 | 精品一区二区三区中文字幕| 国产精品成人免费一区二区| 亚洲视频免费一区| 91福利一区二区| 亚洲Av高清一区二区三区| 日韩精品无码一区二区三区免费| 岛国精品一区免费视频在线观看| 国产乱码伦精品一区二区三区麻豆| 国产在线一区二区三区av| 久久一区二区三区精华液使用方法 | 精品无码国产一区二区三区51安| 亚洲AV本道一区二区三区四区| 精品久久久久一区二区三区| 精品视频一区二区三区四区五区| 亚洲一区二区三区无码影院| www亚洲精品少妇裸乳一区二区 | 在线精品亚洲一区二区小说| 国产情侣一区二区三区| 久久成人国产精品一区二区| 久久婷婷色综合一区二区| 久久久人妻精品无码一区| 国产成人片视频一区二区| 国产美女口爆吞精一区二区| 中文字幕AV一区中文字幕天堂| 亚洲国产成人一区二区三区| 99精品一区二区免费视频| 自拍日韩亚洲一区在线| 成人精品一区久久久久| 国产伦精品一区二区三区视频金莲| 亚洲一区二区三区无码中文字幕| 无码人妻精品一区二区在线视频 | 爆乳无码AV一区二区三区| 国产在线不卡一区| 国产成人精品无码一区二区三区|