国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Chrome插件開發入門:如何實現一鍵上班賴皮

acrazing / 1842人閱讀

摘要:老板查崗時,一個快捷鍵,立即關閉所有賴皮頁面。上傳,發布插件。從零開始,開發簡單的一鍵賴皮插件的上班族都在使用瀏覽器賴皮,所以我們選擇采用插件來實現功能。

很多人介紹過Chrome插件,但必須要說,插件開發就是擺弄一個小玩具,第一要素是實用,其次是好玩。 單純羅列各種功能是非常無趣的。  所以把一篇舊文拿出來與大家分享。

人,活著就是為了賴皮。

作為一個合格的開發人員,把30%的時間用來賴皮(上班偷懶)是值得推薦的。

因為,如果你工作時間無法賴皮,并不能說明你工作認真,只能說明你的工作自動化程度不夠。

賴皮狗,一般會在上班時間瀏覽:SGamer論壇、虎撲論壇、斗魚、BiliBili這一類的網站。

但在瀏覽過程中會遇到以下痛點:

老板查崗,貼子或直播間打開太多,不能及時關閉全部的賴皮站點。

老板走了重新賴皮,不記得之前打開的貼子或直播間在哪里。

每次在瀏覽器里輸入賴皮網址,打字真的很麻煩!

工作時打開了太多標簽頁,休息時很難找到想要的賴皮頁面。

所以,我們需要:

簡單的一鍵賴皮插件需要怎樣的體驗:

打開瀏覽器后,一個快捷鍵,立即打開賴皮頁面,喜滋滋開始賴皮的一天。

老板/leader查崗時,一個快捷鍵,立即關閉所有賴皮頁面。

老板走后,或工作一段時間后,一個快捷鍵,立即打開原來的賴皮貼子和直播間。

簡單的一鍵賴皮插件功能:

包含簡單的一鍵賴皮站點功能

能自定義配置賴皮網站。

上傳Google,發布插件。

從零開始,開發簡單的一鍵賴皮插件

90%的上班族都在使用Chrome瀏覽器賴皮,所以我們選擇采用Chrome插件來實現功能。

Chrome插件沒什么大不了的,依然還是采用HTMLCSSJS的組合。

在這里,我將手把手帶你從零開始制作插件。

mainfest.json

就像node.js的package.json一樣,每一個插件必須有一個manifest.json,作為最初配置文件。

我們創建一個新的項目,在根目錄下創建manifest.json,填入以下代碼

==mainfest.json==

 {
  "name": "上班一鍵賴皮工具",
  "version": "0.1",
  "description": "windows:按Alt+S開啟、關閉賴皮網站
mac:按Control+S開啟、關閉賴皮網站",
  "manifest_version": 2
 }

解釋一下:

name: 插件的名字

version: 插件的版本

description: 插件簡介欄

manifest_version: 這個是寫死的,每個文件必須有

接下來請右鍵保存虎撲logo到根目錄,名字還是如apple-touch-icon.png就行吧。

也可以點擊
https://b1.hoopchina.com.cn/c... 保存圖片

修改mainfest.json,設置四個尺寸的icon都變成apple-touch-icon.png,以及插件欄也顯示apple-touch-icon.png。

==mainfest.json==

{
  "name": "上班一鍵賴皮工具",
  "version": "0.1",
  "description": "windows:按Alt+S開啟、關閉賴皮網站  
mac:按Control+S開啟、關閉賴皮網站",
  "icons": {
    "16": "apple-touch-icon.png",
    "32": "apple-touch-icon.png",
    "48": "apple-touch-icon.png",
    "128": "apple-touch-icon.png"
  },
  "browser_action": {
    "default_icon": "apple-touch-icon.png",
    "default_popup": "popup.html"
  },
  "commands": {
    "toggle-tags": {
      "suggested_key": {
        "default": "Alt+S",
        "mac": "MacCtrl+S"
      },
      "description": "Toggle Tags"
    }
  },
  "manifest_version": 2
}

解釋一下:

icons: 配置了顯示在不同地方的圖標

browser_action: 即右上角插件,browser_action > default_icon即右上角插件圖標

commands:一般用于快捷鍵命令。 commands > toggle-tags > suggested_key之下,設置了快捷鍵,只要按下快捷鍵,即會向Chrome就會向后臺發布一個command,值為toggle-tags

