摘要:每個(gè)區(qū)塊所包含個(gè)基本屬性,,交易列表,工作量證明和前一個(gè)區(qū)塊的哈希值。返回整個(gè)區(qū)塊鏈。負(fù)責(zé)檢查一個(gè)鏈?zhǔn)欠裼行?,具體方法是循環(huán)讀取每個(gè)區(qū)塊并驗(yàn)證哈希和證明。
本篇文章由萬云團(tuán)隊(duì)編譯
原文鏈接:http://mp.weixin.qq.com/s/5-O...
如需轉(zhuǎn)載請(qǐng)聯(lián)系萬云官方微信:萬云Wancloud
2018年的門剛打開,區(qū)塊鏈的火就燒成了火焰山。徐小平放言要擁抱區(qū)塊鏈,朋友圈刷屏不止,連上班地鐵上都能聽到區(qū)塊鏈,一夜起,區(qū)塊鏈成了茶前飯后的談資。于是乎,那個(gè)經(jīng)常聽到的問題又開始抓耳撓腮:區(qū)塊鏈到底是什么鬼?關(guān)注的訂閱號(hào)不停推送“一篇文章讓你搞懂區(qū)塊鏈”,“三分鐘Get區(qū)塊鏈”等不盡相同的內(nèi)容,聲音從四面八方聚焦到你耳邊。
萬云也在思考能為想了解區(qū)塊鏈的老鐵們做點(diǎn)什么,鑒于已有如此多區(qū)塊鏈概念普及文,此次我們不聊枯燥的概念,而是回歸區(qū)塊鏈“技術(shù)”,一步步認(rèn)真教你獲得一個(gè)屬于自己區(qū)塊鏈。放心,只要你稍微懂一點(diǎn)技術(shù),你就可以實(shí)現(xiàn)并擁有它。
|| 以下翻譯自Daniel van Flymen的《Learn Blockchains by Building One》,有所刪改。
|| 原文地址:https://hackernoon.com/learn-...
前言
概念了解:在開始前你需要知道,區(qū)塊鏈?zhǔn)且环N按時(shí)間將數(shù)據(jù)區(qū)塊以順序相連的方式組合在一起的鏈?zhǔn)綌?shù)據(jù)結(jié)構(gòu),并通過密碼學(xué)來保證其不可篡改和不可偽造的分布式賬本。這些區(qū)塊可以包含交易、文件以及任何你想要的數(shù)據(jù),重要的是它們通過哈希鏈接在一起。
目標(biāo)讀者:可以輕松地閱讀和編寫一些基本的Python,并且對(duì)HTTP有一些了解。
所需工具:Python 3.6+、Flask、Requests:
pip install Flask==0.12.2 requests==2.18.4
除此之外還需安裝HTTP工具,如Postman、cURL。
源代碼地址:https://github.com/dvf/blockc...
**第一步:建立區(qū)塊鏈
①實(shí)現(xiàn)一個(gè)Blockchain類**
打開一個(gè)你常用的文本編輯器或者IDE,新建一個(gè)blockchain.py的python文件,并創(chuàng)建一個(gè)Blockchain類,在構(gòu)造函數(shù)中創(chuàng)建兩個(gè)空的隊(duì)列,一個(gè)用于存儲(chǔ)區(qū)塊鏈,另一個(gè)用于存儲(chǔ)交易。下面是Blockchain類的模板代碼:
class Blockchain(object): def __init__(self): self.chain = [] self.current_transactions = [] def new_block(self): # Creates a new Block and adds it to the chain pass def new_transaction(self): # Adds a new transaction to the list of transactions pass @staticmethod def hash(block): # Hashes a Block pass @property def last_block(self): # Returns the last Block in the chain pass
我們所創(chuàng)建的Blockchain類將用來管理鏈,它會(huì)存儲(chǔ)交易,并且提供一些方法來幫助添加新的區(qū)塊到鏈。下面是詳細(xì)的實(shí)現(xiàn)方法。
每個(gè)區(qū)塊所包含5個(gè)基本屬性:index,timestamp (in Unix time),交易列表,工作量證明和前一個(gè)區(qū)塊的哈希值。我們來看一個(gè)例子:
block = { "index": 1, "timestamp": 1506057125.900785, "transactions": [ { "sender": "8527147fe1f5426f9dd545de4b27ee00", "recipient": "a77f5cdfa2934df3954a5c7c7da5df1f", "amount": 5, } ], "proof": 324984774000, "previous_hash": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" }
到這里,我們對(duì)于鏈的概念應(yīng)該比較清楚了,每個(gè)新的區(qū)塊都會(huì)包含上一個(gè)區(qū)塊的哈希值,從而讓區(qū)塊鏈具有不可篡改的特性。如果攻擊者攻擊了鏈中比較靠前的區(qū)塊,則所有后面的區(qū)塊將包含不正確的哈希值。如果不能理解,慢慢消化——這是理解區(qū)塊鏈技術(shù)的核心思想。
②將交易添加到區(qū)塊
接下來我們實(shí)現(xiàn)一個(gè)將交易添加到區(qū)塊的方法,繼續(xù)看代碼:
class Blockchain(object): ... def new_transaction(self, sender, recipient, amount): """ Creates a new transaction to go into the next mined Block :param sender:Address of the Sender :param recipient: Address of the Recipient :param amount: Amount :return: The index of the Block that will hold this transaction """ self.current_transactions.append({ "sender": sender, "recipient": recipient, "amount": amount, }) return self.last_block["index"] + 1
在new_transaction()方法中向列表中添加一筆交易之后,它返回值是本次交易的index,該index會(huì)被添加到下一個(gè)待挖掘區(qū)塊,后面在用戶提交交易時(shí)也會(huì)用到。
③建一個(gè)新的區(qū)塊
當(dāng)Blockchain被實(shí)例化后,我們需要?jiǎng)?chuàng)建一個(gè)創(chuàng)世區(qū)塊,同時(shí)為我們的創(chuàng)世區(qū)塊添加一個(gè)工作量證明,這是挖礦的結(jié)果,我們稍后會(huì)詳細(xì)討論挖礦。
除了創(chuàng)建創(chuàng)世區(qū)塊的代碼,我們還需要補(bǔ)充new_block(),new_transaction()和hash()的方法:
import hashlib import json from time import time class Blockchain(object): def __init__(self): self.current_transactions = [] self.chain = [] # Create the genesis block self.new_block(previous_hash=1, proof=100) def new_block(self, proof, previous_hash=None): """ Create a new Block in the Blockchain :param proof:The proof given by the Proof of Work algorithm :param previous_hash: (Optional) Hash of previous Block :return: New Block """ block = { "index": len(self.chain) + 1, "timestamp": time(), "transactions": self.current_transactions, "proof": proof, "previous_hash": previous_hash or self.hash(self.chain[-1]), } # Reset the current list of transactions self.current_transactions = [] self.chain.append(block) return block def new_transaction(self, sender, recipient, amount): """ Creates a new transaction to go into the next mined Block :param sender: Address of the Sender :param recipient: Address of the Recipient :param amount: Amount :return: The index of the Block that will hold this transaction """ self.current_transactions.append({ "sender": sender, "recipient": recipient, "amount": amount, }) return self.last_block["index"] + 1 @property def last_block(self): return self.chain[-1] @staticmethod def hash(block): """ Creates a SHA-256 hash of a Block :param block: Block :return: """ # We must make sure that the Dictionary is Ordered, or we"ll have inconsistent hashes block_string = json.dumps(block, sort_keys=True).encode() return hashlib.sha256(block_string).hexdigest()
到此,我們的區(qū)塊鏈已經(jīng)基本上實(shí)現(xiàn)了雛形。這時(shí)候,你肯定想知道新區(qū)塊是怎么被挖出來的,也就是我們通常所說的“挖礦”。
④什么是工作量證明?
想了解什么是“挖礦”,就必須理解工作量證明(POW)是什么。區(qū)塊鏈上每一個(gè)新的區(qū)塊都來自于工作量證明(POW),POW的目標(biāo)是計(jì)算出一串解決問題的數(shù)字,這個(gè)結(jié)果眾所周知是很難計(jì)算的,但卻十分容易驗(yàn)證,因?yàn)榫W(wǎng)絡(luò)上的任何人都能夠驗(yàn)證這個(gè)結(jié)果,這是“工作量證明”背后的核心思想。
我們來看一個(gè)非常簡單的例子幫助理解:
假設(shè)整數(shù)X乘以另一個(gè)整數(shù)y的哈希值必須以0結(jié)尾,hash(x * y) = ac23dc...0. 設(shè)x = 5.求y。我們用Python來實(shí)現(xiàn):
from hashlib import sha256 x = 5 y = 0 # We don"t know what y should be yet... while sha256(f"{x*y}".encode()).hexdigest()[-1] != "0": y += 1 print(f"The solution is y = {y}")
得到的答案是當(dāng)y = 21,哈希值的結(jié)尾為0:
hash(5 * 21) = 1253e9373e...5e3600155e860
在比特幣中,工作證明算法被稱為Hashcash,這和我們上面所舉的例子差不多,結(jié)果難于發(fā)現(xiàn)卻易于校驗(yàn)。Hashcash是礦工為了創(chuàng)建一個(gè)新區(qū)塊而爭相計(jì)算的問題,計(jì)算難度通常取決于字符串中搜索的字符數(shù),通常也會(huì)花費(fèi)一定的時(shí)間才能計(jì)算得到,最終計(jì)算出來的礦工們會(huì)通過交易獲得一定數(shù)量的比特幣作為獎(jiǎng)勵(lì)。
⑤實(shí)現(xiàn)一個(gè)基本的工作量證明
首先我們?yōu)锽lockchain類實(shí)現(xiàn)一個(gè)類似的算法:
規(guī)則:找到一個(gè)數(shù)字p,使得它與前一個(gè)區(qū)塊的 proof 拼接成的字符串的 Hash 值以 4 個(gè)零開頭。
import hashlib import json from time import time from uuid import uuid4 class Blockchain(object): ... def proof_of_work(self, last_proof): """ Simple Proof of Work Algorithm: - Find a number p" such that hash(pp") contains leading 4 zeroes, where p is the previous p" - p is the previous proof, and p" is the new proof :param last_proof::return: """ proof = 0 while self.valid_proof(last_proof, proof) is False: proof += 1 return proof @staticmethod def valid_proof(last_proof, proof): """ Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes? :param last_proof: Previous Proof :param proof: Current Proof :return: True if correct, False if not. """ guess = f"{last_proof}{proof}".encode() guess_hash = hashlib.sha256(guess).hexdigest() return guess_hash[:4] == "0000"
通過修改前導(dǎo)零的數(shù)量,可以調(diào)整算法的難度,但是4個(gè)零完全足夠了。你會(huì)發(fā)現(xiàn),每當(dāng)增加一個(gè)前導(dǎo)零,找到一個(gè)對(duì)應(yīng)的解決方案與所需的時(shí)間之間會(huì)產(chǎn)生巨大的差異。
進(jìn)行到這里,我們的Blockchain類已經(jīng)基本完成,接下來我們實(shí)現(xiàn)HTTP服務(wù)進(jìn)行交互。
第二步:區(qū)塊鏈API
我們將使用Python Flask框架,F(xiàn)lask是一個(gè)輕量級(jí)的Web應(yīng)用框架,這使我們可以通過web服務(wù)來調(diào)用Blockchian類。
①創(chuàng)建三個(gè)API:
?/ transactions / new為區(qū)塊創(chuàng)建一個(gè)新的交易
?/mine告訴我們的服務(wù)器開采新的區(qū)塊。
?/chain返回整個(gè)區(qū)塊鏈。
②使用Flask
我們的“服務(wù)器”將基于Flask框架來實(shí)現(xiàn)區(qū)塊鏈網(wǎng)絡(luò)中的一個(gè)節(jié)點(diǎn)。 我們來添加一些模板代碼:
import hashlib import json from textwrap import dedent from time import time from uuid import uuid4 from flask import Flask class Blockchain(object): ... # Instantiate our Node app = Flask(__name__) # Generate a globally unique address for this node node_identifier = str(uuid4()).replace("-", "") # Instantiate the Blockchain blockchain = Blockchain() @app.route("/mine", methods=["GET"]) def mine(): return "We"ll mine a new Block" @app.route("/transactions/new", methods=["POST"]) def new_transaction(): return "We"ll add a new transaction" @app.route("/chain", methods=["GET"]) def full_chain(): response = { "chain": blockchain.chain, "length": len(blockchain.chain), } return jsonify(response), 200 if __name__ == "__main__": app.run(host="0.0.0.0", port=5000)
以下是對(duì)上面添加的內(nèi)容的進(jìn)行簡要說明:
Line15:實(shí)例化Flask web服務(wù)節(jié)點(diǎn)。 Line18:為我們的服務(wù)節(jié)點(diǎn)創(chuàng)建一個(gè)隨機(jī)的名稱。 Line21:實(shí)例化Blockchain類。 Line24-26:創(chuàng)建一個(gè)路由為/mine的GET請(qǐng)求的,調(diào)用后端Blockchain的new block方法。 Line28-30:創(chuàng)建一個(gè)路由為/transactions/new的POST請(qǐng)求,將數(shù)據(jù)發(fā)送給后端Blockchina的new transaction方法。 Line32-38:創(chuàng)建一個(gè)路由為/chain的GET請(qǐng)求,將返回整個(gè)鏈。 Line40-41:在端口5000上運(yùn)行服務(wù)器。
③實(shí)現(xiàn)交易
下面是用戶發(fā)起交易時(shí)發(fā)送到服務(wù)器的請(qǐng)求:
{ "sender": "my address", "recipient": "someone else"s address", "amount": 5 }
由于我們已經(jīng)有了將交易添加到區(qū)塊的方法,接下去就十分容易了。
下面我們來實(shí)現(xiàn)添加交易的函數(shù):
import hashlib import json from textwrap import dedent from time import time from uuid import uuid4 from flask import Flask, jsonify, request ... @app.route("/transactions/new", methods=["POST"]) def new_transaction(): values = request.get_json() # Check that the required fields are in the POST"ed data required = ["sender", "recipient", "amount"] if not all(k in values for k in required): return "Missing values", 400 # Create a new Transaction index = blockchain.new_transaction(values["sender"], values["recipient"], values["amount"]) response = {"message": f"Transaction will be added to Block {index}"} return jsonify(response), 201
④實(shí)現(xiàn)挖礦
我們的挖礦方法是魔法發(fā)生的地方。它十分容易,只做三件事情:計(jì)算工作量證明;通過新增一筆交易獎(jiǎng)勵(lì)礦工一定數(shù)量的比特幣;創(chuàng)建新的區(qū)塊并將其添加到鏈中來。
import hashlib import json from time import time from uuid import uuid4 from flask import Flask, jsonify, request ... @app.route("/mine", methods=["GET"]) def mine(): # We run the proof of work algorithm to get the next proof... last_block = blockchain.last_block last_proof = last_block["proof"] proof = blockchain.proof_of_work(last_proof) # We must receive a reward for finding the proof. # The sender is "0" to signify that this node has mined a new coin. blockchain.new_transaction( sender="0", recipient=node_identifier, amount=1, ) # Forge the new Block by adding it to the chain previous_hash = blockchain.hash(last_block) block = blockchain.new_block(proof, previous_hash) response = { "message": "New Block Forged", "index": block["index"], "transactions": block["transactions"], "proof": block["proof"], "previous_hash": block["previous_hash"], } return jsonify(response), 200
需要注意的是,開采塊的交易接收者是我們自己服務(wù)器節(jié)點(diǎn)的地址,我們?cè)谶@里所做的大部分工作只是與Blockchain類進(jìn)行交互,基于以上我們區(qū)塊鏈已經(jīng)完成了,接下來開始交互演示。
第三步:交互演示
您可以使用cURL或Postman與API進(jìn)行交互。
啟動(dòng)服務(wù)器:
$ python blockchain.py * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
嘗試通過向http:// localhost:5000 / mine發(fā)出GET請(qǐng)求來挖掘區(qū)塊:
創(chuàng)建一個(gè)新的交易,向http://localhost:5000/transactions/new發(fā)出一個(gè)POST請(qǐng)求:
也可以使用cURL發(fā)送請(qǐng)求:
$ curl -X POST -H "Content-Type: application/json" -d "{ "sender": "d4ee26eee15148ee92c6cd394edd974e", "recipient": "someone-other-address", "amount": 5 }" "http://localhost:5000/transactions/new"
以上僅為交互演示的示例,你可以在你自己所完成的區(qū)塊鏈上進(jìn)行更多嘗試。
第四步:共識(shí)機(jī)制
我們有一個(gè)基本的區(qū)塊鏈可以進(jìn)行交易和挖礦,但其實(shí)區(qū)塊鏈更重要的意義在于它們是分布式的。那么我們需要確保所有的節(jié)點(diǎn)都運(yùn)行在同一條鏈上,這就是回歸到了共識(shí)問題,如果要滿足在網(wǎng)絡(luò)上有多個(gè)節(jié)點(diǎn)并且不斷增加,我們必須要實(shí)現(xiàn)共識(shí)算法。
①注冊(cè)新的節(jié)點(diǎn)
在實(shí)現(xiàn)共識(shí)算法之前,需要找到一種方式讓網(wǎng)絡(luò)上的節(jié)點(diǎn)知道其相鄰的節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)都需要存儲(chǔ)網(wǎng)絡(luò)上其他節(jié)點(diǎn)的記錄。因此,我們需要新增幾個(gè)方法來幫助實(shí)現(xiàn):
1./nodes/register接受URL形式的新節(jié)點(diǎn)列表。
/ nodes / resolve來執(zhí)行我們的共識(shí)算法,它可以解決任何沖突,確保節(jié)點(diǎn)具有正確的鏈。
下面我們將修改Blockchain的構(gòu)造函數(shù)以提供注冊(cè)節(jié)點(diǎn)的方法:
... from urllib.parse import urlparse ... class Blockchain(object): def __init__(self): ... self.nodes = set() ... def register_node(self, address): """ Add a new node to the list of nodes :param address:Address of node. Eg. "http://192.168.0.5:5000" :return: None """ parsed_url = urlparse(address) self.nodes.add(parsed_url.netloc)
注意,我們使用set()集合來保存節(jié)點(diǎn)列表,這是確保新節(jié)點(diǎn)的添加是冪等的簡便方法,這意味著無論我們添加特定節(jié)點(diǎn)多少次,它都只會(huì)出現(xiàn)一次。
②實(shí)現(xiàn)共識(shí)算法
如前所述,當(dāng)一個(gè)節(jié)點(diǎn)與另一個(gè)節(jié)點(diǎn)有不同時(shí)會(huì)發(fā)生沖突,為了解決這個(gè)問題,我們遵循取最長鏈原則,通過使用此算法,讓網(wǎng)絡(luò)中的節(jié)點(diǎn)間達(dá)成共識(shí)。
... import requests class Blockchain(object) ... def valid_chain(self, chain): """ Determine if a given blockchain is valid :param chain:A blockchain :return:
True if valid, False if not """ last_block = chain[0] current_index = 1 while current_index < len(chain): block = chain[current_index] print(f"{last_block}") print(f"{block}") print(" ----------- ") # Check that the hash of the block is correct if block["previous_hash"] != self.hash(last_block): return False # Check that the Proof of Work is correct if not self.valid_proof(last_block["proof"], block["proof"]): return False last_block = block current_index += 1 return True def resolve_conflicts(self): """ This is our Consensus Algorithm, it resolves conflicts by replacing our chain with the longest one in the network. :return: True if our chain was replaced, False if not """ neighbours = self.nodes new_chain = None # We"re only looking for chains longer than ours max_length = len(self.chain) # Grab and verify the chains from all the nodes in our network for node in neighbours: response = requests.get(f"http://{node}/chain") if response.status_code == 200: length = response.json()["length"] chain = response.json()["chain"] # Check if the length is longer and the chain is valid if length > max_length and self.valid_chain(chain): max_length = length new_chain = chain # Replace our chain if we discovered a new, valid chain longer than ours if new_chain: self.chain = new_chain return True return False
valid_chain()負(fù)責(zé)檢查一個(gè)鏈?zhǔn)欠裼行В唧w方法是循環(huán)讀取每個(gè)區(qū)塊并驗(yàn)證哈希和證明。
resolve_conflicts()負(fù)責(zé)循環(huán)讀取所有相鄰節(jié)點(diǎn),獲取它們的鏈并使用上面的方法驗(yàn)證它們的有效性。如果找到了一個(gè)更長的有效鏈,則取代我們當(dāng)前的鏈。
我們將兩個(gè)方法注冊(cè)到我們的API中,一個(gè)用于添加相鄰節(jié)點(diǎn),另一個(gè)用于解決沖突:
@app.route("/nodes/register", methods=["POST"]) def register_nodes(): values = request.get_json() nodes = values.get("nodes") if nodes is None: return "Error: Please supply a valid list of nodes", 400 for node in nodes: blockchain.register_node(node) response = { "message": "New nodes have been added", "total_nodes": list(blockchain.nodes), } return jsonify(response), 201 @app.route("/nodes/resolve", methods=["GET"]) def consensus(): replaced = blockchain.resolve_conflicts() if replaced: response = { "message": "Our chain was replaced", "new_chain": blockchain.chain } else: response = { "message": "Our chain is authoritative", "chain": blockchain.chain } return jsonify(response), 200
最后,如果你愿意的話可以開啟另一臺(tái)機(jī)器,并在你的網(wǎng)絡(luò)上運(yùn)轉(zhuǎn)不同的節(jié)點(diǎn)?;蛘呤褂猛慌_(tái)機(jī)器上的不同端口啟動(dòng)進(jìn)程。我在我的機(jī)器的不同端口創(chuàng)建另外一個(gè)節(jié)點(diǎn),并將其注冊(cè)到當(dāng)前區(qū)塊鏈網(wǎng)絡(luò)中。 因此,我有兩個(gè)節(jié)點(diǎn):http:// localhost:5000和http:// localhost:5001。
為了確保鏈更長,我在節(jié)點(diǎn)2上挖掘了一些新的區(qū)塊。 之后,我在節(jié)點(diǎn)1上調(diào)用GET / nodes / resolve,此處的鏈已經(jīng)被共識(shí)算法計(jì)算后的得到的新鏈所替代。
現(xiàn)在,你可以邀請(qǐng)一些朋友來一起測(cè)試你的區(qū)塊鏈了。
本文教程到此結(jié)束,那么,屬于你自己的區(qū)塊鏈擼好了嗎?別忘了分享給身邊同為程序員的朋友,一起來擼區(qū)塊鏈!
本篇文章由萬云團(tuán)隊(duì)編譯,如需轉(zhuǎn)載請(qǐng)聯(lián)系萬云官方微信:萬云Wancloud
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/41404.html
摘要:每個(gè)區(qū)塊所包含個(gè)基本屬性,,交易列表,工作量證明和前一個(gè)區(qū)塊的哈希值。返回整個(gè)區(qū)塊鏈。負(fù)責(zé)檢查一個(gè)鏈?zhǔn)欠裼行?,具體方法是循環(huán)讀取每個(gè)區(qū)塊并驗(yàn)證哈希和證明。 本篇文章由萬云團(tuán)隊(duì)編譯原文鏈接:http://mp.weixin.qq.com/s/5-O...如需轉(zhuǎn)載請(qǐng)聯(lián)系萬云官方微信:萬云Wancloud 2018年的門剛打開,區(qū)塊鏈的火就燒成了火焰山。徐小平放言要擁抱區(qū)塊鏈,朋友圈刷屏不止...
摘要:但是如果將我們的包還沒有測(cè)試好,直接發(fā)到遠(yuǎn)程未免顯得有點(diǎn)笨拙。發(fā)包創(chuàng)建文件在發(fā)包之前排除一些沒有必要發(fā)的文件注冊(cè),就按照提示依次填寫信息就好了發(fā)布由于本人學(xué)識(shí)有限,有很多需要提升的地方,望大家多多指教。 創(chuàng)建一個(gè)項(xiàng)目目錄 mkdir project 創(chuàng)建package.json npm init 配置tsconfig.json npm -i typescript -g //全局安...
摘要:最后提醒下,代碼中使用而非的原因是為了啟動(dòng)移動(dòng)端手機(jī)的動(dòng)畫加速,提升動(dòng)畫流暢度。 前言 最近面試發(fā)現(xiàn)很多前端程序員都從來沒有寫過插件的經(jīng)驗(yàn),基本上都是網(wǎng)上百度。所以打算寫一系列文章,手把手的教一些沒有寫過組件的兄弟們?nèi)绾稳懖寮?。本系列文章都基于VUE,核心內(nèi)容都一樣,會(huì)了之后大家可以快速的改寫成react、angular或者是小程序等組件。這篇文章是第一篇,寫的是一個(gè)類似QQ的側(cè)邊菜...
摘要:夾在中間的被鏈?zhǔn)秸{(diào)用,他們拿到上個(gè)的返回值,為下一個(gè)提供輸入。最終把返回值和傳給。前面我們說過,也是一個(gè)模塊,它導(dǎo)出一個(gè)函數(shù),該函數(shù)的參數(shù)是的源模塊,處理后把返回值交給下一個(gè)。 文:小 boy(滬江網(wǎng)校Web前端工程師)本文原創(chuàng),轉(zhuǎn)載請(qǐng)注明作者及出處 showImg(https://segmentfault.com/img/remote/1460000012990131?w=1083...
摘要:畫字首先我在畫布上畫了個(gè)點(diǎn),用這些點(diǎn)來組成我們要顯示的字,用不到的字就隱藏起來。星星閃爍效果這個(gè)效果實(shí)現(xiàn)很簡單,就是讓星星不停的震動(dòng),具體就是讓點(diǎn)的目的地坐標(biāo)不停的進(jìn)行小范圍的偏移。 哈哈哈哈?。。‘?dāng)我說在寫這邊文章的時(shí)候,妹子已經(jīng)追到了,哈哈哈哈哈?。?! 其實(shí)東西是一年前寫的,妹子早就追到手了,當(dāng)時(shí)就是用這個(gè)東西來表白的咯,二話不說,先看效果(點(diǎn)擊屏幕可顯示下一句) showImg(...
閱讀 1836·2021-09-28 09:46
閱讀 3154·2019-08-30 14:22
閱讀 1886·2019-08-26 13:36
閱讀 3352·2019-08-26 11:32
閱讀 2101·2019-08-23 16:56
閱讀 1158·2019-08-23 16:09
閱讀 1311·2019-08-23 12:55
閱讀 2158·2019-08-23 11:44