我們現在在使用v-for的時候、都必須會加上一個必要的key值,并且很多人會使用index來作為key,其實這樣是不太妥當的一種做法。那么v-for中的鍵值key到底有什么作用呢。請看:
當 Vue 正在更新使用 v-for 渲染的元素列表時,它默認使用“就地更新”的策略。如果數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序,而是就地更新每個元素,并且確保它們在每個索引位置正確渲染。這個類似 Vue 1.x 的 track-by="$index"。
這個默認的模式是高效的,但是只適用于不依賴子組件狀態或臨時 DOM 狀態 (例如:表單輸入值) 的列表渲染輸出。
為了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 key attribute:
-
<div v-for="item in items" v-bind:key="item.id">
-
<!-- 內容 -->
-
</div>
建議盡可能在使用 v-for 時提供 key attribute,除非遍歷輸出的 DOM 內容非常簡單,或者是刻意依賴默認行為以獲取性能上的提升。
-
<div v-for="(item,index) in list" :key="index"> {{item.name}}</div>
-
list: [
-
{
-
id: 1,
-
name: "name1",
-
},
-
{
-
id: 2,
-
name: "name2",
-
},
-
{
-
id: 3,
-
name: "name3",
-
}
-
]
這個場景如何我們不佳key vue 回直接報錯,所以大部分人都會使用index作為key的值
如果我們在添加一個數據
-
-
list: [
-
{
-
id: 1,
-
name: "name1",
-
},
-
{
-
id: 2,
-
name: "name2",
-
},
-
{
-
id: 3,
-
name: "name3",
-
},
-
{
-
id: 4,
-
name: "last",
-
},
-
]
此時前面3條數據直接服用之前的,新渲染最后一條數據,此時index作為key沒有任何問題
如何我們在中間添加一條
-
list: [
-
{
-
id: 1,
-
name: "name1",
-
},
-
{
-
id: 2,
-
name: "name2",
-
}, {
-
id: 4,
-
name: "last",
-
},
-
{
-
id: 3,
-
name: "name3",
-
}
-
]
此時我們更新渲染的數據 通過index 定義key 進行數據對比一下
之前的數據:
中間插入之后的數據 :
由此可以發現除了第一條數據可以復用以為其余的3條數據都是需要重新渲染,因為key的值發生了變化。
這個時候就可以體現出一個效率的問題,只插入一條數據,卻要從新渲染3條數據
所以我們需要可以想辦法讓數組中不會變化的數據的key值也不變,所以不能通過index來設置key值,應該設置一個唯一的id來標識數據的唯一性;我們修改之后再來對比一下渲染的效率:
之前的數據:
<div v-for="(item,index) in list" :key="item.id"> {{item.name}}</div>
中間插入之后的數據:
對此對比發現,只有一條數據發生改變,因為其他數據的id 都沒有變、所以對應的key也沒有發生改變。我們只需要渲染這一條新的數據就可以。 所以一般推薦使用id作為key值配合v-for使用
Vue
很大的一個特點就是雙向數據綁定,數據一旦改變,那么頁面就渲染新的數據呈現在頁面上。但是對于用v-for
渲染的列表數據來說,數據量可能一般很龐大,而且我們經常還要對這個數據進行一些增刪改操作,而key
的出現就是盡可能的回避這個問題,提高效率,如果我們給列表增加了一條數據,頁面只渲染了這數據。
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
var arr = [2,3,4,2,34,21,1,12,3,4,1] for(var i =0;i<arr.length;i++){ //第一層:每次循環拿到arr中一個元素 for(var j=i+1;j<arr.length;j++){ //第二層:每次拿到的元素再和每次拿到的元素后邊的元素依次進行比對(因為第一個要從第二個開始比,第二個要從第三個比以此類推,所以這里的j應比i大1為j=i+1) if(arr[i] === arr[j]){ //如果相同就刪除后邊的元素 arr.splice(j,1) } } } //arr:[1, 2, 3, 4, 12, 21, 34]
創建新數組,循環舊數組,看每次循環的元素是否存在于新數組中沒有就把當前元素添加到新數組中
//indexof var arr = [2,3,4,2,34,21,1,12,3,4,1] var arr2 = [] arr.forEach((e)=>{ if(arr2.indexOf(e)==-1){ arr2.push(e) } }) console.log(arr2) //arr2:[1, 2, 3, 4, 12, 21, 34]
//includes var arr = [2,3,4,2,34,21,1,12,3,4,1] var arr2 = [] arr.forEach((e)=>{ if(!arr2.includes(e)){ arr2.push(e) } }) console.log(arr2) //arr2:[1, 2, 3, 4, 12, 21, 34]
var arr = [2,3,4,2,34,21,1,12,3,4,1] var obj = {}; arr.forEach((e,i)=>{ obj[arr[i]] = "abc"; }); var arr2=Object.keys(obj) console.log(arr2) //arr2:["1", "2", "3", "4", "12", "21", "34"] var arr3 = arr2.map(e => ~~e ) //arr3:[1, 2, 3, 4, 12, 21, 34] //注意這種方法不僅給數組重新排列而且還改變了數組中元素的類型
~是js里的按位取反操作符,~~就是執行兩次按位取反,其實就是保持原值,但是注意雖然是原值,但是對布爾型變量執行這個操作,會轉化成相應的數值型變量,也就是 ~~true === 1,~~false === 0。
ES6 提供了新的數據結構 Set。它類似于數組,但是成員的值都是唯一的,沒有重復的值。
var arr = [2,3,4,2,34,21,1,12,3,4,1] var arr1 = [...new Set(arr)] console.log(arr1) //arr1:[1, 2, 3, 4, 12, 21, 34]
注:indexOf在數組中找元素的時候,碰到符合條件的第一個就會把它的下標返回
var arr = [2,3,4,2,34,21,1,12,3,4,1] var arr2 = arr.filter((e,i)=>{ //看每次循環的元素在數組中出現的第一個下標位置(indexOf返回的位置),和每次循環的元素的下標(filter循環每次的i)是否一致,一致就說明他就是第一個符合條件,不會被過濾掉。 return arr.indexOf(e)==i; }) console.log(arr2) //arr2:[1, 2, 3, 4, 12, 21, 34]
var arr = [2,3,4,2,34,21,1,12,3,4,1] var arr2 = arr.reduce((pre,e)=>{ //這里當然也可以用indexOf來判斷是否存在 pre.includes(e)?pre:pre.push(e); return pre },[]) console.log(arr2) //arr2:[1, 2, 3, 4, 12, 21, 34]
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
本節課程教大家如何講智能合約部署到conflux公鏈上,首先大家可以看到下面的這個智能合約是不是很簡單。我們將會以這個合約演示部署到conflux公鏈的過程。
pragma solidity ^0.5.0;
contract Counter {
uint public count=0;
event SelfEvent(address indexed sender, uint current);
constructor() public {
} function inc(uint num) public returns (uint){ return count += num;
} function self() public {
emit SelfEvent(msg.sender, count);
}
} 復制代碼
我們使用js-conflux-sdk作為本教程的web教程,交互首先我們需要進行安裝nodejs作為我們的運行環境。飛機票一張收下吧,我們安裝好nodejs后,就可以來玩我們的sdk了。廢話不多說,直接開始擼。
我們使用WIN + R鍵打開命令行,然后創建一個文件夾(溫馨提示切換到非系統盤玩切換方式“D:”就切換到D盤了)使用“mkdir my-project && cd my-project” 創建好項目后自動進入文件夾,然后我們運行“npm init” 進行初始化node項目,這一步會讓你確認一些東西,如果你是小白一路回車(Enter鍵)就好。如果你是前端大神,我也沒啥好教的我也不太懂。為了穩定我們使用固定版本號方式安裝依賴,我們運行 “npm install js-conflux-sdk@0.9.2” 命令進行安裝js-conflux-sdk的0.9.2版本依賴(可以使用“npm uninstall package-name” 命令刪除對應依賴)。前置準備到這里基本已經完成。
下面請看我的目錄結構跟隨我一起來學習,下面的目錄結構請不要直接看到了就創建,因為你不知道都是什么意思,看玩我的解釋在回頭創建。
小伙伴應該已經發現了 node_modules、package-lock.json、package.json 這些文件是我們在進行安裝 sdk依賴時自動生成的。其他文件目前都沒有,我們來按順序生成他們。
先創建sol這個文件夾,然后創建這三個文件。test.sol就是上面我們的合約代碼直接拷入文件中。abi.json和code.json兩個文件是通過這個工具 remix 在線生成的。我來說下生成過程。 首先我們將里面的文件全部刪除,然后點擊這里找到我們的項目目錄下的test.sol 文件
我們應該看到下方我框出來的兩個按鈕了吧,那兩個按鈕就是abi.json和code.json文件的來源。abi.json我們可以直接復制過去,code.json文件我們要改點東西。
首先我們看到的code文件應該是這樣的
{ "linkReferences": {}, "object": "608060405260...c63430005110032", "opcodes": "PUSH1 0x80 PUSH1 ... 1100 ORIGIN ", "sourceMap": "27:337:0 ... 37;;;;;;" } 復制代碼
代碼有省略,太長不好看,我們看到object這個key值了吧,我們把它的值考出來然后在頭部加0x 就好了放在code.json文件中。code.js文件中只存放object的內容前面加0x,也就是下面的代碼,其他信息都不要,千萬記住了。這點很重要?。。。?
"0x608060405260...c63430005110032" 復制代碼
就是這樣的。然后我們在寫另外兩個call和deploy兩個文件
先寫deploy文件
// 私鑰地址
const PRIVATE_KEY = '0x20f9169d40801955faada641cdb029f8e42c581c0c991a62753c736a0a168e5e';
// 合約地址
const CONTRACT = '';
const { Conflux } = require('js-conflux-sdk');
async function main() {
const cfx = new Conflux({
url: 'http://mainnet-jsonrpc.conflux-chain.org:12537',
defaultGasPrice: 100,
defaultGas: 1000000,
});
const account = cfx.Account(PRIVATE_KEY); // create account instance
console.log(account.address);
// create contract instance
const contract = cfx.Contract({
abi: require('./sol/RC20.abi.json'),
bytecode: require('./sol/RC20.code.json'),
});
const receipt = await contract.constructor()
.sendTransaction({ from: account })
.confirmed();
console.log(receipt.contractCreated);
}
main().catch(e => console.error(e)); 復制代碼
打開項目cmd窗口在上面的目錄下 運行命令 “node deploy.js”就將合約部署上去了
receipt.contractCreated 這個會打印出合約地址。
作者:悠悠_15832013094
鏈接:https://juejin.im/post/5ef563f75188252e99702335
來源:掘金
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
對本教程有任何疑問或建議可以在 GitHub 給我們留言。
Conflux DApp 開發教程將使用 Conflux Studio 在 Oceanus 網絡下開發一個簡單的代幣應用 Coin。
通過這個開發教程,你將會學習到如何進行 Conflux 智能合約的編寫、調用,配置智能合約的代付以及如何使用 Web 前端項目與智能合約進行交互,從而實現一個包含前端和智能合約的完整的 DApp。
在閱讀教程中遇到任何問題,歡迎在 Issues 中向我們反饋。
請在 GitHub 下載頁面下載 Conflux Studio。目前 Conflux Studio 支持 macOS 和 Linux 系統,請根據系統下載對應的版本。
正確安裝 Conflux Studio 并初次啟動后,Conflux Studio 將顯示歡迎頁面,根據提示完成 Docker, Conflux Node 以及 Conflux Truffle 的下載、安裝及啟動。
完成所有的安裝步驟后,首先需要創建鑰匙對來完成后續的合約部署以及調用。
在 Conflux Studio 的任意界面,點擊應用左下?的鑰匙圖標,打開密鑰管理器。點擊 Create 按鈕打開新鑰匙對彈窗,輸入鑰匙對的名字并點擊 Save 按鈕。完成后將在密鑰管理器中看到剛剛生成的鑰匙對的地址。鑰匙對由私鑰和公鑰組成,公鑰在智能合約中也常被稱作地址。
導出私鑰可以通過點擊每個地址后面的眼睛按鈕打開查看私鑰彈窗,彈窗顯示地址以及私鑰。后續教程中會需要通過管理器導出私鑰。
為了順利完成教程,首先需要創建三個鑰匙對:
minter_key
用于 Coin 合約部署時的簽名,是這個教程中最常使用的鑰匙對
receiver_key
用于 Coin 合約接收轉賬,將在后文中介紹轉賬時用到
sponsor_key
用于 Coin 合約代付功能,將在后文中介紹代付功能時用到
教程將在 Oceanus 網絡進行合約的部署以及合約的調用。點擊頂部 Network 標簽的倒三角打開下拉菜單,點擊選擇 Oceanus 網絡進行切換。
切換完成后,可以在主頁面中看到當前網絡為 oceanus。頁面左邊包括了當前網絡的節點 URL,Chain ID,TPS 信息,頁面右邊包含了當前網絡區塊的信息。
點擊頂部 Explorer 標簽打開區塊瀏覽器,并在地址欄粘貼鑰匙對地址,可以在左邊看到當前地址的 CFX 余額信息。
在區塊鏈的世界中,大家通常將申請測試 Token 的方式稱為 faucet,目前在 Oceanus 網絡下每次 faucet 申請到的 Token 為 100 CFX。
獲取 CFX 的方式有兩種方式:
https://wallet.confluxscan.io/faucet/dev/ask?address={address}
來申請 CFX
使用上述方法在 Conflux Studio 中為 minter_key
和 sponsor_key
申請 CFX Token。完成申請后,這兩個賬戶上的余額將會從 0 CFX 更新為 100 CFX。
目前余額信息為:
minter_key
余額 100 CFX
receiver_key
余額 0 CFX
sponsor_key
余額 100 CFX
點擊頂部左邊的 Project 標簽切換至項目列表頁面,點擊頁面中的 New 按鈕打開項目創建窗口,輸入項目的名稱并選擇 coin 模版,點擊 Create Project 完成項目的創建。
Coin 合約是一個簡單的代幣合約,其中:
Conflux 智能合約使用 Solidity 語言進行開發,打開目錄下的 contracts/Coin.sol
文件,這個是本項目的核心代碼:
// 指定了 Solidity 的版本,通過 Pragmas(https://solidity.readthedocs.io/en/latest/layout-of-source-files.html#pragmas) 告訴編譯器本代碼可以兼容的版本為 0.5.0 到 0.7.0
pragma solidity >=0.5.0 <0.7.0;
// 導入 SponsorWhitelistControl 合約
import "./SponsorWhitelistControl.sol";
// 定義 Coin 的合約
contract Coin {
// 定義了兩個 State Variables(https://solidity.readthedocs.io/en/latest/structure-of-a-contract.html#state-variables)
address public minter;
mapping (address => uint) private balances;
// 使用 SponsorWhitelistControl 合約連接系統合約
SponsorWhitelistControl constant private SPONSOR = SponsorWhitelistControl(address(0x0888000000000000000000000000000000000001));
// 定義了 `Sent` 的事件,定義了 from / to / amount 列
event Sent(address from, address to, uint amount);
// Coin 合約的 constructor ,在 constructor 中指定了 minter 的地址
constructor() public {
// msg.sender 為部署合約時簽名的賬戶地址,將這個地址賦值給 minter
minter = msg.sender;
}
// 定義 mint 方法,通過此方法來增發代幣
function mint(address receiver, uint amount) public {
require(msg.sender == minter);
require(amount < 1e60);
balances[receiver] += amount;
}
// 定義 send 方法,通過此方法可以給別的賬戶轉賬代幣
function send(address receiver, uint amount) public {
require(amount <= balances[msg.sender], "Insufficient balance.");
balances[msg.sender] -= amount;
balances[receiver] += amount;
// 通過 emit 觸發 Sent 事件,記錄這筆轉賬的信息
emit Sent(msg.sender, receiver, amount);
}
// 定義 balanceOf 方法,這是個 view 類型的方法,用于查詢賬戶余額
function balanceOf(address tokenOwner) public view returns(uint balance){
return balances[tokenOwner];
}
// 定義了 add_privilege 方法,調用系統合約 add_privilege 方法添加地址到代付白名單
function add_privilege(address account) public payable {
address[] memory a = new address[](1);
a[0] = account;
SPONSOR.add_privilege(a);
}
// 定義了 remove_privilege 方法,調用系統合約 remove_privilege 從合約代付白名單中移除地址
function remove_privilege(address account) public payable {
address[] memory a = new address[](1);
a[0] = account;
SPONSOR.remove_privilege(a);
}
}
點擊工具欄的 Build 按鈕進行合約的編譯,編譯的結果將會保存在 build/Coin.json
文件中。
在部署合約前,首先需要確認在 Explorer 中選擇合約部署所使用的地址,Conflux Studio 會使用這個地址將部署合約這筆交易進行簽名(選擇的方法為在 Explorer 的地址欄中輸入地址)。在合約代碼的 constructor
中,minter
被賦值為 msg.sender
,這個 msg.sender
就是 Explorer 所選擇的地址。
在此我們選擇 minter_key
作為部署合約的簽名者。
點擊工具欄的部署按鈕進行部署,部署完成后,部署結果會在 deploys
的 JSON 文件中,在這個文件中可以在 contractCreated
中找到當前合約部署的地址,后文中使用 contract_addr
來代表這個合約地址。
點擊頂部的 Contract 標簽切換至合約頁面,在地址欄輸入 contract_addr
地址并加載合約。
合約頁面由三個部分組成:
點擊合約調用的下拉菜單中選擇 mint 方法,在下方的參數區域分別填入以下信息:
minter_key
地址
msg.sender
獲取到這個地址。填入 minter_key
地址
填寫完成后點擊執行按鈕,Conflux Studio 將自動構造交易并推送到網絡中。成功執行后可以在下方 Result 中看到這筆成功的交易。
點擊查詢區域的下拉菜單并且選擇 balanceOf 方法,這是在代碼中定義的查詢方法。在下方的 tokenOwner 填入 minter_key
地址并點擊執行,就可以在下方的 Result 中看到 minter_key
賬戶的 Coin 代幣的余額信息為 1000。使用同樣方法可以查詢到 receiver_key
賬戶的代幣余額為 0。
在合約調用區域選擇 send 方法,在 Parameters 中分別填入:
receiver_key
地址
minter_key
地址,
點擊執行完成轉賬,再次查詢代幣余額可以看到 minter_key
賬戶只剩下 800 代幣,而 receiver_key
賬戶則從 0 變成了 200 代幣。
Conflux 智能合約的每個調用的方法都可以帶上 Value 參數,這是一個可選的參數。如果帶上了這個值,智能合約出了在執行這個方法的邏輯外,還會額外轉 Value 中指定數量的 CFX token 到 receiver 賬戶,轉賬金額為 Value 中所填的值。有些智能合約的方法需要這個參數才可以完成調用,但是在 Coin 合約不需要這個參數。
后文中的代付功能將會使用到 Value 參數。
在事件區域選擇 Sent 并點擊執行,下方的 Event Logs 可以看到轉賬的記錄。Sent 事件的列都是由代碼中的 Sent 事件的參數來定義的(其中 epoch 為事件發生的時間,這個為系統默認列)。在代碼中定義了 Sent
方法的參數為 from
, to
和 amount
,分別對應了這筆轉賬的發起者地址,接受者地址以及轉賬的數量。
Conflux Studio 支持 Conflux 系統合約提供的代付功能。
通過系統合約可以為別的合約設置代付功能,系統合約提供給了四個方法:
add_privilege
添加合約代付白名單,在代付白名單中的地址調用該合約的方法時不需要付手續費,費用由代付賬戶支付。其中添加特殊地址 0x0000000000000000000000000000000000000000
代表為所有調用該合約的地址代付費用
remove_privilege
移除合約代付白名單
set_sponsor_for_collateral
設置合約儲存費 (collateral for storage) 的代付賬戶及代付金額
set_sponsor_for_gas
設置合約手續費 (gas fee) 的代付賬戶、代付金額及每筆交易代付金額上限
啟用一個合約的代付需要設置代付的賬戶、代付金額的及代付白名單。教程將會使用 Conflux Studio 通過系統合約設置代付賬戶及代付金額,通過 Coin 合約添加代付白名單。設置完成后,minter_key
賬戶調用 Coin 合約的方法時將不會被扣除手續費,手續費由 sponsor_key
賬戶代付。
在 Conflux Studio 中訪問系統合約地址 0x0888000000000000000000000000000000000001
,在合約調用區域能看到前文中提及的四個設置代付的方法。
選擇 set_sponsor_for_collateral
方法,該方法有三個參數:
contract_addr
sponsor_key
地址sponsor_key
賬戶將會被扣除 40 CFX。
選擇 set_sponsor_for_gas
方法,該方法有四個參數:
contract_addr
sponsor_key
地址sponsor_key
賬戶將會再次被扣除 40 CFX。
完成這兩個方法的調用后 Coin 合約代付賬戶便設置好了,sponsor_key
賬戶將為 Coin 合約的手續費和儲存費各提供為 40 CFX Token 的代付服務。由于目前代付白名單中并沒有賬戶地址,因此還需要添加白名單地址才能完成代付設置。
在 Coin 合約中集成了設置代付白名單的方法,通過調用此方法可以添加或刪除代付白名單。
在 Conflux Studio 中訪問 contract_addr
合約,選擇 add_privilege 方法:
minter_key
地址
minter_key
地址
運行后就成功設置了代付白名單了,至此 Coin 合約的代付功能設置好了。
在進行代付測試前,先查詢并記錄下 minter_key
賬戶的 CFX 余額。例如本教程中,minter_key
的初始余額為 97.6210937497093952 CFX。
回到 Coin 合約調用頁面,再次調用 mint 方法并使用 minter_key
地址增發代幣 1000,完成代幣增發后再次查詢 minter_key
的余額,仍然為 97.6210937497093952 CFX。
可以看到增發代幣的這筆交易,原本應該由 minter_key
賬戶支付的手續費,變成了由 sponsor_key
賬戶支付。
前端項目源碼可以前往 Conflux 前端。
git clone https://github.com/ObsidianLabs/conflux-frontend-react
npm install
或者 yarn
進行項目依賴安裝
Conflux Portal 是由 Conflux 提供的瀏覽器插件,目前提供了 Chrome 及 Firefox 的支持,用戶可以使用 Conflux Portal 進行私鑰的管理以及交易簽名。
前往 Conflux Portal GitHub 下載安裝。項目的源代碼在 GitHub 中可以找到。
在這里需要將 Conflux Studio 中生成的地址導入到 Conflux Portal 中。完成插件安裝后,在 Conflux Portal 的頁面中選擇 Import,將 Conflux Studio 中的 minter_key
的私鑰(在創建錢包章節中介紹了如何將私鑰導出)粘貼到輸入框中,點擊 Import 按鈕完成私鑰導入。
在運行項目之前,需要修改一些默認的環境變量。
在前面的教程中部署合約后會生成一個 contractCreated
,這個值便是部署在網絡中智能合約的地址。打開項目根目錄并找到 .env
文件,這個文件提供了項目的環境變量,將 REACT_APP_CONFLUX_COIN_ADDRESS
的值修改為 contract_addr
。
使用 yarn start
啟動前端項目,開發服務器運行起來后會在瀏覽器中打開前端頁面(如果沒有打開,請在瀏覽器中訪問 http://localhost:3000)。
項目運行起來后,頁面將顯示四個卡片信息,分別為
點擊右上角組件中的 Connect to Conflux Portal 按鈕,Conflux Portal 頁面將被打開,輸入密碼和選擇賬戶后完成連接。連接成功后,將會在按鈕下看到當前連接的賬戶地址以及賬戶中的 CFX 余額。
左下角的組件為 Coin 合約組件,可以通過這個組件調用代幣增發和代幣轉賬功能。
代幣增發:選擇 mint 方法并在 receiver 中填入增發地址 minter_key
地址和在 amount 中填入增發代幣的數量 100,點擊 Push Transaction,在彈出的 ConfluxPortal Notification 窗口中點擊 Confirm 按鈕來確認交易。
代幣轉賬:選擇 send 方法并在 receiver 中填入收款人地址 receiver_key
地址和在 amount 中轉賬代幣的數量 20,點擊 Push Transaction,在彈出的 ConfluxPortal Notification 窗口中點擊 Confirm 按鈕來確認交易。
選擇 balanceOf 方法并在 tokenOwner 輸入框中填入查詢的地址,點擊 Query Data 按鈕可以查詢到賬戶的余額。
選擇 Sent 事件并點擊 Query Data 可以查詢到轉賬操作所觸發的轉賬事件的記錄。
項目使用 React 進行開發。主要由三大部分組成:視圖組件、js-conflux-sdk 以及 Conflux Portal。
項目根目錄下的 .env
環境變量,在這里定義了兩個環境變量,分別為
REACT_APP_CONFLUX_NODE_RPC
:Conflux 的網絡節點地址,目前默認為 Oceanus 網絡的地址
REACT_APP_CONFLUX_COIN_ADDRESS
:已部署的 Coin 智能合約地址
視圖組件在項目的 src/components
中,其中 App.js
為頁面的主入口,負責頁面的排列及合約信息的讀取。
負責渲染 Conflux 網絡信息,Node URL
的值為 .env
環境變量文件下的 REACT_APP_CONFLUX_NODE_RPC
設置的值(默認為 Oceanus 網絡)。
負責渲染 Conflux Portal 的連接信息,并提供了連接 Conflux Portal 的交互按鈕。
connectConfluxPortal
調用 Conflux Portal 的 enable
方法啟用 conflux (conflux portal 實例由瀏覽器插件注入到 windows.portal 中),完成 enable
后調用 getAccount
方法獲取到 Portal 中的賬戶。
refreshBalance
調用 Conflux SDK 的 getBalance
方法來更新賬戶余額信息
renderPortalButton
根據當前不同的狀態,渲染連接 Portal 的按鈕
負責渲染 Conflux 合約信息,本項目中提供了 Coin 和 SponsorWhitelistControl 兩個合約。
ConfluxContract.js
由三個組件組成,分別為:
ConfluxContract
負責根據傳入的合約 abi 來渲染合約的信息,包括合約地址、合約方法和事件,合約提交的交互邏輯及顯示執行后的結果
ContractMethods
負責渲染合約 abi 中的方法和事件的表單及相對應的按鈕
ConfluxForm
負責根據方法或事件的 abi 來渲染輸入表單
lib 在項目的 src/lib
中,這里的文件主要是為視圖提供包括連接網絡、構造交易、獲取賬戶、讀取合約等服務。
conflux.js
是 js-conflux-sdk
的封裝。js-conflux-sdk
是由 Conflux 提供的 JavaScript SDK,本前端項目使用 SDK 來連接 Conflux 網絡,和合約進行交互以及構造合約中的實例。
conflux-portal.js
是 Conflux Portal 的封裝,本前端項目通過調用瀏覽器插件來完成交易的簽名。調用 Conflux Portal 提供的 enable
方法可以啟動項目和 Conflux Portal 的連接(需要提前檢查瀏覽器是否正確安裝插件,在 constructor 中通過檢查 window.conflux
是否為空來判斷)。conflux-portal.js
提供了獲取賬戶 getAccount
和發送交易 sendTransaction
兩個主要的方法。
lib/abi
文件夾下提供了兩個 json 文件,分別為 Coin.json
和 SponsorWhitelistControl.json
,這兩個文件是構造合約所需要使用的 abi 文件。
在本開發教程中,我們學習了如何使用 Conflux Studio 來完成一個完整的 Coin DApp 開發,其中包括了:
Conflux 基金會為了鼓勵用戶參與生態建設,提供了 Conflux Bounty 賞金平臺。通過完成 Bounty 賞金平臺發布的各項任務,參與者可以獲得 FC (Fans Token) 作為獎勵。
FC,全稱 Fans Coin,是由 Conflux 基金會與社區成員共同研發的生態代幣,用于記錄和感謝對 Conflux 生態建設做出貢獻的社區成員。FC 目前在 Oceanus 上運行,Conflux 基金會承諾,在主網上線后,鎖定和未鎖定的 FC 都可以與主網 CFX 進行 1:1 承兌,以此保障所有社區成員的勞動成果都可以獲得獎勵。
FC 賞金分配方案會展示在賞金任務詳情頁中,包括最高獎金數量、獎金分配人數、獎金數量分布、排行名次確定方式等信息。賬號余額中的賞金獎勵可以隨時申請提現至 Conflux 錢包。Conflux 團隊會對所有的提現申請進行審核。
對于已經通過的提現申請,Conflux 團隊會在每周二中午 12 點(如遇節假日,往后順延至下一個工作日)進行提幣操作。完成提幣操作后,您的 Conflux 錢包將會收到您提現的賞金獎勵。
Conflux Bounty (https://bounty.conflux-chain.org) 的宗旨是為每一個通證找到價值。Bounty 分為幾個板塊:技術、品牌、社群、資源、其他等。
黑曜石實驗室(Obsidian Labs) 是全球最大的區塊鏈開發工具(IDE)提供商,也是 Conflux Studio 的開發團隊,致力于為區塊鏈開發者提供必備的工具及服務,幫助鏈上應用生態快速發展。目前,除了 Conflux Studio 外,Obsidian Labs 還為 EOS、Nervos、Substrate、Alogorand 等明星項目提供了專屬的 IDE 和框架工具。
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
原文鏈接:https://blog.csdn.net/weixin_45029854/article/details/107638406
作者:Sam @黑曜石實驗室
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
web3.js是以太坊提供的一個Javascript庫,它封裝了以太坊的JSON RPC API,提供了一系列與區塊鏈交互的Javascript對象和函數,包括查看網絡狀態,查看本地賬戶、查看交易和區塊、發送交易、編譯/部署智能合約、調用智能合約等,其中最重要的就是與智能合約交互的API。
下面就介紹如何使用web3.js提供的接口調用智能合約。
系統和軟件
-
Ubuntu 16.04 64位
-
nodejs 6.10.0
-
npm 3.10.10
示例合約
本文以下面的MetaCoin合約為例,說明在應用中使用web3.js操作智能合約的方法。
-
// 本文中用到的MetaCoin合約
-
pragma solidity ^0.4.2;
-
-
contract MetaCoin {
-
mapping (address => uint) balances;
-
-
event Transfer(address indexed _from, address indexed _to, uint256 _value);
-
-
function MetaCoin() {
-
balances[tx.origin] = 10000;
-
}
-
-
function sendCoin(address receiver, uint amount) returns(bool sufficient) {
-
if (balances[msg.sender] < amount) return false;
-
balances[msg.sender] -= amount;
-
balances[receiver] += amount;
-
Transfer(msg.sender, receiver, amount);
-
return true;
-
}
-
-
function getBalance(address addr) returns(uint) {
-
return balances[addr];
-
}
-
}
這個合約有三個函數:
MetaCoin:構造函數,在合約被部署到區塊鏈時執行
getBalance:返回某賬戶的余額,它只讀數據,不會修改數據
sendCoin:向另一個賬戶發送指定數量的MetaCoin,它會改變狀態變量balances
啟動一個以太坊節點,將上面的合約部署到區塊鏈中,并記錄下合約的地址,可以通過truffle部署,具體參考這篇文章。 接下來就可以按照下面的步驟在項目中通過web3.js來使用這個合約。
添加web3到項目中
首先新建一個Nodejs項目并初始化:
-
$ mkdir web3test && cd web3test
-
$ npm init
會提示輸入項目信息,全部默認即可。
接下來下載web3.js到項目中:
$ npm install web3 --save
以上命令會將web3.js下載到web3test/node_modules目錄下,其中–save參數會web3.js添加到package.json配置文件中。
創建web3對象
要使用web3.js與區塊鏈交互,需要先創建web3對象,然后連接到以太坊節點。 在web3test目錄下新建index.js文件,在其中輸入以下代碼:
-
var Web3 = require("web3");
-
// 創建web3對象
-
var web3 = new Web3();
-
// 連接到以太坊節點
-
web3.setProvider(new Web3.providers.HttpProvider("http://localhost:8545"));
獲取已部署的合約實例
要使用智能合約,必須先從區塊鏈中獲取到合約實例,獲取合約實例需要合約的ABI和合約的地址:
-
// 合約ABI
-
var abi = [{"constant":false,"inputs":[{"name":"receiver","type":"address"},{"name":"amount","type":"uint256"}],"name":"sendCoin","outputs":[{"name":"sufficient","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"}];
-
// 合約地址
-
var address = "0xb2cdd356e58280906ce53e1665697b50f88aac56";
-
// 通過ABI和地址獲取已部署的合約對象
-
var metacoin = web3.eth.contract(abi).at(address);
metacoin就是獲取到的合約對象實例,此時metacoin對象中就包含了與合約函數同名的Javascript函數,之后就可以通過metacoin對象來調用合約中的函數了。
調用合約函數
MetaCoin合約中有兩個函數:getBalance和sendCoin,可以通過metacoin對象直接調用這兩個函數。
首先來看getBalance,由于getBalance函數只是從區塊鏈中讀數據,而不修改數據,因此我們通過在getBalance后面加上.call()的方式調用:
-
var account_one = web3.eth.accounts[0];
-
var account_one_balance = metacoin.getBalance.call(account_one);
-
console.log("account one balance: ", account_one_balance.toNumber());
這里:
在getBalance后加上.call()來顯式指明用call的方式調用
通過call的方式調用可以得到getBalance函數的返回值
通過call的方式調用的函數只在節點本地虛擬機中執行,不會產生交易,不會花費費用,不會修改數據
下面來看sendCoin函數,由于sendCoin要修改合約內部的數據,所以要使sendCoin生效,必須要向區塊鏈發送交易,可以在sendCoin后面加上.sendTransaction()來指明這是一筆交易:
-
var account_one = web3.eth.accounts[0];
-
var account_two = web3.eth.accounts[1];
-
// 提交交易到區塊鏈,會立即返回交易hash,但是交易要等到被礦工收錄到區塊中后才生效
-
var txhash = metacoin.sendCoin.sendTransaction(account_two, 100, {from:account_one});
-
console.log(txhash);
這里:
在sendCoin函數后加上.sendTransaction()指明要向區塊鏈發送交易
合約代碼中sendCoin函數只有兩個參數,而在web3中通過.sendTransaction()調用合約函數的時候需要增加最后一個參數,它是一個javascript對象,里面可以指定from/value/gas等屬性,上面的例子用from來指定交易的發送者
上面的調用語句執行后,會向區塊鏈提交一筆交易,這筆交易的發送者是account_one,接收者是metacoin的地址,交易的作用是以account_two和100作為參數執行合約的sendCoin函數
函數會立即返回交易的hash,表明交易已經提交到區塊鏈,但是并不知道交易何時處理完成,交易要等到被曠工收錄到區塊中后才會生效
監聽合約事件
當通過.sendTransaction()調用合約的時候,交易會被提交到區塊鏈進行處理,這個處理需要一定的時間,如果需要等交易完成之后再執行其他操作,就必須要知道交易何時完成,那么如何知道交易何時完成呢?可以通過監聽合約事件來實現。
在合約中可以定義事件,事件可以帶有參數,在合約函數內部完成某些操作時,可以觸發事件,向外界傳達一些信息。例如,在MetaCoin合約中定義了一個事件叫做Transfer,表示一個轉賬的事件,它帶有三個參數:交易的發送者、接受者、轉賬數量。在sendCoin函數中,轉賬成功后就會觸發Transfer事件,將對應的參數傳給該事件,這樣外部監聽到事件后,可以取出事件的參數來獲得交易發送者、接收者、數量。同時事件中還帶有其他信息,比如交易hash等。
在web3中使用事件,要首先獲取事件對象,然后監聽事件,如果事件發生,就會在回調函數中獲取到事件信息:
-
// 獲取事件對象
-
var myEvent = metacoin.Transfer();
-
// 監聽事件,監聽到事件后會執行回調函數
-
myEvent.watch(function(err, result) {
-
if (!err) {
-
console.log(result);
-
} else {
-
console.log(err);
-
}
-
myEvent.stopWatching();
-
});
-
-
// 輸出:
-
{ address: '0xb2cdd356e58280906ce53e1665697b50f88aac56',
-
blockNumber: 651,
-
transactionIndex: 0,
-
transactionHash: '0xcc71bc2824cc84d1ee831c46189e3a80cf0af05697ba0370693aa97390c8067b',
-
blockHash: '0x1d53f04206f3926d0f311b1230a9dd0b0c5aadac35b169a6a609e384ab130c6f',
-
logIndex: 0,
-
removed: false,
-
event: 'Transfer',
-
args:
-
{ _from: '0x68b73956d704007514e9257813bdc58cdf3c969a',
-
_to: '0x9c3c1a2f5ef913fac44f0348a78f68d835f3f26e',
-
_value: { [String: '100'] s: 1, e: 2, c: [Object] } } }
從輸出可以看出,獲取到的事件信息包括事件的參數、事件名、區塊號、交易hash等。
通過檢測事件中的transactionHash與調用合約函數返回的交易hash是否一致,可以判定某一筆交易是否已完成:
-
var account_one = web3.eth.accounts[0];
-
var account_two = web3.eth.accounts[1];
-
-
var account_one_balance = metacoin.getBalance.call(account_one);
-
console.log("account one balance:", account_one_balance.toNumber());
-
-
var txhash = metacoin.sendCoin.sendTransaction(account_two, 100, { from: account_one });
-
-
var myEvent = metacoin.Transfer();
-
myEvent.watch(function (err, result) {
-
if (!err) {
-
if (result.transactionHash == txhash) {
-
var account_one_balance = metacoin.getBalance.call(account_one);
-
console.log("account one balance after sendCoin:", account_one_balance.toNumber());
-
}
-
} else {
-
console.log(err);
-
}
-
myEvent.stopWatching();
-
});
-
-
// 輸出:
-
account one balance: 7000
-
account one balance after sendCoin: 6900
watch中的回調函數如果被執行,說明事件已被觸發,也就是說某筆交易已經處理完,檢查交易hash是否一致,可以判定產生這個事件的交易是否是自己發送的交易,如果是,就可以進行其他操作,比如查詢最新的余額
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
這篇文章多看幾遍加深理解
async function 聲明定義了一個異步函數,它返回一個AsyncFunction對象。異步函數 是指通過 事件循環(event loop) 異步執行的函數,通過返回一個隱式的 Promise 作為其結果。使用異步函數的代碼的語法和結構更像使用標準同步功能。(The async function declaration defines an asynchronous function, which returns an AsyncFunction object. An asynchronous function is a function which operates asynchronously via the event loop, using an implicit Promise to return its result. But the syntax and structure of your code using async functions is much more like using standard synchronous functions.
)
async function name([param[, param[, ... param]]]) { statements }
參數:
返回值:返回一個promise
對象,將返回異步函數返回的值(如果異步函數是resolved則返回resolved的值;如果拋出異常,則rejected從異步函數中拋出的異常)。(A Promise which will be resolved with the value returned by the async function, or rejected with an uncaught exception thrown from within the async function.)
異步函數可以包含await
表達式,該表達式暫停異步函數的執行 并等待 Promise的執行結果返回,結果返回后就恢復異步函數的執行。
await 關鍵字只在異步函數(async functions)內有效。如果在異步函數外使用它,會拋出語法錯誤。
當異步函數暫停時,它調用的函數仍會繼續執行。
舉例一:
function resolveAfter5Seconds() { return new Promise(resolve => { setTimeout(() => { resolve('resolved'); }, 5000); }); } async function asyncCall() { console.log('calling'); let result = await resolveAfter5Seconds(); console.log(result); // 5s之后輸出結果 } asyncCall(); //返回的是一個promise對象 // console.log(asyncCall()); // Promise { <pending> }
運行效果:
舉例二:
let resolveAfter6Second = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Second = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let sequentialStart = async function () { console.log('sequential start'); const slow = await resolveAfter6Second(); console.log(slow); const fast = await resolveAfter4Second(); console.log(fast); } sequentialStart() //立即輸出 // sequential start // start slow promise //再過6秒后輸出 // slow promise is done // slow // start fast promise //再過4秒后輸出 // fast promise is done // fast
運行效果:
換一種await
的寫法,結果完全不同:兩個計時器被同時創建
let resolveAfter6Seconds = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Seconds = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let concurrentStart = async function () { console.log('concurrent start'); let slow = resolveAfter6Seconds(); let fast = resolveAfter4Seconds(); console.log(await slow); console.log(await fast); } setTimeout(() => { concurrentStart(); }, 2000); //2秒后執行 // concurrent start // start slow promise // start fast promise //再過4秒后執行 // fast promise is done //再過2秒后執行 // slow promise is done // slow // fast
運行效果:
在 concurrentStart 中,兩個計時器被同時創建,接著執行await。等待的是 promise的resolve回調,resolve后面的代碼( console.log(‘fast promise is done’);)會繼續執行。
這兩個計時器同時運行。但是 await 仍舊是順序執行的,第二個 await 還是得等待第一個執行完。在這個例子中,這使得先運行結束的輸出出現在最慢的輸出之后。
也可以把 concurrentStart 改寫成如下,運行效果一樣:
let resolveAfter6Seconds = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Seconds = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let concurrentPromise = async function () { console.log('concurrent start'); return Promise.all([resolveAfter6Seconds(), resolveAfter4Seconds()]).then((messages) => { console.log(messages[0]); // slow console.log(messages[1]); // fast }); } setTimeout(() => { concurrentPromise(); }, 2000); //2秒后輸出 // concurrent start // start slow promise // start fast promise //再過6秒后輸出 // fast promise is done //再過2秒后輸出 // slow promise is done // slow // fast
并行執行兩個或更多的任務,如下例所示:
let resolveAfter6Seconds = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Seconds = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let parallel = async function () { console.log('start paralel'); await Promise.all([ (async () => console.log(await resolveAfter6Seconds()))(), (async () => console.log(await resolveAfter4Seconds()))() ]); } setTimeout(parallel, 2000); //2秒后輸出 // start paralel // start slow promise // start fast promise //再過4秒后輸出 // fast promise is done // fast //再過2秒后輸出 // slow promise is done // slow
運行效果:
如果希望并行執行兩個或更多的任務,你必須像在parallel中一樣使用await Promise.all([job1(), job2()])
也可以把parallel改寫成如下,運行效果一樣:
let resolveAfter6Seconds = function(){ console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }); } let resolveAfter4Seconds = function(){ console.log('start fast promise'); return new Promise(resolve =>{ setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let parallelPromise = function(){ console.log('parallelPromise start'); resolveAfter6Seconds().then(msg => console.log(msg)); resolveAfter4Seconds().then(msg => console.log(msg)); } setTimeout(() => { parallelPromise(); }, 2000); //2秒后輸出 // parallelPromise start // start slow promise // start fast promise //再過4秒后輸出 // fast promise is done // fast //再過2秒后輸出 // slow promise is done // slow
async/await和Promise#then對比以及錯誤處理:
大多數異步函數(async functions )也可以使用 Promises函數 編寫。然而,當涉及到錯誤處理時,異步函數不太容易出錯。
上面例子中的concurrentStart函數和concurrentPromise函數在功能上都是等效的。在concurrentStart函數中,如果任一awaited調用失敗,它將自動捕獲異常,異步函數執行中斷,并通過隱式返回Promise將錯誤傳遞給調用者。
在Promise例子中這種情況同樣會發生,函數必須負責返回一個捕獲函數完成的Promise。在concurrentPromise函數中,這意味著它從Promise.all([]).then()中返回一個Promise。事實上,在此示例的先前版本忘記了這樣做!
但是,async函數仍有可能然可能錯誤地忽略錯誤。
以parallel異步函數為例。 如果它沒有等待await(或 return)Promise.all([])調用的結果,則不會傳播任何錯誤。
雖然parallelPromise函數示例看起來很簡單,但它根本不會處理錯誤! 這樣做需要一個類似于return Promise.all([])處理方式。(詳見)
返回 Promise的 API 將會產生一個 promise 鏈,它將函數分解成許多部分。例如下面的代碼:
function getProcessedData(url) { return downloadData(url)// returns a promise .catch(e => { return downloadFallbackData(url);// returns a promise }) .then(v => { return processDataInWorker(v);// returns a promise }) }
可以重寫為單個async函數:
async function getProcessedData(url) { let v; try { v = await downloadData(url); } catch (e) { v = await downloadFallbackData(); } return processDataInWorker(v); }
在上述示例中,return 語句中沒有 await 操作符,因為 async function 的返回值將被隱式地傳遞給 Promise.resolve。
return await promiseValue;
與 return promiseValue;
的比較
返回值隱式的傳遞給Promise.resolve
,并不意味著return await promiseValue;
,只是在功能上等同于返回return promiseValue;
。
重寫的上面代碼,在processDataInWorker拋出異常時返回null:
async function getProcessedData(url) { let v; try { v = await downloadData(url); } catch(e) { v = await downloadFallbackData(url); } try { return await processDataInWorker(v); // 注意 `return await` 和單獨 `return` 的比較 } catch (e) { return null; } }
簡單地寫上return processDataInworker(v);將導致在processDataInWorker(v)出錯時function返回值為Promise而不是返回null。
return foo;
和return await foo;
有一些細微的差異:
return foo;
不管foo是promise還是rejects都將會直接返回foo。相反地,如果foo是一個Promise,return await foo;將等待foo執行(resolve)或拒絕(reject),如果是拒絕,將會在返回前拋出異常。
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
一般情況下,this 指向調用他們的那個對象 ,也就是說誰調用就指向誰。
console.log(this);
-
function fn() {
-
console.log(this);
-
};
-
fn();
-
window.setTimeout(function() {
-
console.log(this);
-
-
}, 3000);
-
var idol = {
-
myname: '某某某',
-
age: '18歲',
-
sex: '女',
-
skill: function() {
-
console.log(this);
-
}
-
};
-
idol.skill()
-
var btn = document.querySelector('button');
-
// btn.addEventListener('click', function() {
-
// console.log(this);
-
-
// });
-
btn.onclick = function() {
-
console.log(this);
-
-
};
-
function Fun() {
-
console.log(this);
-
-
}
-
var fun = new Fun();
-
fun.uname = 'Jack';
-
fun.age = '18歲';
-
fun.sex = '男';
-
console.log(fun)
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
更改之前的效果圖:
更改之前瀏覽器窗口放大縮小圖表都不會進行動態的縮放,
更改之后的效果圖:
更改之后圖表就會根據瀏覽器窗口大小實時監聽進行縮放
代碼:
topChart.setOption({ series: [ {name: '最大值',type: 'line',stack: '最大值',data: dataMax}, {name: '最小值',type: 'line',stack: '最小值',data: dataMin}, {name: '平均值',type: 'line',stack: '平均值',data: dataAvg}, ] }); window.addEventListener("resize",()=> {//監聽瀏覽器窗口大小 topChart.resize(); });
如果有多個圖表同時渲染,給個定時器就可以了,ss[0],ss[1],ss[2],ss[3]分別表示四個圖表的class
var resizeTimer = null; window.addEventListener("resize", () => { if (resizeTimer) { clearTimeout(resizeTimer) } resizeTimer = setTimeout(function(){ ss[0].resize(); ss[1].resize(); ss[2].resize(); ss[3].resize(); }, 10); });
沒了,結束了,是不是很簡單吶,如有問題,歡迎留言。
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
vue文件最后要空一行,不然會報錯,真的奇葩…
這里要清楚哦!
通過Element-UI組件實現布局
在vscode打開終端ctrl+~
git status
查看當前git狀態
git checkout -b login
創建一個新的分支叫login
git branch
切換分支
在vue ui中啟動!
終端指令npm run serve
也可以運行!
import Vue from 'vue' import VueRouter from 'vue-router' import login from './components/login.vue' Vue.use(VueRouter) const routes = [ {path:'/login',component:login} ] const router = new VueRouter({ routes }) export default router
const router = new VueRouter({ routes: [ { path: '/', redirect: '/login' }, { path: '/login', component: login } ] })
一定要注意空格,不然會報錯,可惡啊!
先給一個全局樣式表
/* 全局樣式表 */ html, body, #app{ height: 100%; margin: 0; padding: 0; }
并在main.js中導入
import './assets/css/global.css'
注意:translate 進行移動,完成真正的居中
.login_box{ width: 450px; height: 300px; background-color: #fff; position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); }
.avatar_box{ height: 130px; width: 130px; border: 1px solid #eee; border-radius: 50%; padding: 10px; box-shadow: 0px 0px 10px #ddd; position: absolute; left: 50%; transform: translate(-50%,-50%); background-color: #fff;
img{ width: 100%; height: 100%; border-radius: 50%; background-color: #eee; } }
通過Element-UI組件實現布局
elements組件庫網頁
在網站里面可以找到一些可以使用的基礎模板代碼
導入組件
import Vue from 'vue'
import { Button, Form, FormItem, Input } from 'element-ui'//分開import會報錯
Vue.use(Button) Vue.use(Form) Vue.use(FormItem) Vue.use(Input)
中間form和button都是直接到上面的組件庫里面去找的
中間一些代碼不貼了,比較枯燥呀
特別地,我們的小圖標是從阿里的icon庫里面下載的
具體用法見以前寫得一篇博客
阿里巴巴icon圖標盡在掌握(前端如何引入icon庫,美麗圖標隨你處置T.T)
// 這是表單的驗證規則對象 loginFormRules: { // 驗證用戶名是否合法 username: [ { required: true, message: '請輸入登錄名稱', trigger: 'blur' }, { min: 3, max: 10, message: '長度在 3 到 10 個字符', trigger: 'blur' } ], // 驗證密碼是否合法 password: [ { required: true, message: '請輸入登錄密碼', trigger: 'blur' }, { min: 6, max: 15, message: '長度在 6 到 15 個字符', trigger: 'blur' } ] }
this.$refs.loginFormRef.resetFields()
來重置表單,注意表單的值會變為data里面設置的初值
this.$refs.loginFormRef.validate()
import axios from 'axios' // 配置請求的根路徑 axios.defaults.baseURL = 'https://127.0.0.1:8888/api/private/v1/' Vue.prototype.$http = axios
this.$refs.loginFormRef.validate(async valid => { if (!valid) return const { data: res } = await this.$http.post('login', this.loginForm) console.log(res) if (res.meta.status !== 200) return console.log('登錄失敗') console.log('登錄成功') })
Vue.prototype.$message = Message // 掛載到了Vue上
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
藍藍設計的小編 http://www.syprn.cn