在windows環境下,我們將快捷鍵設置成Alt+S,在mac環境下,我們將快捷鍵設置成Control+S,配置文件中寫作MacCtrl+S

現在我們有了命令,就需要后臺腳本接收,在mainfest.json中添加后臺腳本:
==mainfest.json==

...
  "background": {
    "scripts": [
      "background.js"
    ]
  }
...

并在根目錄下創建background.js.
==background.js==

chrome.commands.onCommand.addListener(function(command) {
    alert(command)
    console.log(command)
})

現在我們的目錄結構如下:

├── manifest.json
└── background.js
└── sgamers.png
在chrome內加載插件

點擊Chorme右上角的三個點按鈕...> More Tools > Extensions

在右上角把Developer mode打開

再找到頂部的LOAD UNPACKED,把項目的根目錄導入進去

項目導入后會出現一個新的卡片,是這個效果:

這時,你如果在Windows中按下Alt+S就會彈出消息,消息為toggle-tags,正好是我們在mainfest.json中定義好的。

同時我們可以點擊上圖藍色鍵頭所指示的background page,打開一個調試工具,可以看到toggle-tags的輸出。

我們在之后本地編輯插件后,可以按灰色鍵頭所指的刷新,新功能就能立即刷新加載了!

有了這些工作,意味著你可以進入下一步了!

標簽頁配置

一鍵打開/關閉賴皮網站,實現原理其實就是chrome的標簽頁功能。

標簽頁功能訪問需要在manifest.json中添加權限
==mainfest.json==

  ...
  "permissions": ["tabs"]
  ...

接下來,我們寫一下background.js實現通過快捷鍵(windows的Alt+S,或mac的Ctrl+S)創建新的主頁:
==background.js==

// 輸入你想要的網站主頁
const MainPageUrl = "http://https://bbs.hupu.com/all-gambia"

chrome.commands.onCommand.addListener(function (command) {
  if (command === "toggle-tags") {
    chrome.tabs.create({"url": MainPageUrl, "selected": true});
  }
})

其實實現很簡單,就是調用chrome.tabs.create接口,就創建了一個新的標簽頁。
刷新一下插件,再試一試快捷鍵功能————是不是已經能控制瀏覽器彈出標簽 頁了!

實現具體邏輯:

稍顯復雜的地方是標簽頁isOpen狀態的處理,
下圖主要關注isOpen狀態的變化,以及tabCache的值變化。

具體后臺邏輯如下,可以跟據備注、對照流程圖進行理解:

//初始化isOpen和tabCache狀態
let isOpen = false
let tabCache = []

//新標簽打開的主頁
const mainPageUrl = "https://bbs.hupu.com/all-gambia"
//四個賴皮網站的正則匹配表達式
const myPattern = "sgamer.com/|douyu.com|hupu.com|bilibili.com"
//當前頁面的Url
let currentPageUrl = ""

/**
 * 開始步驟: 判斷isOpen狀態
 * 情形一:isOpen為true,則移除頁面
 * 情形二:isOpen為false,則重載頁面
 */
chrome.commands.onCommand.addListener(function (command) {
  if (command === "toggle-tags") {
    if (isOpen) {
      //情形一:isOpen為true
      removePages(myPattern)
      //情形二:isOpen為false
    } else {
      reloadPages(myPattern, mainPageUrl)
    }
  }
})


/**
 * 情形1:移除頁面
 * 1、清空tabCache緩存
 * 2、關閉所有域名內標簽
 * 3、將關閉的標簽存入tabCache緩存數組
 * 4、將isOpen狀態改為false
 */
function removePages(patternStr) {
  tabCache = []
  chrome.tabs.query({active: true}, function (tab) {
    currentPageUrl = tab[0].url
  })
  let pattern = new RegExp(patternStr)
  walkEveryTab(function (tab) {
    if (pattern.test(tab.url)) {
      chrome.tabs.remove(tab.id,function(){
        tabCache.push(tab.url)
      })
    }
  },function(){
    isOpen = false
  })
}

/**
 * 情形2:重載頁面
 * 判斷有沒有緩存:
 *    情形2-1無緩存:開啟新標簽或定位到域名內的標簽
 *    情形2-2有緩存:打開全部緩存內的頁面
 */
