通過鏈接如何找到指定位置

  • 2019 年 11 月 7 日
  • 筆記

通過鏈接如何找到指定位置

現在有一個需求,就是通過鏈接調到指定頁面的位置,不然就得不同鏈接不同頁面,那樣工作量大之外,還太浪費。於是決定在一個頁面中,通過鏈接跳到指定位置。需要跟github的效果一樣

github

通過上面的github圖,可以看出幾個基本需求

  • 跳轉時攜帶id,自動跳轉到指定位置
  • 被選中的元素具有 focus 效果
  • 被選中的元素具體頂部有一段距離
  • 點擊 document 時,清除選中效果,同時路由上刪除id
  • 點擊瀏覽器回退按鈕,可以出現新進入時的效果

開啟挖掘之旅

鑒於上面的需求,通過hash(錨點)是可以簡單實現上面的要求,個人當然希望能用瀏覽器及css解決的,就盡量解決,若是不行只能通過js來儘可能模擬出想要的效果。

在此,我們需要惡補2個知識點

地址欄改變,頁面不刷新不滾動 介紹

通過github的效果,我們知道地址欄是改變了,但是視覺上確實沒有感到有任何一樣(除了focus效果消失)。

通過historyreplaceState便可以實現上述效果

// 記錄第一次的值  const firstTop = document.scrollingElement.scrollTop  // 清空hash  window.location.hash = ""  // 地址欄刷新不跳轉  window.history.replaceState(null, null, window.location.pathname + window.location.search)  // 再回滾之前的位置  document.scrollingElement.scrollTop = firstTop

github的程式碼 github

鄙人的程式碼沒有那麼全面,但是原理是一樣的

至此頁面刷新不跳轉便算完成了

利用hash進行定位

利用錨點進行定位

html

<a href="./base.html#two" class="header">two</a>    > base.html    <div class="wide segment" id="two">    <h2>two</h2>    <div class="sc">      <div class="ui placeholder fluid active inverted">        <div class="image header">          <div class="line"></div>          <div class="line"></div>          <div class="line"></div>          <div class="line"></div>        </div>      </div>    </div>  </div>

css

.wide {    padding: 20px;    border: 1px solid #333;  }    .wide .sc {    padding: 20px;    border: 1px solid transparent;  }    .wide:target .sc {    border: 1px solid red;    box-shadow: 0 0 0 .2em pink;  }

js

 // 鏈接改變頁面不刷新  const changeUrl = () => {    const firstTop = document.scrollingElement.scrollTop    window.location.hash = ""    window.history.replaceState(null, null, window.location.pathname + window.location.search)    document.scrollingElement.scrollTop = firstTop  }  /**    * @description: 若是通過鏈接進入當前頁面,最好使用 `one`    * 如此事件只執行一次即可    */  $(document).on('click', function () {    changeUrl()  })

效果圖
hash

通過上面的方式,便可以完成基本需求,但是有幾點需要探討一下

  • 定位的盒子無法設置距離頂部多高,完全由錨點說的算了
  • 如果攜帶了?v=1類似參數,錨點便完全失效了

針對上面遺留的問題,使用js進行改版

鑒於使用js,那就需要完全按上面的需求,進行js訂製化,需要一個一個完成方可。

  • 滾動到指定位置
  • 選中效果
  • 瀏覽器回退時需要恢復focus效果
  • 攜帶參數依舊有錨點效果

code開啟

html

<a href="./update.html#one" class="header">one</a>  // 攜帶參數  <a href="./update.html#two?v=1" class="header">two?v=1</a>    > update.html  <div class="wide " id="one">    <h2>one</h2>    <div class="sc">      <div class="ui placeholder fluid">        <div class="image header">          <div class="line"></div>          <div class="line"></div>          <div class="line"></div>          <div class="line"></div>        </div>      </div>    </div>  </div>  <div class="wide " id="two">    <h2>two</h2>    <div class="sc">      <div class="ui placeholder fluid">        <div class="image header">          <div class="line"></div>          <div class="line"></div>          <div class="line"></div>          <div class="line"></div>        </div>      </div>    </div>  </div>

css

.wide .sc {    padding: 20px;    border: 1px solid transparent;  }  .wide.target .sc,  .wide:target .sc {    border: 1px solid red;    box-shadow: 0 0 0 .2em pink;  }

js

/**    * @description: 通過url獲取對應元素    * @return: node    */  const getEl = () => {    const urlId = location.href.split('#')[1]    if (!urlId) return null    return document.getElementById(urlId.replace(/?.*/, ''))  }  /**    * @description: 初始進入頁面跳轉到指定位置,同時生成focus效果    */  const elScroll = () => {    const el = getEl()    if (!el) return    $(el).addClass('target')    // 此處用來獲取需要滾動的位置    const scrollY = el.getBoundingClientRect().top + document.scrollingElement.scrollTop - 40    $(document.scrollingElement).scrollTop(scrollY)  }  /**    * @description: 監聽地址欄hash值變化    */  const listenHashChange = () => {    window.addEventListener('hashchange', () => {      elScroll()    }, false)  }  /**    * @description: 地址欄改變頁面不刷新    */  const changeUrl = () => {    // 移除選中效果    getEl() && $(getEl()).removeClass('target')    const firstTop = document.scrollingElement.scrollTop    window.location.hash = ""    window.history.replaceState(null, null, window.location.pathname + window.location.search)    document.scrollingElement.scrollTop = firstTop  }

效果圖

  • 不攜帶參數
    no-has-params

  • 攜帶參數
    has-params

至此,基本完成想要的需求

效果頁面鏈接

總結

  • 項目地址link
  • Google瀏覽器會記住默認位置 link,但使用了該方法
    javascript {highlight=2} if ('scrollRestoration' in history) { history.scrollRestoration = 'manual'; }
    會與原始錨點方案有衝突

  • 滾動到指定位置,可以通過scrollIntoView來實現,只是依舊跟錨點存在同樣的問題,無法設置距離頂部的位置
  • 對於獲取scrollTop=0值的想法,可以通過getBoundingClientRect來進行處理

不足之處

  • 使用js方案,前後的滾動可以看出來,而是用錨點模式較好,若是不考慮設置距離頂部的高度,個人更加偏向於兩者進行處理(通過是否攜帶參數來進行判斷)

參考鏈接