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 亚洲国产精品成熟老女人,日本一区二区免费看,久久精品国产亚洲

          整合營銷服務商

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

          免費咨詢熱線:

          創(chuàng)建頁面并實現(xiàn)無刷新頁面跳轉(zhuǎn)

          創(chuàng)建頁面并實現(xiàn)無刷新頁面跳轉(zhuǎn)

          篇,你可以學到Ember頁面的創(chuàng)建,并且在不同的頁面之間跳轉(zhuǎn)。新建兩個頁面,一個是創(chuàng)建about頁面,一個是創(chuàng)建contact頁面。


          看完本篇你將學到如下知識點:

          • 定義路由
          • 使用路由模板
          • 自定義路由URL
          • 使用<LinkTo>組件在不同模板之間跳轉(zhuǎn)
          • 組件之間傳遞參數(shù)、屬性


          定義路由

          在前一篇,我們定義了一個index.hbs首頁,接著繼續(xù)在templates下面創(chuàng)建新的頁面。

          首先通過Ember CLI創(chuàng)建一個路由,

          ember g route about

          本機創(chuàng)建日志:

          ubuntuvim at ubuntuvim-mbp.local in [~/code/super-rentals]  on git:master ?  9b5a1ac "Initial Commit from Ember CLI v3.18.0"
          
          23:22:20 ? ember g route about
          
          installing route
          
            create app/routes/about.js
          
            create app/templates/about.hbs
          
          updating router
          
            add route about
          
          installing route-test
          
            create tests/unit/routes/about-test.js

          題外話:

          ubuntuvim at ubuntuvim-mbp.local in [~/code/super-rentals] on git:master ? 9b5a1ac "Initial Commit from Ember CLI v3.18.0"

          23:22:20 ?

          這一段是我本機命令行自動前綴,如果你的命令行安裝過zsh這個工具,就會很熟悉,zsh是一個非常強大而且漂亮的命令行工具。

          打開router.js,可以看到自動創(chuàng)建了一個路由this.route('about');


          使用路由模板

          修改about路由模板文件app/templates/about.hbs,在文件內(nèi)添加一下HTML內(nèi)容。

          {{!-- app/templates/about.hbs --}}
          
          <div class="jumbo">
            <div class="right tomster"></div>
            <h2>About Super Rentals</h2>
            <p>
              The Super Rentals website is a delightful project created to explore Ember.
              By building a property rental site, we can simultaneously imagine traveling
              AND building Ember applications.
            </p>
          </div>

          瀏覽器訪問驗證:http://localhost:4200/about。可以看到about頁面的內(nèi)容


          使用同樣的方式創(chuàng)建contact路由。

          ubuntuvim at ubuntuvim-mbp.local in [~/code/super-rentals]  on git:master ?  9b5a1ac "Initial Commit from Ember CLI v3.18.0"
          
          23:22:37 ? ember g route contact
          
          installing route
          
            create app/routes/contact.js
          
            create app/templates/contact.hbs
          
          updating router
          
            add route contact
          
          installing route-test
          
            create tests/unit/routes/contact-test.js

          在contact.hbs添加一些HTML內(nèi)容。

          {{!-- app/templates/contact.hbs --}}
          <div class="jumbo">
            <div class="right tomster"></div>
            <h2>Contact Us</h2>
            <p>
              Super Rentals Representatives would love to help you<br>
              choose a destination or answer any questions you may have.
            </p>
            <address>
              Super Rentals HQ
              <p>
                1212 Test Address Avenue<br>
                Testington, OR 97233
              </p>
              <a href="tel:503.555.1212">+1 (503) 555-1212</a><br>
              <a href="mailto:superrentalsrep@emberjs.com">superrentalsrep@emberjs.com</a>
            </address>
          </div>

          瀏覽器訪問驗證:http://localhost:4200/contact??梢钥吹絚ontact頁面的內(nèi)容


          contact1.png


          自定義路由URL

          前面已經(jīng)定義了兩個頁面,一個是about一個是contact。默認情況下訪問的路徑都是和路由同名的,另外Ember提供了非常靈活的擴展,你可以自定義的路由的訪問路徑,比如下面的代碼,把contact路由的訪問路徑改為getting-in-touch,手動修改router.js文件。

          Router.map(function() {
            this.route('about');
            this.route('contact', { path: '/getting-in-touch' });
          });

          注意看第三行,使用path屬性指定這個路由的訪問路徑為getting-in-touch

          現(xiàn)在你在訪問http://localhost:4200/contact就會發(fā)現(xiàn)報錯了,提示找不到這個路由了。


          contact2.png

          再訪問http://localhost:4200/getting-in-touch??梢钥吹巾撁娴膬?nèi)容就是之前contact的內(nèi)容。


          contact3.png


          使用<LinkTo>組件在不同模板之間跳轉(zhuǎn)

          <LinkTo>是Ember提供好的組件,用于在不同模板之間跳轉(zhuǎn),其作用類似于HTML標簽中的<a>標簽。

          為何不直接用<a>標簽而是要自定義一個跳轉(zhuǎn)的組件呢??因為使用普通的<a>標簽,當你點擊鏈接的時候會發(fā)送瀏覽器的刷新,但是Ember是單頁應用不需要刷新整個頁面,只要是實現(xiàn)頁面的跳轉(zhuǎn)即可(所謂的跳轉(zhuǎn)其實就是實現(xiàn)不同的路由之間的切換,并且不會刷新頁面)。

          繼續(xù)改造前面的創(chuàng)建的index,about和contact。分別在這兩個模板頁面中添加一個跳轉(zhuǎn)的鏈接。


          {{!-- index.hbs是 "/" 這個路徑默認的頁面。 --}}
          
          <div class="jumbo">
            <div class="right tomster"></div>
            <h2>Welcome to Super Rentals!</h2>
            <p>We hope you find exactly what you're looking for in a place to stay.</p>
            
            {{!-- 使用LinkTo組件添加一個跳轉(zhuǎn)按鈕,并且指定調(diào)整到的路由是about,也就是說當用戶點擊這按鈕的時候會跳轉(zhuǎn)到about這個子頁面上 --}}
            <LinkTo @route="about" class="button">About Us</LinkTo>
            
          
            
            <a href="/about" class="button">About Us With A Tag</a>
          </div>


          index5.png

          點擊“About Us”這個按鈕,然后看瀏覽器的地址欄,可以看到自動轉(zhuǎn)到about這個路由下,并且頁面不會刷新。為了驗證前面所說的效果,我在About Us后面添加了一個<a>標簽按鈕,當你點擊這個鏈接的時候會看到瀏覽器自動刷新了,并且也跳轉(zhuǎn)到about頁面上。


          index6.png


          繼續(xù)改造about和contact,分別添加跳轉(zhuǎn)按鈕。

          {{!-- app/templates/about.hbs --}}
          <div class="jumbo">
            <div class="right tomster"></div>
            <h2>About Super Rentals</h2>
            <p>
              The Super Rentals website is a delightful project created to explore Ember.
              By building a property rental site, we can simultaneously imagine traveling
              AND building Ember applications.
            </p>
            
            <LinkTo @route="contact" class="button">Contact Us</LinkTo>
            {{!-- 增加一個跳轉(zhuǎn)回到首頁的鏈接 --}}
            <LinkTo @route="index" class="button">Index</LinkTo>
          </div>
          {{!-- app/templates/contact.hbs --}}
          <div class="jumbo">
            <div class="right tomster"></div>
            <h2>Contact Us</h2>
            <p>
              Super Rentals Representatives would love to help you<br>
              choose a destination or answer any questions you may have.
            </p>
            <address>
              Super Rentals HQ
              <p>
                1212 Test Address Avenue<br>
                Testington, OR 97233
              </p>
              <a href="tel:503.555.1212">+1 (503) 555-1212</a><br>
              <a href="mailto:superrentalsrep@emberjs.com">superrentalsrep@emberjs.com</a>
            </address>
            
            <LinkTo @route="about" class="button">About</LinkTo>
            {{!-- 增加一個跳轉(zhuǎn)回到首頁的鏈接 --}}
            <LinkTo @route="index" class="button">Index</LinkTo>
          </div>

          在about和contact兩個頁面添加了兩個跳轉(zhuǎn)按鈕,一個是about和contact頁面的相互跳轉(zhuǎn),一個是跳轉(zhuǎn)回首頁的按鈕。


          about3.png


          contact4.png


          通過前面的這三個頁面,相信你很容易就可以掌握<LinkTo>組件的使用。其中@route屬性指定的是你定義的路由名字,這個路由的名字要和router.js里面的定義的完全一致,否則會找不到。另外需要注意的是@route屬性的值一定是路由的名字而不是URL的名字,比如contact路由,這個路由的路由名是contact而不是訪問的getting-in-touch。

          另外在<LinkTo>組件上可以使用普通的HTML屬性,比如上面使用的class屬性,這個class屬性就是普通HTML屬性,用于指定CSS樣式的。在Ember應用中,通過@符號區(qū)別是普通的HTML屬性還是Ember提供的屬性,比如上面使用的@route就是Ember提供的屬性。

          在底層,<LinkTo>組件會為我們生成一個常規(guī)的<a>標簽,并帶有針對特定路由的href。通過Ember生成的這個<a>標簽對于用戶來說非常友好,無需頁面刷新就可以實現(xiàn)跳轉(zhuǎn)。 簡單講,當單擊這些特殊鏈接之一時,Ember將攔截該單擊,呈現(xiàn)新頁面的內(nèi)容,并更新URL(所有這些操作均在本地執(zhí)行,而無需等待服務器),從而避免刷新整個頁面。

          我們開發(fā)系統(tǒng)的時候,可能會接到這樣的需求:不要讓用戶復制頁面上的文字或者圖片,不要讓用戶調(diào)試我們的頁面,更甚至也不要讓用戶進行打印操作等等。

          聽起來是不是讓人很頭大,這咋實現(xiàn)???這有必要嗎?這能禁住么?

          如果你沒做過這些,或者沒接到過這樣的需求,那你也應該看到過某個網(wǎng)站做了一些這樣的措施。

          既然要做,我們就得想方案,先來看看禁止復制都有哪些方法。

          禁止復制

          假設我們有這樣一段代碼:

          <div style="padding-left: 56px;">
            <textarea rows="5" cols="33"></textarea>
          </div>
          <pre>
            海客談瀛洲,煙濤微茫信難求,
          
            越人語天姥,云霞明滅或可睹。
          
            天姥連天向天橫,勢拔五岳掩赤城。
          
            天臺四萬八千丈,對此欲倒東南傾。
          
            我欲因之夢吳越,一夜飛度鏡湖月。
          
            湖月照我影,送我至剡溪。
            </pre>

          接下來就通過這個例子來論述我們的方案:

          x效果

          1. 通過user-select:none

          這是一個css屬性,標識了元素及其子元素的文本不可被選中,因此設定之后,文本將不能夠被選中,因此也就不能復制:

          <pre style="user-select: none;">
            海客談瀛洲,煙濤微茫信難求,
          
            越人語天姥,云霞明滅或可睹。
          
            天姥連天向天橫,勢拔五岳掩赤城。
          
            天臺四萬八千丈,對此欲倒東南傾。
          
            我欲因之夢吳越,一夜飛度鏡湖月。
          
            湖月照我影,送我至剡溪。
            </pre>

          我們在這段文本上,加上這個樣式。

          效果

          可以看到,文字壓根就不能選擇,從鼠標形狀也能看出來。

          1. 通過攔截copy操作

          由于用在進行復制操作的時候,會觸發(fā)copy事件,我們可以通過監(jiān)聽它來做一些處理,使得復制的行為發(fā)生改變:

          <div>
            <div style="padding-left: 56px;">
              <textarea rows="5" cols="33"></textarea>
            </div>
            <pre id="content">
              ??驼勫?,煙濤微茫信難求,
          
              越人語天姥,云霞明滅或可睹。
          
              天姥連天向天橫,勢拔五岳掩赤城。
          
              天臺四萬八千丈,對此欲倒東南傾。
          
              我欲因之夢吳越,一夜飛度鏡湖月。
          
              湖月照我影,送我至剡溪。
            </pre>
          </div>
          <script>
            let c=document.getElementById('content')
            c.removeEventListener("copy", copyFilter)
            c.addEventListener("copy", copyFilter)
            function copyFilter(e) {
              let cp=e.clipboardData || window.clipboardData
              if(!cp) {
                return
              }
              let text=window.getSelection().toString()
              if(text) {
                e.preventDefault()
                cp.setData("text/plain", "你復制了一段魔法")
              }
            }
          </script>

          先獲取到我們要禁止復制的元素,然后給它添加一個copy的事件監(jiān)聽,在添加監(jiān)聽之前,要先移除一下,這樣是為了避免局部刷新的時候重復添加,然后我們通過copyFilter函數(shù)來對這次操作進行處理。

          先獲取剪貼板對象,如果當前事件對象里不存在,那就從window里面取,然后我們通過getSelection再拿到選取的內(nèi)容,因為我們對剪貼板對象進行修改,所以要阻止默認行為,然后把剪貼板的內(nèi)容重新賦值,可以是示例中那樣的一段文字,也可以設置為空,甚至是任意其他內(nèi)容,然后我們就可以看到產(chǎn)生的效果了:

          效果

          雖然能復制文本,但是由于我們攔截了復制操作,更改了它的行為,因此再粘貼的時候就變成了我們更改的樣子,也做到了禁止復制的功能。

          這種方式對于使用快捷鍵或者右鍵的方式都是有效的。

          1. 通過攔截cut操作

          這種情況主要是在可編輯區(qū)域,比如文本框、文本域、設置為contenteditable的元素等,用戶可以對文字進行剪切操作,雖然上面禁止了復制,但是剪切是另一個操作,不攔截的話還是相當于能復制出來。

          copy和cut只是觸發(fā)的事件不同而已,但是它們都是執(zhí)行相同的邏輯處理:

          <div>
            <div style="padding-left: 56px;">
              <textarea rows="5" cols="33"></textarea>
            </div>
            <pre id="content" contenteditable>
              海客談瀛洲,煙濤微茫信難求,
          
              越人語天姥,云霞明滅或可睹。
          
              天姥連天向天橫,勢拔五岳掩赤城。
          
              天臺四萬八千丈,對此欲倒東南傾。
          
              我欲因之夢吳越,一夜飛度鏡湖月。
          
              湖月照我影,送我至剡溪。
            </pre>
          </div>
          <script>
            let c=document.getElementById('content')
            c.removeEventListener("cut", copyFilter)
            c.addEventListener("cut", copyFilter)
            function copyFilter(e) {
              let cp=e.clipboardData || window.clipboardData
              if(!cp) {
                return
              }
              let text=window.getSelection().toString()
              if(text) {
                e.preventDefault()
                cp.setData("text/plain", "你復制了一段魔法")
              }
            }
          </script>

          這里我為了方便,給元素添加了contenteditable屬性,讓它變成可編輯的,copyFilter函數(shù)沒有變化,我們只是添加了一個剪切事件的監(jiān)聽,然后它們的處理函數(shù)都是copyFilter。看下效果:

          效果

          可以看到,首先我們對文字進行剪切,沒有出現(xiàn)預期的效果,這時因為我們在代碼里面對剪切進行了攔截,并阻止了它的默認行為,然后我們在粘貼的時候,文字也改變成我們設置的了。

          1. 通過媒體查詢控制打印

          雖然我們可以通過上面的幾種方法禁止在頁面上復制,但是用戶也可能開啟打印預覽模式,在這種情況下,也是可以進行復制的,我們要想對打印頁面進行一些控制,那么就要用到媒體查詢,先看下打印的樣子:

          效果

          雖然我們做了限制,但是在打印頁面沒有生效,現(xiàn)在我們針對這個場景更改一下代碼:

          @media print {
            html {
              display: none;
            }
          }

          通過添加上面這個樣式規(guī)則,我們能夠使頁面在打印的時候,內(nèi)容隱藏起來,這樣就無法進行復制了:

          效果

          能夠看到,點擊打印的時候,預覽頁面一片空白,,這樣就禁止了在打印頁面進行復制的操作。當然了,你其實也可以設置其他的樣式屬性來做些控制,但要記住寫在打印的媒體查詢里面,只有這樣才會在打印頁面生效。

          1. 通過偽元素覆蓋內(nèi)容

          還有一種方式就是,通過設定一個偽元素,讓它全面覆蓋文本內(nèi)容,這樣鼠標就不能選到實際的文本,改造一下代碼:

          .content {
            position: relative;
          }
          .content::before {
            content: '';
            position: absolute;
            left: 0px;
            top: 0px;
            width: 100%;
            height: 100%;
          }
          <pre id="content" class="content">
            海客談瀛洲,煙濤微茫信難求,
          
            越人語天姥,云霞明滅或可睹。
          
            天姥連天向天橫,勢拔五岳掩赤城。
          
            天臺四萬八千丈,對此欲倒東南傾。
          
            我欲因之夢吳越,一夜飛度鏡湖月。
          
            湖月照我影,送我至剡溪。
          </pre>

          現(xiàn)在就不能在元素上面選中文字了,不過用戶也可能還有一些操作,比如在內(nèi)容區(qū)域外面ctrl+a全選,或者在外面拖動鼠標來全選,如果是這種情形,那么我們可以通過監(jiān)聽鍵盤和鼠標事件來禁止全選等操作。

          1. 通過監(jiān)聽鼠標和鍵盤事件

          由于用戶有很多種操作的方式,鍵盤全選、鼠標全選、鍵盤右鍵、鼠標右鍵等等,我們?nèi)绻F舉的話,情況太多了,因此我們只監(jiān)聽鼠標按下和抬起事件,以及鍵盤的按下事件:

          document.removeEventListener("mousedown", haveSelect)
          document.addEventListener("mousedown", haveSelect)
          document.removeEventListener("mouseup", haveSelect)
          document.addEventListener("mouseup", haveSelect)
          document.removeEventListener("keydown", haveSelect)
          document.addEventListener("keydown", haveSelect)
          function haveSelect() {
            window.getSelection().removeAllRanges()
          }

          主要就是在removeAllRanges方法上面,能夠在觸發(fā)上面事件的時候,將所選區(qū)域清空,也就是不管你選沒選,咋選的,反正就是你只要進行了操作,那我就那可能選擇的區(qū)域給你清空,這樣你就啥也干不了了。

          效果

          好,這樣就可以啦,無論怎么選,即使出現(xiàn)了選區(qū),但是只要你再按了鼠標或者鍵盤,那么選區(qū)就會直接消失,就能達到不能復制的效果,因為你發(fā)現(xiàn)啥都做不了。

          這里額外說明一下,對于事件的監(jiān)聽,一定要用addEventListener來實現(xiàn),因為它會將多個綁定的事件都添加上去,當觸發(fā)的時候就會按照綁定的順序進行執(zhí)行,如果是用賦值的方式,那么后面的會覆蓋前面的,而且賦值的方式很容易被篡改,可以很輕松的讓你的綁定函數(shù)不能執(zhí)行從而失效,而使用addEventListener就不會被人為覆蓋,只能通過綁定的函數(shù)句柄來手動移除,也就是說要移除的時候,必須使用跟綁定時使用同一個函數(shù)才行。

          通過CSS的方式禁止復制,可以很容易的被用戶解除,只能是設置的稍微復雜一點,增加難度。而通過JS的方式禁止復制,也可以通過禁用頁面JavaScript代碼來解除,因此我們可以將內(nèi)容通過js來渲染,這樣如果頁面禁用了js,那么內(nèi)容也不會渲染。

          禁止調(diào)試

          對于禁止調(diào)試,主要是指用戶打開控制臺,控制臺也就是開發(fā)者工具,我為了方便稱之為控制臺,想要對頁面進行調(diào)試時,我們做一些處理,阻止這種行為,最大可能的攔截通過控制臺對系統(tǒng)的調(diào)試。
          主要的方法有幾種,由于打開控制臺是瀏覽器提供的調(diào)試功能,因此我們沒法攔截打開操作,即使通過事件監(jiān)聽不允許快捷鍵這樣做,但是也可以通過其他方式進行打開,因此我們的主要關(guān)注點就在于打開控制臺之后,我們能做哪些事情來限制用戶行為。

          1. 禁用快捷鍵

          打開控制臺的快捷鍵主要有F12和ctrl+shift+i,我們先把這倆給禁用了:

          document.removeEventListener("keydown", disableDevShortcut)
          document.addEventListener("keydown", disableDevShortcut)
          function disableDevShortcut(e) {
            console.log(e)
            if(e.keyCode===123) {
              e.preventDefault()
            }else if(e.keyCode===73 && e.ctrlKey && e.shiftKey) {
              e.preventDefault()
            }
          }

          這樣在使用這兩個快捷鍵的時候,頁面沒有任何反應,控制臺也不會喚起,因為我們阻止了它們的默認行為。

          1. 禁用右鍵的檢查功能

          除了通過快捷鍵,還可以使用右鍵的方式,并點擊檢查也會調(diào)出控制臺。

          效果

          這種情景,我們可以通過禁止在頁面上使用右鍵的方式,來阻止打開控制臺:

          document.removeEventListener("contextmenu", cancelContextmenu)
          document.addEventListener("contextmenu", cancelContextmenu)
          function cancelContextmenu(e) {
            e.preventDefault()
          }

          現(xiàn)在就不能通過右鍵打開控制臺了,但是相應的整個右鍵功能也都不能使用了。

          1. 設置無限斷點

          如果用戶最終打開了控制臺,比如通過在瀏覽器的更多功能中來打開的話,那么我就需要采取其他的措施,其中之一就是給代碼設置無限斷點,因為斷點只在控制臺打開的時候才會發(fā)生作用,從而不必擔心非調(diào)試模式下的程序正常運行。

          無限斷點的主要思路就是利用定時器等手段,頻繁的觸發(fā)斷點效果,使得不能輕松的調(diào)試程序,先看下代碼:

          ;(()=> {
            function breakDebugger() {
              if(new checkDebugger().check) {
                breakDebugger()
              }
            }
            function checkDebugger() {
              const now=new Date();
              eval('(function () {debugger;false;})()')
              const dur=Date.now() - now
              if(dur < 5) {
                return {check: false}
              }else {
                return {check: true}
              }
            }
            setInterval(()=> {
              eval('(function () {debugger;true;})()')
              breakDebugger()
            }, 500)
          })()

          我們利用一個立即執(zhí)行的自執(zhí)行函數(shù),來使我們的代碼被封裝在一個固定塊內(nèi),不與其他部分有任何影響。

          這里主要做了兩步:

          第一步設置一個重復執(zhí)行的定時器,其中包括了一個斷點和一個函數(shù)調(diào)用。

          第二步通過函數(shù)來遞歸調(diào)用斷點,主要使用了實例化對象的方式和時間差的判斷。

          這樣做的主要作用就是在設置無限斷點的同時,也能夠讓每次的斷點都是被重新生成的,看下效果,一目了然:

          效果

          發(fā)現(xiàn)沒有,我們通過這種方式,只要打開了控制臺,那么就會進入到無限斷點的循環(huán)中,使得不能做任何其他事情,而且每個斷點的生成都會開辟一個新的虛擬運行環(huán)境,這種情況下,只有關(guān)閉控制臺,才能結(jié)束斷點。

          即使使用右鍵選擇Never parse here,也毫無作用,雖然可以通過Deactive breakpoints按鈕來徹底禁用斷點,就是下面這個按鈕:

          按鈕

          但是,如果這樣做的話,那么用戶也就同時失去了調(diào)試其他代碼的能力。

          況且,我們接下來還會介紹其他的控制手段,可以配合著使用。

          1. 監(jiān)測控制臺開啟

          我們?nèi)绻苡幸环N手段,可以知道用戶開啟了控制臺,換句話說只要控制臺被打開,就通知我們或者被我們監(jiān)測到,那么我們就可以執(zhí)行一些控制手段,這種效果肯定是很理想的,遺憾的是還沒有這種api暴露給我們?nèi)プ屛覀兡軌蜻@樣做。

          不過我們可以通過其他的方式,利用既有的一些能力來實現(xiàn)這一點,這里我還是使用循環(huán)定時器,來不斷的去嗅探用戶是否開啟了控制臺,直接看代碼:

          ;(()=> {
            setInterval(function() {
              let foo=document.createElement('a')
              let a1=+new Date()
              console.table(foo)
              let a2=+new Date()
              if(a2 - a1 > 1) {
                location.href='about:blank'
              }
              console.clear()
            }, 500)
          })()

          同樣,通過一個自執(zhí)行函數(shù),我們開啟了一個循環(huán)定時器,然后在回調(diào)方法里面,我們就去實現(xiàn)上面的目標,也是分為了兩步:

          第一步創(chuàng)建一個a元素,然后通過表格的形式將它打印出來,并記錄下消耗的時間。

          第二步判斷耗時的長短來控制是否跳轉(zhuǎn)到空白頁,然后清空控制臺。

          這種方式主要是利用了console.table的特性,它會將元素以表格的形式輸出到控制臺,大概就像下面的樣子:

          效果

          由于太多了,我就沒有全部截下來,如果沒有打開控制臺的話,使用console.table輸出我們創(chuàng)建的a標簽是很快的,有多快呢,就是js執(zhí)行一條語句的速度,所以打印a1和a2的時間間隔非常短,幾乎為0,因為他們快到差不多是同時執(zhí)行的,給大家打印看一下:

          效果

          我們先不打開控制臺,等輸出完畢再打開,很清楚的發(fā)現(xiàn),我們沒打開控制臺的時候,輸出的a就是它標簽,而且時間間隔是0毫秒。

          現(xiàn)在我們打開控制臺的時候刷新一下頁面,看看控制臺的輸出:

          效果

          這次就變成了以table的形式輸出a元素,而且它的耗時明顯增多,不再是0毫秒,而是耗費了10毫秒,雖然打開控制臺的時候多次刷新頁面,每次輸出的毫秒數(shù)是不同的,但是跟關(guān)閉控制臺的時候輸出的耗時差距非常明顯,因此我們就可以在這個上面做文章。

          我在上面的代碼中假定了,只要是大于1毫秒的耗時,那就表示用戶打開了控制臺,然后我們就把頁面給跳轉(zhuǎn)到空白頁,當然了你也可以做一些任何你想做的操作,比如彈出一個提示,或者把body內(nèi)容置空等等等等。

          回到我們上面的代碼,看一下它實際發(fā)生的作用和帶給我們的效果:

          效果

          哈哈,古德古德,平時瀏覽一切正常,只要剛一打開控制臺,瞬間頁面就被跳轉(zhuǎn)走了,什么都干不了。這樣我們就通過這種方式,達到了限制打開控制臺的目的,也就是在當前頁沒法調(diào)試,一打開就跳轉(zhuǎn)。

          這種辦法由于是繞路實現(xiàn)的,那么你可能會有疑問,它穩(wěn)定嗎?會不會誤判,我可以對它絕對放心嗎?

          理論上來說,通過輸出的執(zhí)行時間是不太能精確掌握的,但是我們可以再做一些其他的措施來逼近真相:

          ;(()=> {
            setInterval(function() {
              let foo=document.createElement('a')
              let a1=+new Date()
              console.table(foo)
              let a2=+new Date()
              if(a2 - a1 > 1) {
                let time=0
                for(let i=0; i < 10; i++) {
                  let a1=+new Date()
                  console.table(foo)
                  let a2=+new Date()
                  time +=a2 - a1
                }
                if(time > 20) {
                  location.href='about:blank'
                }
              }
              console.clear()
            }, 500)
          })()

          我又改造了一下判斷的邏輯,當發(fā)現(xiàn)輸出耗時為2毫秒甚至更多的時候,我立馬再進行一次真?zhèn)闻袛?,也就是說,萬一由于其他的影響,導致我第7行的代碼誤判了,那么我再同步執(zhí)行一個循環(huán),連續(xù)輸出10次,把他們的耗時總和計算出來,然后判斷是否大于20毫秒,如果還是耗時過高的話,那么就可以非??隙ǖ闹烙脩羰谴蜷_了控制臺,這個時候就可以放心的做一些處理了。

          最后

          其實限制用戶行為的方法有很多很多,上面列出了一些主要的,多種方法還是要結(jié)合著使用。你也可以自由發(fā)揮,多使用一些其他的手段,也會增加用戶復制或者調(diào)試的難度,比如防止用戶重寫console的方法,或者清除所有定時器等。

          甚至也可以將你的內(nèi)容繪制到canvas上面來防止復制,多加一些js的處理工作,防止禁用js的時候,我們的代碼不生效,只有在js可用的時候再去渲染內(nèi)容等。也可以在綜合考慮的情況下加上代碼混淆、代碼加密等措施。

          話說回來,大家都是同路人,何必相互為難,哈哈哈,不過提這個需求的人也著實會為難我們,既然提了那就盡力去做,能做到什么程度,只能說是盡量做到極致。

          希望上面的內(nèi)容能夠幫助到你,也希望能夠?qū)δ阌兴鶈l(fā)。

          謝謝

          51rgb

          網(wǎng)頁自動跳轉(zhuǎn)頁面的代碼在很多時候都非常的有用,下面的是兩個簡單的例子。僅供參考。

          方案一,用<meta>里直接寫刷新語句:

          <html>

          <head>

          <meta http-equiv="Content-Language" content="zh-CN">

          <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312">

          <meta http-equiv="refresh" content="5;url=http://www.51rgb.com">

          <title>html網(wǎng)頁自動跳轉(zhuǎn)代碼--西農(nóng)大網(wǎng)站</title>

          </head>

          <body>

          測試:html網(wǎng)頁自動跳轉(zhuǎn)代碼<br/>

          你可以在這里寫下你想的一切東西!<br />

          如:西北農(nóng)林科技大學是一所985、211院校。<br />

          </body></html>

          方案二,用javascript腳本來跳轉(zhuǎn)

          <html><head>

          <meta http-equiv="Content-Type" content="text/html; charset=gb2312">

          <title>正在進入西農(nóng)大網(wǎng)站</title>

          </head>

          <body>

          <form name=loading>

          <p align=center> <font color="#0066ff" size="2">正在進入,請稍等</font><font color="#0066ff" size="2" face="Arial">...</font>

          <input type=text name=chart size=46 style="font-family:Arial; font-weight:bolder; color:#0066ff; background-color:#fef4d9; padding:0px; border-style:none;">

          <inputtype=text name=percent size=47 style="color:#0066ff; text-align:center; border-width:medium; border-style:none;">

          <script>

          var bar=0

          var line="||"

          var amount="||"

          count

          function count{

          bar=bar+2

          amount=amount + line

          document.loading.chart.value=amount

          document.loading.percent.value=bar+"%"

          if (bar<99)

          {setTimeout("count",100);}

          else

          {window.location=http://www.51rgb.com;}

          }</script>

          </p>

          </form><p align="center">

          測試:html網(wǎng)頁自動跳轉(zhuǎn)代碼<br/>

          你可以在這里寫下你想的一切東西!<br />

          如:西北農(nóng)林科技大學是一所985、211院校。<br /><br />

          如果您的瀏覽器不支持跳轉(zhuǎn),<astyle="text-decoration: none" ><font color="#FF0000">請點這里</font></a>.</p>

          </body>

          </html>

          ↓↓↓


          主站蜘蛛池模板: 国产高清在线精品一区小说| 高清国产AV一区二区三区| 久久久久久人妻一区二区三区| 国产成人精品视频一区二区不卡| 一夲道无码人妻精品一区二区| 日本不卡一区二区视频a| 91精品国产一区二区三区左线| 99精品国产一区二区三区不卡| 无码人妻精品一区二区三区99性| 日韩一区二区三区免费体验| 一区二区三区杨幂在线观看| 亚洲AV美女一区二区三区| 无码国产精品一区二区免费式直播 | 影院成人区精品一区二区婷婷丽春院影视| 精品久久久久久无码中文字幕一区| 国产在线精品一区在线观看| 中文字幕一区日韩在线视频| 色噜噜狠狠一区二区| 精品免费AV一区二区三区| 亚洲av无码一区二区三区不卡 | 国产高清视频一区三区| 亚洲高清一区二区三区| 无码日韩人妻AV一区二区三区| 久久一区二区明星换脸| 国产精品免费综合一区视频| 亚洲国产综合无码一区| 久久精品日韩一区国产二区| 国产乱码伦精品一区二区三区麻豆| 久久精品一区二区三区日韩| 精品国产一区二区二三区在线观看 | 亚洲性日韩精品国产一区二区| 人妻无码第一区二区三区| 精品在线视频一区| 亚洲精品日韩一区二区小说| 清纯唯美经典一区二区| 日本福利一区二区| 69福利视频一区二区| 中文字幕一区二区三区免费视频| 中文乱码字幕高清一区二区 | 精品香蕉一区二区三区| 亚洲日韩精品一区二区三区无码 |