function reloadPages(patternStr, mainPageUrl) {
  if (tabCache.length === 0) {
    focusOrCreateTab(patternStr, mainPageUrl)
  } else {
    openAllCachedTab(tabCache)
  }
}

/**
 * 情形2-1:開啟新標簽或定位到域名內的標簽
 * 1、遍歷全部標簽,記錄符合域名的標簽的url,以及最后一個標簽頁
 * 2、如果沒有符合域名的標簽,則創建主頁,并將isOpen狀態改為true
 * 3、如果有符合域名的標簽:
 *        1、獲取當前的頁面url
 *        2、如果當前頁面url不符合域名,則定位到這個標簽頁,將isOpen狀態改為true
 *        3、如果當前頁面url符合域名,則關閉所有標簽頁(按情形1處理),將isOpen狀態改為false
 */
function focusOrCreateTab(patternStr, url) {
  let pattern = new RegExp(patternStr)
  let theTabs = []
  let theLastTab = null
  walkEveryTab(function (tab) {
      if (pattern.test(tab.url)) {
        theTabs.push(tab.url)
        theLastTab = tab
      }
    }, function () {
      if (theTabs.length > 0) {
        chrome.tabs.query({active: true}, function (tab) {
          let currentUrl = tab[0].url
          if (theTabs.indexOf(currentUrl) > -1) {
            removePages(patternStr)
            isOpen = false
          } else {
            chrome.tabs.update(theLastTab.id, {"selected": true});
            isOpen = true
          }
        })
      } else {
        chrome.tabs.create({"url": url, "selected": true});
        isOpen = true
      }
    }
  )
}

/**
 * 情形2-2:
 * 1、把tabCache所有標簽頁重新打開
 * 2、將isOpen狀態改為true
 */
function openAllCachedTab(tabCache) {
  let focusTab = null
  tabCache.forEach(function (url, index) {
    chrome.tabs.create({"url": url}, function (tab) {
      if (tab.url === currentPageUrl) {
        focusTab = tab.id
      }
      if (index === tabCache.length-1 - 1) {
        if (focusTab) {
          chrome.tabs.update(focusTab, {"selected": true},function(){
          });
        }
      }
    })
  })
  isOpen = true
}




/**
 *
 * @param callback
 * @param lastCallback
 * 包裝一下遍歷全部標簽的函數,創建兩個回調。
 * 一個回調是每一次遍歷的過程中就執行一遍。
 * 一個回調是全部遍歷完后執行一遍。
 */
function walkEveryTab(callback, lastCallback) {
  chrome.windows.getAll({"populate": true}, function (windows) {
    for (let i in windows) {
      let tabs = windows[i].tabs;
      for (let j in tabs) {
        let tab = tabs[j];
        callback(tab)
      }
    }
    if(lastCallback) lastCallback()
  })
}
上傳與發布插件

我們需要在Chrome的開發者中心發布插件,進入 Developer Dashboard

好了,一個簡單易用的上班賴皮插件做好了!在調試模式下,你可以用ctrl+s來快捷尋找、打開、關閉、重新打開賴皮頁面。隨時隨地、全方位賴皮,從容面對老板查崗。
可配置的高級賴皮插件

現在我希望我的插件都可以隨時配置站點:

那么就需要用到chrome.storage了。

你需要打開storage權限:

manifest.json內添加

...
  "permissions": [
    "tabs","storage"
  ],
...

然后使用

chrome.storage.local.set({
        "value1":theValue1,
        "value2",theValue2
})

這種形式來存放storage。
這后使用

chrome.storage.local.get(["value1"],(res)=>{
    const theValue1 = res.value1
})

這樣得到存放的value值。

開始改寫background.js

我們把mainPageUrlmyPattern改成從storage中獲取。

const INIT_SITES_LIST = ["bilibili.com","douyu.com","sgamer.com","hupu.com"]
const INIT_MAIN_PAGE = "https://bbs.hupu.com/all-gambia"

// 在安裝時即設置好storage
chrome.runtime.onInstalled.addListener(function() {
  chrome.storage.local.set({
    sites: INIT_SITES_LIST,
    mainPage:INIT_MAIN_PAGE
  })
});


//初始化isOpen和tabCache狀態
let isOpen = false
let tabCache = []
let currentPageUrl = ""

/**
 * 開始步驟: 判斷isOpen狀態
 * 情形一:isOpen為true,則移除頁面
 * 情形二:isOpen為false,則重載頁面
 */
chrome.commands.onCommand.addListener(function (command) {
  if (command === "toggle-tags") {
    chrome.storage.local.get(["sites","mainPage"],function(res){
      let sites =  res.sites
      let mainPageUrl = res.mainPage
      let myPattern = sites.map(item=>item.replace(".",".")).join("|")
      console.log(myPattern)

      if (isOpen) {
        //情形一:isOpen為true
        removePages(myPattern)
        //情形二:isOpen為false
      } else {
        reloadPages(myPattern, mainPageUrl)
      }
    })

  }
})
// ======================== 下面的部分不需要改動,看到這里就夠了)

/**
 * 情形1:移除頁面
 * 1、清空tabCache緩存
 * 2、關閉所有域名內標簽
 * 3、將關閉的標簽存入tabCache緩存數組
 * 4、將isOpen狀態改為false
 */
function removePages(patternStr) {
  tabCache = []
  chrome.tabs.query({active: true}, function (tab) {
    currentPageUrl = tab[0].url
  })
  let pattern = new RegExp(patternStr)
  walkEveryTab(function (tab) {
    if (pattern.test(tab.url)) {
      chrome.tabs.remove(tab.id,function(){
        tabCache.push(tab.url)
      })
    }
  },function(){
    isOpen = false
  })
}

/**
 * 情形2:重載頁面
 * 判斷有沒有緩存:
 *    情形2-1無緩存:開啟新標簽或定位到域名內的標簽
 *    情形2-2有緩存:打開全部緩存內的頁面
 */
function reloadPages(patternStr, mainPageUrl) {
  if (tabCache.length === 0) {
    focusOrCreateTab(patternStr, mainPageUrl)
  } else {
    openAllCachedTab(tabCache)
  }
}

/**
 * 情形2-1:開啟新標簽或定位到域名內的標簽
 * 1、遍歷全部標簽,記錄符合域名的標簽的url,以及最后一個標簽頁
 * 2、如果沒有符合域名的標簽,則創建主頁,并將isOpen狀態改為true
 * 3、如果有符合域名的標簽:
 *        1、獲取當前的頁面url
 *        2、如果當前頁面url不符合域名,則定位到這個標簽頁,將isOpen狀態改為true
 *        3、如果當前頁面url符合域名,則關閉所有標簽頁(按情形1處理),將isOpen狀態改為false
 */
function focusOrCreateTab(patternStr, url) {
  let pattern = new RegExp(patternStr)
  let theTabs = []
  let theLastTab = null
  walkEveryTab(function (tab) {
      if (pattern.test(tab.url)) {
        theTabs.push(tab.url)
        theLastTab = tab
      }
    }, function () {
      if (theTabs.length > 0) {
        chrome.tabs.query({active: true}, function (tab) {
          let currentUrl = tab[0].url
          if (theTabs.indexOf(currentUrl) > -1) {
            removePages(patternStr)
            isOpen = false
          } else {
            chrome.tabs.update(theLastTab.id, {"selected": true});
            isOpen = true
          }
        })
      } else {
        chrome.tabs.create({"url": url, "selected": true});
        isOpen = true
      }
    }
  )
}

/**
 * 情形2-2:
 * 1、把tabCache所有標簽頁重新打開
 * 2、將isOpen狀態改為true
 */
function openAllCachedTab(tabCache) {
  let focusTab = null
  tabCache.forEach(function (url, index) {
    chrome.tabs.create({"url": url}, function (tab) {
      if (tab.url === currentPageUrl) {
        focusTab = tab.id
      }
      if (index === tabCache.length-1 - 1) {
        if (focusTab) {
          chrome.tabs.update(focusTab, {"selected": true},function(){
          });
        }
      }
    })
  })
  isOpen = true
}




/**
 *
 * @param callback
 * @param lastCallback
 * 包裝一下遍歷全部標簽的函數,創建兩個回調。
 * 一個回調是每一次遍歷的過程中就執行一遍。
 * 一個回調是全部遍歷完后執行一遍。
 */
function walkEveryTab(callback, lastCallback) {
  chrome.windows.getAll({"populate": true}, function (windows) {
    for (let i in windows) {
      let tabs = windows[i].tabs;
      for (let j in tabs) {
        let tab = tabs[j];
        callback(tab)
      }
    }
    if(lastCallback) lastCallback()
  })
}


那么我們可以寫一個popup頁面,如果點擊圖標就會顯示,如圖:

下面我們完善一下popup.html和popup.css和pupup.js頁面

所有js文件都可以直接調用chrome.storage.local.get

只需要特別注意一下js文件的chrome.storage調用部分

其它的拷貝即可,我們不是來學頁面布局的

popup.html



  常用網站配置頁面
  


常用賴皮站點域名

我的賴皮主頁

Alt+S快速開啟/關閉賴皮站點

popup.css

* {
    margin: 0;
    padding: 0;
    color:#6a6f77;
}


input, button, select, textarea {
    outline: none;
    -webkit-appearance: none;
    border-radius: 0;
    border: none;
}

input:focus{
    list-style: none;
    box-shadow: none;
}

ol, ul {
    list-style: none;
}

li{
    margin: 5px 0;
}

.container {
    width: 200px;
    padding: 10px;
}

.container h2{
    margin: 10px;
    text-align: center;
    display: block;
}

.lapi-content li{
    transition: opacity 1s;
}

.site{
    cursor: pointer;
    color: #00b0ff;
}

.add, .main-page{
    box-sizing: border-box;
    text-align:center;
    font-size:14px;
    /*height:27px;*/
    border-radius:3px;
    border:1px solid #c8cccf;
    color:#6a6f77;
    outline:0;
    padding:0 10px;
    text-decoration:none;
    width: 170px;
}

#main-page{
    font-size: 12px;
    text-align: left;
    width: 166px;
    margin: 0;
    padding: 2px;
}

.add{
    height: 27px;
}

.main-page{
    width: 170px;
    outline: none;
    resize: none;

}

.main-page-inactive{
    width: 160px;
    line-break: auto;
    word-break: break-word;
    overflow: hidden;
    display: inline-block;
    cursor: pointer;
    color: #00b0ff;
    margin: 3px;
}

.button{

    font-size: 16px;
    /*border: 1px solid #c8cccf;*/
    color: #c8cccf;
    /*border: none;*/
    padding: 0 4px 1px 3px;
    border-radius: 3px;
}

.close-button{
    transition: all 1s;
}

.button:hover{
    background: #E27575;
    color: #FFF;
}

.add-button{
    transition:all 1s;
    font-size: 20px;
    padding: 0 6px 1px 5px;
}

.change-button{
    position: absolute;
    transition:all 1s;
    font-size: 20px;
    padding: 0 6px 1px 5px;
}
.change-button:hover{
    background: #f9a825;
    color: #FFF;
}

#change-check{
    color: #f9a825;
}

#change-check:hover{
    color: #fff;
}

.add-button:hover{
    background: #B8DDFF;
    color: #FFF;
}

.submit{
    transition: all 1s;
    margin: 10px;
    padding: 5px 10px;
    font-size: 16px;
    border-radius: 4px;
    background: #B8DDFF;
    border: 1px solid #B8DDFF;
    color: #FFF;
}

.submit:hover{
    border: 1px solid #B8DDFF;
    background: #fff;
    color: #B8DDFF;
}

.fade{
    opacity: 0;
}

.add-wrong,.add-wrong:focus{
    border: #e91e63 1px solid;
    box-shadow:0 0 5px rgba(233,30,99,.3);
}

.lapi-tip{
    margin-top: 20px;
    border-top: 1px solid #c8cccf;
    padding-top: 8px;
    color: #c8cccf;
    text-align: center;
}

.lapi-key{
    color: #B8DDFF;

}

重點關注:chrome.storage部分

popup.js

let sites = []
let mainPage = ""
const isMac = /Macintosh/.test(navigator.userAgent)
let $lapiKey = $(".lapi-key")

isMac? $lapiKey.text("Control+S"):$lapiKey.text("Alt+S")

// 從storage中取出site和mainPage字段,并設置在頁面上。
chrome.storage.local.get(["sites","mainPage"], function (res) {
  if (res.sites) {
    sites = res.sites
    mainPage = res.mainPage
    sites.forEach(function (item) {
      let appendEl = "
  • " + item + " " + " " + "
  • " $("ul.lapi-content").append(appendEl) }) } $("#main-page").val(mainPage) $("#main-page-inactive").html(mainPage) }) $("#save").on("click", function () { alert() }) $("#change-content").delegate("#main-page-inactive","click",function(){ let mainPageUrl = $(this).html() if(/^http://|^https:///.test(mainPageUrl)){ chrome.tabs.create({"url": mainPageUrl, "selected": true}) }else{ chrome.tabs.create({"url": "http://"+mainPageUrl, "selected": true}) } }) let addEl = $("#add") addEl.focus() let lapiCon = $("ul.lapi-content") lapiCon.delegate(".close-button", "click", function () { let $this = $(this) let siteValue = $this.siblings().html() sites = sites.filter(function (item) { return item !== siteValue }) chrome.storage.local.set({sites: sites}) $this.parent().addClass("fade") setTimeout(function () { $this.parent().remove() }, 800) }) $(".add-button").on("click",addEvent) addEl.bind("keypress",function(event){ if(event.keyCode === 13) addEvent() }) function addEvent(){ if(!validate(addEl.val())){ addEl.addClass("add-wrong") }else{ let appendEl = "
  • " + addEl.val() + " " + " " + "
  • " $("ul.lapi-content").append(appendEl) sites.push(addEl.val()) chrome.storage.local.set({sites:sites}) addEl.removeClass("add-wrong") addEl.focus().val("") } } function validate(value){ value = value.trim() if(value.length ===0){ return false } return /^([w_-]+.)*[w_-]+$/.test(value) } lapiCon.delegate(".site","click",function(){ let siteUrl = $(this).html() chrome.tabs.create({"url": "http://"+siteUrl, "selected": true}) }) $("#change-content").delegate("#change","click",function(){ changeMainPage($(this)) }).delegate("#change-check","click",function(){ changeCheck($("#change-check")) }).delegate("#main-page","blur",function(){ changeCheck($("#change-check")) }) function changeMainPage($this){ $this.siblings().remove() $this.parent().prepend("") $this.parent().append("") $("#main-page").val(mainPage).focus() $this.remove() } function changeCheck($this){ let mainPageVal = $("#main-page").val() $this.siblings().remove() $this.parent().prepend("") $("#main-page-inactive").text(mainPageVal) chrome.storage.local.set({mainPage:mainPageVal}) $this.parent().append("") }

    好了,一個優雅的賴皮插件就做好了,大家可以查看
    https://github.com/wanthering...

    祝大家上班賴得開心。 別老躲廁所玩手機了,不健康!賴皮插件用起來!

    文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

    轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100067.html

    相關文章

    • NodeJs能給前端小白帶來什么。(一)

      摘要:引子的引子第一次寫博客,本文是寫給和我一樣的小白的,大牛請謹慎食用,歡迎拍磚。是稱霸全平臺的偉大的一步,當然對于我們普通前端小白并不太關心會怎么發展,我們只想高高興興上班平平安安回家,所謂老板和我談理想,我說我的理想是不上班。 引子的引子 第一次寫博客,本文是寫給和我一樣的小白的,大牛請謹慎食用,歡迎拍磚。 引子 隨著Node.js 4.0 的發布,這次是nodejs和iojs合并后的...

      Binguner 評論0 收藏0
    • NodeJs能給前端小白帶來什么。(一)

      摘要:引子的引子第一次寫博客,本文是寫給和我一樣的小白的,大牛請謹慎食用,歡迎拍磚。是稱霸全平臺的偉大的一步,當然對于我們普通前端小白并不太關心會怎么發展,我們只想高高興興上班平平安安回家,所謂老板和我談理想,我說我的理想是不上班。 引子的引子 第一次寫博客,本文是寫給和我一樣的小白的,大牛請謹慎食用,歡迎拍磚。 引子 隨著Node.js 4.0 的發布,這次是nodejs和iojs合并后的...

      liuchengxu 評論0 收藏0
    • 7月份前端資源分享

      摘要:更多資源請文章轉自月份前端資源分享的作用數組元素隨機化排序算法實現學習筆記數組隨機排序個變態題解析上個變態題解析下中的數字前端開發筆記本過目不忘正則表達式聊一聊前端存儲那些事兒一鍵分享到各種寫給剛入門的前端工程師的前后端交互指南物聯網世界的 更多資源請Star:https://github.com/maidishike... 文章轉自:https://github.com/jsfr...

      pingan8787 評論0 收藏0

    發表評論

    0條評論

    最新活動
    閱讀需要支付1元查看
    <