React Native 入門寶典
聲明:該書的筆者為徐嬴老師,一名具有5年IOS開發經驗,和兩年RN開發經驗的老司機。
原文可以在gitbook上找到 筆者只是為他的書中提的的一些列問題,進行有償答疑。
有償答疑。本書將持續保持更新,有關問題可以加群討論。
正在上傳...取消
簡介
筆者在研究ReactNative過程中,發現其中文資料相對較少,已出版的大部分圖書資料都已過時。Facebook中的ReactNative開發團隊以每月更新一版的速度在向前推進版本。
為更好的讓廣大開發者快速入門ReactNative,筆者結合自身開發和教學的經驗,整理一份可用,且快速入門的資料。
希望大家可以通過這份資料,快速入門ReactNative技術。
開發環境的配置
安裝Nodejs環境
1,進入http://nodejs.cnnodejs中文網,下載與自身環境相一致的nodejs安裝包
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
2,安裝包下載之後,雙擊進行安裝
win平臺的同學註意,安裝過程中要關閉殺毒軟件和各種安全工具
3,安裝完成之後,打開命令行工具,檢查是否安裝成功,執行如下命令:
$ node -v
該命令執行結果為當前node版本,筆者當前版本為:
v6.9.1
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
4,檢查NPM是否安裝成功,
npm 是Node包管理工具,之後需要使用它來安裝其他node程序包
在在命令行中輸入如下命令:
$ npm -v
該命令執行結果為:
4.5.0
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
安裝Yarn
Yarn
Yarn是Facebook出品的一個依賴包管理工具,起作用和npm一樣。但Yarn具有更多好用的特性:
Yarn 會緩存它下載的每個包,所以不需要重復下載。它還能並行化操作以最大化資源利用率,所以安裝速度之快前所未有
Yarn 在每個安裝包的代碼執行前使用校驗碼驗證包的完整性。
Yarn 使用一個格式詳盡但簡潔的 lockfile 和一個精確的算法來安裝,能夠保證在一個系統上的運行的安裝過程也會以同樣的方式運行在其他系統上
網絡適應單個請求失敗不會導致安裝失敗,請求失敗時會重試。
安裝yarn
訪問Yarn官網 ,下載響應平臺的安裝包,進行安裝
使用Yarn
安裝好之後,其他工具會自動使用Yarn進行加速。
安裝create-react-native-app命令行工具
create-react-native-app是一個綜合創建ReactNative工程,並且不需要配置的工具,它極大的簡化了入門開發的流程。具體的內容,大家可以進入其github.com的主頁進行瀏覽。
安裝create-react-native-app需要使用npm進行,在任意目錄下,輸入如下命令,便可以在該目錄下創建一個ReactNative工程。
$ npm install -g create-react-native-app
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
安裝成功之後,會展示安裝路徑。如安裝不成功,請檢查網絡,重新安裝。
創建ReactNative工程
ReactNative工程的模板需要通過create-react-native-app工具進行創建。創建方法如下:
1,通過命令行進入存放ReactNative工程的文件夾。
2,在該文件夾下執行如下命令:
$ create-react-native-app myapp
myapp為工程名,可以更換為其他字符,但必須小寫
安裝過程需要1-5分鐘不等,如想提升安裝速度,可以安裝yarn,詳情見yarn官網
下面為筆者安裝成功截圖:
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
筆者使用了yarn進行提速,所有命令中顯示為yarn。
運行預覽工程
1,工程創建完成之後,便可以啟動工程,開始開發和調試。
啟動工程,首先要使用命令行工具進入工程更目錄,然後運行如下指令
$ npm start
工程 啟動之後,會生成一個二維碼和一個本地鏈接,通過此此二維碼或本地鏈接,便可預覽工程運行效果。
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
2,啟動工程之後,需要在手機端安裝Expo App,使用Expo App對所開發的ReactNative App進行預覽運行。
安裝ExpoApp的方法如下:
iOS平臺:在AppStore中搜索Expo client,如圖
正在上傳...取消
正在上傳...取消
Android平臺下,訪問此鏈接:http://expo.io/--/api/v2/versions/download-android-apk下載安裝包並安裝,安裝過程中需要給此App全部權限。
3,Expo App在手機端安裝完成之後,打開ExpoApp,通過其掃描二維碼的功能,掃描生成的二維碼,便可以在App內預覽開發中的App工程
正在上傳...取消
4,新建工程的運行效果為:
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
ES6基礎語法
變量
ES6中,增加了let和const兩個關鍵字聲明變量。
建議大家放棄var聲明變量的模式。var的特性與現代語言差異過大,非常容易造成bug
1,let
let聲明變量非常簡單,如下代碼:
let name = ‘Tom‘;
console.log(name);
let a = 1;
let b = 2;
let sum = a+b;
在聲明變量中,變量名為駝峰命名法。例如:let myName = ‘Tom‘;
變量一定要先申明,在使用,例如:
console.log(name);//錯誤,找不到name
let name = ‘Tom‘;
2,const
const聲明的變量,其值不能改變,代碼如下:
const age = 10;
age = 11;//error,const 聲明的變量,其值不能改變
但大家一定註意一點,const聲明的變量值不能變,但如果該變量為對象,其對象屬性值可變。
const person={
name:‘Tom‘,
age:10,
};
person.name = ‘Jhon‘;//沒問題
person = {
name:‘TT‘,
age:11
}//error,錯誤,不能改變person的值
3,變量作用域
let和const聲明的變量,以大括號為作用域邊界,只有在變量作用域內,才可以使用該變量,超過變量作用域再使用該變量,報錯。例如:
{
const name = ‘Tom‘;
console.log(name);//正確
}
console.log(name);//錯誤!name作用域再上面大括號內,超過無法使用
在有多層作用域嵌套的情況下,如果有同名變量,內層變量會屏蔽外面變量作用域,例如:
{
const name = ‘Tom‘;
{
const name = ‘Jim‘;
console.log(name);//打印為Jim
}
console.log(name);//打印為Tom
}
在多層作用域嵌套下,如沒有同名變量,作用域範圍不變。例如:
{
const name = ‘Tom‘;
{
console.log(name);//打印為Tom
}
console.log(name);//打印為Tom
}
註意,在多層作用域嵌套下,內層如有聲明同名變量,內層變量聲明之前,變量不能使用。例如:
{
const name = ‘Tom‘;
{
console.log(name);//錯誤!找不到name變量!
const name = ‘Jim‘;
}
console.log(name);//打印為Tom
}
字符串
JavaScript的字符串就是用‘‘或""括起來的字符表示。
如果‘本身也是一個字符,那就可以用""括起來,比如"I‘m OK"包含的字符是I,‘,m,空格,O,K這6個字符。
如果字符串內部既包含‘又包含"怎麽辦?可以用轉義字符\來標識,比如:
‘I\‘m \"OK\"!‘;
表示的字符串內容是:
I‘m "OK"!
1,字符串模板
要把多個字符串連接起來,可以用+號連接:
const name = ‘Tom‘;
const age = 10;
const message = ‘Hello, ‘ + name + ‘, your age is‘ + age;
console.log(message);
如果有很多變量需要連接,用+號就比較麻煩。ES6新增了一種模板字符串,表示方法和上面的多行字符串一樣,但是它會自動替換字符串中的變量:
const name = ‘Tom‘;
const age = 10;
const message = `Hello, ${name}, your age is ${age}`JavaScript為字符串提供了一些常用方法,註意,調用這些方法本身不會改變原有字符串的內容,而是返回一個新字符串
註意包裹字符串的字符為反引號,esc按鍵下方的字符,英文狀態下輸入
2,多行字符串
由於多行字符串用\n寫起來比較費事,所以最新的ES6標準新增了一種多行字符串的表示方法,用反引號包裹。
`Hello
World`//這是一個多行字符串
3,操作字符串
獲取字符串長度
const s = ‘Hello, world!‘;
s.length; // 13
要獲取字符串某個指定位置的字符,使用類似Array的下標操作,索引號從0開始:
const s = ‘Hello, world!‘;
s[0]; // ‘H‘
s[6]; // ‘ ‘
s[7]; // ‘w‘
s[12]; // ‘!‘
s[13]; // undefined 超出範圍的索引不會報錯,但一律返回undefined
註意:字符串是不可變的,如果對字符串的某個索引賦值,不會有任何錯誤,但是,也沒有任何效果
const s = ‘Test‘;
s[0] = ‘X‘;
console.log(s); // s仍然為‘Test‘·
JavaScript為字符串提供了一些常用方法,註意,調用這些方法本身不會改變原有字符串的內容,而是返回一個新字符串。
indexOf,會搜索指定字符串出現的位置:
const s = ‘hello, world‘;
s.indexOf(‘world‘); // 返回7
s.indexOf(‘World‘); // 沒有找到指定的子串,返回-1
substring,返回指定索引區間的子串:
const s = ‘hello, world‘
s.substring(0, 5); // 從索引0開始到5(不包括5),返回‘hello‘
s.substring(7); // 從索引7開始到結束,返回‘world‘
更多JavaScript 字符串操作,可參見W3School教程.
數組
JavaScript的Array可以包含任意數據類型,並通過索引來訪問每個元素。通過length可以訪問數組長度。
1,通過索引訪問數組元素
//通過索引讀取數組中的元素
const item = array[0];
console.log(item);//輸出0
註意:JavaScript中對數組越界操作沒有異常處理
const array = [1,2,3,4];
console.log(array[5]);//不報錯,打印undefined
2, 通過數組索引,可以修改數組中元素值
const array = [1,2,3,4];
array[0] = 5;
console.log(array[0]);//輸出為5
註意:對越界修改數組的值,會改變數組長度,且為賦值的元素值為undefined。不建議此操作
const array = [1,2,3,4];
array[5] = 6;
console.log(array);//打印結果為[1,2,3,4,undefined,6]
3,push和pop
//push()向數組末尾添加元素
const array = [1,2,3,4];
array.push(5);
console.log(array);//打印結果[1,2,3,4,5]
//pop()從數組末尾刪除元素
const array = [1,2,3,4];
array.pop();
console.log(array);//打印結果為[1,2,3];
4,splice
該方法可以操作數組在制定位置添加或刪除元素
//刪除指定元素
//splice(index,length)從index位置開始刪除長度為length
const array = [1,2,3,4];
array.splice(1,1);//從下標1開始刪除一個元素,即把2刪除
console.log(array);//輸出結果[1,3,4]
//添加制定元素
//splice(index,0,item1,item2,...),表示從index位置開始添加各元素,其他元素後移
const array = [1,2,3,4];
array.splice(1,0,5);
console.log(array);//輸出結果[1,5,2,3,4]
//混合操作,添加刪除
const array = [1,2,3,4];
array.splice(1,1,5);
console.log(array);//輸出結果[1,5,3,4]
其他Array操作方法,詳見W3SchoolArray教程。
對象
JavaScript的對象是一種無序的集合數據類型,它由若幹鍵值對組成。
鍵值對是有鍵和值組成的,一般稱為key-value。鍵和值直接用冒號分割,鍵只能為字符串,值可以為任何類型。
在對象中,多個鍵值對之前沒有順序概念,之間用逗號分割。
const obj = {
name:‘Tom‘,
age:10,
‘a:b‘:‘xx‘,
}
鍵為字符串,默認可以不加單引號,但如果字符串本身不加單引號有歧義
比如,上方第三個鍵值對中的鍵,為a:b一個字符串,如不加單引號,會有歧義,所以需要加。
通過對象的鍵可以對其對應的值進行讀寫操作。
const obj = {
name:‘Tom‘,
age:10,
‘a:b‘:‘xxx‘,
}
//通過 . 讀取對象屬性值
console.log(obj.name);//輸出Tom
obj.name = ‘XXX‘;
console.log(obj.name);//輸出XXX
//通過 [] 讀取對象屬性值,中括號內需要填字符串
console.log(obj.[‘age‘]);
obj[‘age‘] = 11;
console.log(obj[‘age‘]);
//有歧義的鍵,只能用[]號方式訪問
console.log(obj.[‘a:b‘]);
//使用變量作為鍵時,只能使用[]方式訪問
const key = ‘name‘;
console.log(obj.[key]);
函數
JavaScript中提供函數的定義和調用方式
1,基本語法
return x + y;
}
const sum = add(1,2);
console.log(sum);//結果為3
2,參數默認值
function add(x = 1,y = 2){
return x+y;
}
const sum1 = add();
console.log(sum1);//結果為3
const sum2 = add(2);
console.log(sum2);//結果為4
const sum3 = add(2,3);
console.log(sum3);//結果為5
3,箭頭函數
ES6增加箭頭函數特性
(x,y)=>{
return x + y;
}
箭頭函數沒有函數名,只描述了參數列表和函數體。
通常情況下,箭頭函數一般作為值進行傳遞。
const aFunc = ()=>{
console.log(‘xxx‘);
}//將箭頭函數賦值給aFunc變量
const bFunc = aFunc;//通過aFunc變量為bFunc變量賦值
箭頭函數無法直接被調用,只能借助存放箭頭函數值的變量進行調用,調用方法與調用普通函數一樣
const add = (x,y)=>{
return x+y;
}
const sum = add(1,2);
console.log(sum);//結果為3
箭頭函數也經常作為函數的參數,為函數形參賦值
function Test(func){
func();
}
const f1 = ()=>{
console.log(‘a‘);
}
const f2 = ()=>{
console.log(‘b‘);
}
Test(f1);//輸出結果為a
Test(f2);//輸出結果為b
4,高階函數
高階函數本質為能夠接收其他函數作為參數傳入的函數。也就是說,高階函數本身也是一種函數,只不過它的參數可以為其他函數,一般我們用箭頭函數作為高階函數的參數。
例如我們上文中提到的Test()函數,可以稱為一個高階函數。
我們對高階函數的要求為,會使用,不要求會編寫。這是基於我們當前開發技術提出的要求。在ReactNative開發中,我們會遇到很多寫好的高階函數,供我們使用,來完成更復雜的功能。但我們並不需要自己編寫一個高階函數。
所以本節重點是研究如何使用高階函數。
首先我們需要先明確一個概念:函數的類型。
函數類型由其輸入參數和返回值決定,輸入和返回值相同的函數,我們稱之為同一類型函數。例如:
(x,y)=>{
return x+y;
}
(a,b)=>{
return a-b;
}
這兩個為同類型函數,因輸入參數和返回值類型相同。
我們來看第一個例子,首先我給出一個寫好的高階函數,同學們不用糾結高階函數如何實現。
//func1的參數是一個f,f的類型為無輸入參數,無返回值。
//func1為一個高階函數
function func1(f){
f();
}
有了func1這個高階函數,所有無輸入參數,無返回值的函數,都可以作為參數出入該高階函數。例如:
f1 = ()=>{
console.log(‘hello‘);
}
func1(f1);//輸出hello
讀到這裏,大家可能會有一個疑問。使用了高階函數,執行操作也僅僅是打印一個hello字符串。這樣做的意義是什麽。接下來我們便進行討論,解釋高階函數的意義。
5,高階函數的意義
在討論這個問題之前,我們先明確兩個概念,在上文中提到的,
func1:我們稱之為高階函數。
f1:是高階函數的參數,也是一個函數。我們一般稱之為這個函數為功能函數
高階函數+功能函數的組合,才能實現完整的功能。其中高階函數一般為框架提供,功能函數一般由使用框架的開發者自己編寫。
為什麽要是這樣的組合呢?
是因為,我們做應用開發,尤其是App開發,如果代碼從零開始寫,那成本是非常高的。所以,我們在開發的時候,都是在各種框架下進行二次開發,這樣可以非常有效的提升開發效率,避免大量重復基礎的工作。我們可以認為,如果一個App的開發工作是100,那麽一個優秀的框架可以幫助我們完成其中的70-80的工作量。我們只需要完成20-30的工作量便可開發一個App並發布。
所以,開發效率的核心是框架。
那框架是如何被開發出來的呢?
這個問題比較復雜,在此我們舉一個簡單的例子,方便大家理解,並不做深入探討。
比如我們書中提供一個計算框架共大家使用。
計算這個功能不止包含法則,還包含數據的存儲和驗證。我們平時寫的1+2,僅僅是通過運算符對計算法則的描述。
function compute(x,y,f){
return f(x,y);
}
上面代碼中的compute便是我給大家的一個計算框架,我們可以想計算框架中傳入兩個計算變量一個計算規則,計算規則通過函數來描述。
我們先用計算框架做一個簡單的加法計算:
//準備計算數據
const p = 1;
const q = 2;
//先用函數描述一個加法計算規則
const f1 = (a,b)=>{
return a+b;
}
//調用計算框架進行計算
const sum = compute(p,q,f1);
console.log(sum);//打印結果為3
計算框架使用我們傳入的計算數據和計算法則,計算出我們的結果。這個計算框架就是高階函數。
到這裏,大家可能還是不能夠理解,我簡單的a+b也能完成這樣的操作,為什麽要用計算框架這個高階函數。這是因為,我們的問題不足夠復雜,沒法提現計算框架的優勢。下面我們在構造一個更復雜的計算。
我們規定,計算法則為:兩個輸入參數之和如果為奇數就相乘,如果之和為偶數結果為0。
這樣稍微復雜的計算規則,普通的處理方式就沒法進行了,這時候就體現出計算框架的功能了。
//構造計算規則
const f2 = (x,y)=>{
const s = x+y;
if(s%2 == 0){
return 0;
}
return x*y;
}
const result1 = compute(2,2,f2);
console.log(result1);//結果為0;
const result2 = compute(1,2,f2);
console.log(result2);//結果為2
通過計算框架,我們不需要關系具體計算過程,我們只需要描述特定的業務即可。
這便是高階函數的意義:提供了一種使用框架的方法,讓我們開發更加高效。
6,高階函數的應用
這一節我們舉兩個例子,說明高階函數的使用場景
提供操作基礎
提供事件回調
一般來說,高階函數無法獨自使用,必須配合我們寫的功能函數才能起作用。
案例1,數組的遍歷
//一般我們使用for循環進行數組的遍歷
const array = [1,2,3,4];
for(let i = 0; i < array.length; i++){
const value = array[i];
console.log(value);
}
此種方式,我們需要手寫一個for循環來進行,但是大家思考一下,所有的數組遍歷模式都差不多,那麽有沒有框架將for循環這種重復的基礎操作封裝,只讓我們寫遍歷規則呢。
答案是肯定的,JavaScript語言本身的Array對象中,包含了一個map()方法,該方法便是一個高階函數,其參數需要傳入一個函數,函數類型為:兩個輸入參數,一個返回值。
第一個輸入參數為數組中某一個元素的值
第二個輸入參數為該元素在數組中的索引
map方法會用返回值組成一個新的數組並返回
const array = [1,2,3,4];
array.map((value,index)=>{
console.log(value);
})//依次打印數組中每一個值
const arr1 = [1,2,3,4];
const arr2 = arr1.map((value,index)=>{
return value * 2;
});
console.log(arr2);//結果為[2,4,6,8];
通過使用框架提供的高階函數map,我們無需關註如果遍歷數組,只需要關註遍歷規則即可。
案例2,Timer事件回調
Timer是JavaScript中定時器,可以進行周期性操作,例如每隔1秒鐘打印一個字符串。實現這樣周期性操作,同樣使用的高階函數
//setInterval(func,msecond)
//該函數有兩個輸入參數,第一個輸入參數為一個函數,類型為無輸入參數,無返回值。第二個輸入參數為間隔時間,單位毫秒
//我們通過函數描述周期性需要完成的任務,例如是一個打印任務
const task = ()=>{
console.log(‘hello‘);
};
//只需要將此任務傳入高階函數,並設置好間隔時間,該任務便會安裝計劃運行,
setInterval(task,1000);//每1秒鐘打印一個hello
高階函數的應用場景很多,我們經常用的就是以上兩種類型。
對於高階函數,是區分程序員能力的標桿,後續的案例,我們會接觸越來越多的高階函數。使大家對高階函數的引用有更加深刻的認識。
JSON
JSON是JavaScript Object Notation的縮寫,它是一種數據交換格式。
在JSON中,一共就一下幾種數據類型:
number:和JavaScript的number完全一致;
boolean:就是JavaScript的true或false;
string:就是JavaScript的string;
null:就是JavaScript的null;
array:就是JavaScript的Array表示方式——[];
object:就是JavaScript的{ ... }表示方式。
上面的數據可以任意嵌套和組合。
由於JSON非常簡單,很快就風靡Web世界,並且成為ECMA標準。幾乎所有編程語言都有解析JSON的庫,而在JavaScript中,我們可以直接使用JSON,因為JavaScript內置了JSON的解析。
把任何JavaScript對象變成JSON,就是把這個對象序列化成一個JSON格式的字符串,這樣才能夠通過網絡傳遞給其他計算機。
如果我們收到一個JSON格式的字符串,只需要把它反序列化成一個JavaScript對象,就可以在JavaScript中直接使用這個對象了。
1,序列化
JSON序列化是指,將JavaScript中的對象轉換為JSON格式的字符串。
例如我們在數據庫中查詢到了一個人的信息,需要把這個信息通過網絡傳遞到前臺的App進行顯示,這時,我們需要將此對象進行JSON序列化,轉換成JSON字符串才能進行傳輸。
const person = {
name:‘Tom‘,
age:10,
tel:‘18612341234‘
}
//JSON序列化使用JavaScript語言中自帶的JSON解析器的stringify方法
const jsonData = JSON.stringify(person);
console.log(jsonData);//字符串:‘{"name":"Tom","age":11,"tel":‘1861234123‘}‘
2,反序列化
JSON反序列化也叫JSON解析。
拿到一個JSON格式的字符串,我們直接用JSON.parse()把它變成一個JavaScript對象。
一般來說,JSON格式的字符串都是通過網絡請求獲取
在此,我們為了測試JSON反序列化的功能,手寫一個本地的JSON格式字符串。
const jsonData = ‘{"name":"Tom","age":11,"tel":18612341234}‘;
const person = JSON.parse(jsonData);
console.log(person.name);//結果為Tom.
Class
ES6新增了class關鍵字,對面向對象編程有了更好的支持。
1,基本語法
class Point {
constructor(x,y){
this.x = x;
this.y = y;
}
toString(){
return `x is ${this.x}, y is ${this.y}`;
}
}
const p = new Point(1,2);
const s = p1.toString();
console.log(s);//輸出結果為x is 1, y is 2;
上面代碼演示了ES6中的class的基本用法。
使用class定義一個類
constructor為類的構造方法,當使用類實例化一個對象是,該方法會調用,並接受實例化時傳入的參數
類的屬性不需要提前聲明,可以直接使用,為定義的屬性值為null
聲明類的方法時,不需要寫function
2,this對象
this對象表示該類創建的對象,可以簡單理解為自身。
this有兩種使用場景:
訪問自身屬性
調用自身方法
class Point {
constructor\(x,y\){
this.x = x;
this.y = y;
}
toString(){
//通過this訪問自身屬性
return `x is ${this.x}, y is ${this.y}`;
}
}
class Point {
constructor\(x,y\){
this.x = x;
this.y = y;
}
toString(){
//通過this訪問自身屬性
return `x is ${this.x}, y is ${this.y}`;
}
logSelf(){
//通過this調用自身方法
const s = this.toString();
console.log(s)
}
}
const p1 = new Point(1,2);
p1.logSelf();
3,手動綁定this對象
在特定情況下,類中的方法在調用時,會產生this為undefined的情況。這些情況較為復雜,後續章節會詳細說明,在此不展開講解。
例如,如下代碼,變無法正常運行:
class Timer {
constructor(x){
this.x = x;
}
start(){
setInterval(this.event,1000);
}
event(){
console.log(‘a‘);
console.log(this.x);
}
}
const t = new Timer(1);
t.start();
上述代碼的運行結果為,每秒鐘,打印一個a字符,本應該一起打印的屬性x的值,無法輸出。
原因為,在此種情況下,event方法中的this對象為undefined,所以無法通過this對象訪問屬性x的值。
我們在學習初期,無法區分哪些情況this對象會丟失,所以我們采用一個統一的保守方案來修改此bug。
只要是自己寫的方法且方法中用到了this對象,我們都統一在constructor方法中,手動對其綁定this對象,避免this對象丟失的情況發生。
class Timer {
constructor(x){
this.x = x;
//手動綁定this
this.event = this.event.bind(this);
}
start(){
setInterval(this.event,1000);
}
event(){
console.log(‘x‘);
console.log(this.x);
}
}
const t = new Timer(1);
t.start();
通過手動綁定this對象之後,this對象丟失的情況便不會發生。
4,類的繼承
在ES6中,提供的extends關鍵字用來實現類的繼承關系。
class Base {
say(){
console.log(‘this is Base‘);
}
}
class Sub extends Base {
sayHello(){
console.log(‘this is Sub‘);
}
}
const s = new Sub();
s.say();//輸出結果為this is Base
s.sayHello();//輸出結果為 this is Sub
Sub類通過繼承獲得say方法,所有通過Sub實例化的對象也同樣可以使用該方法。
如果子類的方法與父類方法同名,那麽子類的方法會覆蓋父類的方法。
class Base {
say(){
console.log(‘this is Base‘);
}
}
class Sub extends Base {
say(){
console.log(‘this is Sub‘);
}
}
const s = new Sub();
s.say();//輸出結果為this is Sub
5,super對象
super對象和this對象類似。this對象表示對象本身,super對象表示本身對象的父類對象。
super對象的使用場景兩個:
調用與子類同名的父類方法
調用父類的constructor
class Base {
say(){
console.log(‘this is Base‘);
}
}
class Sub extends Base {
say(){
//調用父類的say方法
super.say();
console.log(‘this is Sub‘);
}
}
const s = new Sub();
s.say();
//輸出結果為
this is Base
this is Sub
class Point {
constructor(x,y){
this.x = x;
this.y = y;
}
}
class Point3D extends Point {
constructor(x,y,z){
//調用父類的constructor構造函數
super(x,y);
this.z = z;
}
logSelf(){
console.log(`x:${this.x},y:${this.y},z:${this.z}`);
}
}
const p = new Point3D(1,2,3);
p.logSelf();//輸出結果x:1,y:2,z:3
Module模塊系統
ES6提供了語言級別的模塊系統解決方案,是模塊化編程更加簡單和清晰。
我們將一個JavaScript文件看做一個js模塊,在模塊內部的變量和表達式,只要在相同的作用域中,不需要額外的引入操作變可以直接使用。
但在不同模塊之前的變量或者表達式無法直接使用,需要使用Module系統進行暴露和導入操作,才可以使用。
在編寫代碼時,我們通常在一個js模塊中編寫一個類,方面後期的維護和閱讀。當在另一個js模塊中需要使用這個類時,我們需要進行以下兩步操作
在編寫類的js模塊中,暴露該類的定義
在使用類的js模塊中,引入該類的定義
在完成以上兩步操作之後,便可以在新的模塊中使用已經寫好的類的代碼。
1,暴露模塊接口
在ES6中,使用export關鍵字對模塊內的定義進行暴露。
一般我們暴露三種接口:
變量接口
函數接口
Class接口
暴露接口方法有兩種形式,分別為暴露定義和通過大括號暴露名稱。直接暴露名稱為錯誤方法!
註意:export命令,只能寫在模塊的頂層作用域(註意,不是頂部)。頂層作用域的意思是不能再任何一個大括號內寫export
//變量接口
//正確1,暴露定義
export const a = 1;
export const b = 2;
//正確2
const x = 1;
const y = 1
//通過大括號暴露名稱
export {
x,
y,
};
//錯誤!!!
cosnt x = 1;
export x;
//函數接口
//正確1
export function f1(){
console.log(1);
}
export function f2(){
console.log(2);
}
//正確2
function f1(){
console.log(1);
}
function f2(){
console.log(2);
}
export {
f1,
f2,
}
//class接口
//正確1
export class AClass {
}
export class BClass {
}
//正確2
class AClass {
}
class BClass {
}
export {
AClass,
BClass,
}
2,引入模塊接口
引入模塊使用import關鍵字進行。使用方法如下
import { 接口名 } from ‘相對路徑‘
例如,我們首先在a.js文件中暴露一個變量,
//a.js
export const name = ‘Tom‘;
如果我們想在b.js文件中使用這個變量,我們需要引入該變量接口。
我們假定a.js和b.js在同級目錄下。
import { name } from ‘./a.js‘;
console.log(name);//輸出結果為Tom
在import命令中,如引入文件為.js,那麽其拓展名可以省略,其他類型文件不可以省略
import { name } from ‘./a‘;與上午中代碼等效,日常開發經常省略.js
在引入中一定註意,暴露的變量名和引入的變量名,一定要一致,如果不一致,將引入失敗。
3,默認暴露
在上述講解中,暴露和引入都必須使用相同的接口名,如果不相同便會出錯。這樣的要求在實際使用中不是很方便,在使用其他人的模塊是,還需要閱讀其源碼才能完成正確引入。
在ES6通過這樣的暴露引入機制同時,為了方面開發者更加方便的使用模塊,增加了一個默認暴露引入機制。
該機制通過export default關鍵字進行暴露,且同一模塊中,只能使用一次export default,同時可以使用傳統的export進行暴露
//a.js
export default const name = ‘Tom‘;
當引入默認暴露的接口是,接口名稱可以自定義,無需和暴露名一致。同時也不需要大括號
import XXX from ‘./a‘;
console.log(XXX);//輸出結果為Tom
默認暴露和普通暴露機制可以同時使用:
//a.js
export default const name = ‘Tom‘;
export const age = 10;
import Name , { age } from ‘./a‘;
console.log(Name);
console.log(age);
4, as重命名
在除了默認暴露以外的情況,暴露和引入的接口名必須一致。但有時模塊內部有自己的命名規則,對外暴露是命名規則可能過於繁瑣,我們便可以使用 as 關鍵字做暴露或者引入重命名,方面後面編碼使用該接口。
暴露重命名
//a.js
const xxx_name = ‘Tom‘;
export {
xxx_name as name,
}
import { name } from ‘./a‘;
console.log(name)
引入重命名
//a.js
export const name = ‘Tom‘;
import { name as xxx_name } from ‘./a‘
console.log(xxx_name);
React Native 基礎
以上說了那麽多,都是對知識的預熱,
下面我們的RN才漸漸粉墨登場了,在這裏我們再次感謝我們的徐嬴老師,熬夜加班寫下這本書。原文請上gitbook上找。該書gitbook上的原文
HelloWorld工程
在本機配置好開發環境之後,便可以創建工程。
首先我們先創建一個HelloWorld工程,打開命令行:
$ cd 指定目錄
$ create-react-native-app hello-world
等待一段時間,當命令行出現如下信息,便表示該工程創建成功。
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
1,文件結構
創建好的工程根目錄下,有如下文件。
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
其中點開通的文件為隱藏文件,如看不到,可以調整文件夾顯示屬性,使隱藏文件和文件夾顯示即可。隱藏文件的功能在此不做介紹,後續高級章節中進行展開講解。
App.js 應用開發入口
app.json 應用配置文件
App.test.js 應用測試用例
node_modules 依賴包文件夾
package.json node配置文件
README.md 說明文件
yarn.lock yarn配置文件
以上文件中,出第一個App.js文件外,其他文件我們暫時不會使用,大家不要更改其他文件中的內容。其他文件的功能,在後續高級章節中陸續展開講解。
2,App.js
App.js是程序開發的入口,我們首先閱讀下其源碼:
為了講解方便,我將代碼分為三個區域:
//區域1
import React from ‘react‘;
import { StyleSheet, Text, View } from ‘react-native‘;
//區域2
export default class App extends React.Component {
render() {
return (
Open up App.js to start working on your app!
Changes you make will automatically reload.
Shake your phone to open the developer menu.
);
}
}
//區域3
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: ‘#fff‘,
alignItems: ‘center‘,
justifyContent: ‘center‘,
},
});
區域1
模塊引入區,通過ES6的Module引入外部模塊。
通常我們使用兩個默認的外部模塊react和react-native構建我們的初始工程。
大家註意,這裏我們引入模塊是並沒有給出模塊的相對路徑,而是直接使用模塊名稱進行引入。
是因為在ReactNative項目中,react和react-native是依賴框架,通過npm或者yarn進行安裝使用,這樣的依賴框架包,我們安裝之後可以直接使用模塊名稱進行引入,不需要在標註相對路徑。
但自己書寫的js模塊,仍需要使用相對路徑進行引入,後續我們會涉及到此內容。
區域2
React組件定義區,ReactNative采用的是React.js組件化編程思想,每一個模塊中包含一個React組件,關於React.js的知識我們在下一個章節講述。
該區域是編程的核心區域,在此區域中,我們通過代碼編寫邏輯,控制頁面元素,響應用戶交互信息和刷下頁面。
區域3
樣式表定義區。
在ReactNative開發中,頁面元素的樣式通過inline的樣式表進行調整,與傳統網頁CSS控制樣式不同,ReactNative樣式是通過元素的style屬性進行控制,所有樣式對象都只對其style賦值的元素起作用,沒有全局樣式的概念。
ReactNative不支持CSS樣式屬性,但其樣式控制屬性與CSS類似,最大的不同是采用駝峰命名法,例如CSS中的background-color,在ReactNative中的屬性為backgroundColor。
具體的樣式,我們在後續章節會詳細講解。
React.js基礎
ReactNative框架是基於React.js擴展而來,其編碼基礎和基本開發思想都是與React.js一致。
React.js是Facebook在2013年5月開源的一個JavaScript框架,主要用於構建UI頁面。
目前Facebook及其旗下的前端都是用React.js進行構建,在之前,Facebook是用Angular.js框架進行開發,但是隨著Facebook業務的增加,Angular.js框架自身的架構能力不足以支撐項目的繼續繼承。Facebook在內部首先開啟了一個以組件化編程思想為基礎的新框架,後期開源,命名為React.js,用來架設 Instagram 的網站。
React.js核心思想為組件化編程,通過 React 構建組件,使得代碼更加容易得到復用,能夠很好的應用在大項目的開發中。
本章會對React.js基礎知識進行講解,為ReactNative做技術基礎準備。
0,開發環境
本節內容無法在手機App中運行,因React.js是瀏覽器JavaScript框架,所以本章內容全部在瀏覽器中運行調試。
首先確保,Nodejs,chrome瀏覽器和Yarn已經安裝。
通過npm安裝React工程創建工具
npm install -g create-react-app
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
安裝成功之後便可以通過該工具創建一個React項目
cd 指定目錄
create-react-app myapp
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
創建成功之後,進入該項目的工程文件夾根目錄,運行
npm start
或
yarn start
啟動項目。
首先會啟動一個本地調試服務器,通過該調試服務器可以預覽項目。
初始項目為下圖所示:
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
1,React元素
React元素對象是在頁面上顯示的基本單位,能夠在頁面上看到的東西,都是React元素對象。
創建React元素對象有兩種方式:
使用HTML標簽創建React元素對象
使用React組件創建React元素對象
使用React組件創建元素的內容,在我們後續講完React組件在詳細說明
首先我們需要引入react框架,
import React from ‘react‘;
react框架在創建項目中自動被安裝,同時自動安裝的還有react-dom框架,react-dom框架下文中講解。
通過react框架提供的createElement()函數創建React元素對象。
React.createElement(
type,
props,
children1,
children2,
...
)
type:為HTML標簽字符串或React組件類名
props:為元素屬性,類型為一個對象,屬性名為對象中的鍵名,屬性值為相應鍵名對應的值
從第三個參數起,都為該元素的子元素,類似HTML中的節點的子節點。
例如,我們需要在屏幕上顯示一個HelloWorld字符串,我們使用HTML中的p標簽進行創建React元素,元素屬性為空,子節點為一個字符串:HelloWorld。
const text = ‘HelloWorld‘;
const textObject = React.createElement(‘p‘,null,text);
如果我們需要在屏幕上展示一個圖片,創建React元素對象如下:
const url = ‘https://facebook.github.io/react/img/logo_og.png‘;
const imageObject = React.createElement(‘img‘,{src:url,alt:‘react-icon‘})
在實際開發中,我們需要頻繁的創建React元素對象,但此種創建方式十分不方便,所以,Facebook在ES6語法基礎上,發布了JSX語法,使用JSX語法,可以更加方便的創建和管理React元素對象。
2,JSX語法
JSX是React的核心組成部分,它使用XML標記的方式去直接聲明界面,界面組件之間可以互相嵌套。可以理解為在JS中編寫與XML類似的語言,一種定義帶屬性樹結構(DOM結構)的語法,它的目的不是要在瀏覽器或者引擎中實現,它的目的是通過各種編譯器將這些標記編譯成標準的JS語言。
例如我們對比上文中提到的兩個創建React元素對象的代碼:
const text = ‘HelloWorld‘;
//使用JavaScript語法
const textObject = React.createElement(‘p‘,null,text);
//使用JSX語法
const textObject =
{text}
可以看出,JSX語法的本質就是使用標簽語法代替React.createElement()方法。
使用JSX語法,必須首先引入React框架,雖然使用JSX語法雖然沒有顯示調用React框架,但編譯後的代碼仍然包含React的調用。
且JSX語法的核心優勢就是可以將變量寫入標簽中,這是之前HTML標簽語法做不到的操作。有了變量,React框架的編程能力得到了極大的提升,可以處理更多動態的問題。
對於動態和靜態,我在這裏做一個基礎定義
靜態:在寫代碼的這個時刻,已知所要編寫的內容。例如,我要輸出一個HelloWorld字符串,這個字符串在編碼的這個時刻是已知的,在編寫這樣的操作時,我們稱之為靜態問題。
動態:在編寫代碼這個時刻,對編寫內容有部分未知的空間。例如,我要求兩個書的和。到底這兩個數是什麽,在編寫代碼的時候不知道,這樣的問題稱之為動態問題,動態問題,必須使用變量來解決使用JSX語法創建對象和HTML標簽語法很像,但和標簽語法最大的區別就是在與語句中可以帶變量,通過大括號對變量進行包裹。
創建一個顯示圖片的React元素對象
const url = ‘https://facebook.github.io/react/img/logo_og.png‘;
//使用JavaScript語法
const imageObject = React.createElement(‘img‘,{src:url,alt:‘react-icon‘});
//使用JSX語法
const imageObject =
正在上傳...取消;
同樣,React元素對象可以像HTML標簽一樣進行嵌套:
const text = ‘HelloWorld‘;
const url = ‘https://facebook.github.io/react/img/logo_og.png‘;
const divObject = (
{text}
正在上傳...取消);
JSX語法中,變量可以是值,也可以是另一個React元素對象:
const textObject =
{‘HelloWorld‘}
;
const divObject = (
{textObject}
)
//相當於
const divObject = (
{‘HelloWorld‘}
);
變量可以為數組,數組的每一個元素必須為React元素對象
const objectArray = [];
const textObject1 =
{‘HelloWorld1‘}
;
const textObject2 =
{‘HelloWorld2‘}
;
const textObject3 =
{‘HelloWorld3‘}
;
objectArray.push(textObject1);
objectArray.push(textObject2);
objectArray.push(textObject3);
const divObject = (
{objectArray}
)
//相當於
const divObject = (
{‘HelloWorld1‘}
{‘HelloWorld2‘}
{‘HelloWorld3‘}
);
3,ReactDOM
ReactDOM框架提供了將React元素對象渲染到屏幕上的方法。
使用ReactDOM框架首先需要引入
import ReactDOM from ‘react-dom‘;
ReactDOM提供了一個render()方法,通過此方法可以將React元素對象渲染到指定的div標簽中。
//通過document操作獲取一個div節點
const div = document.getElementById(‘root‘);
//通過JSX語法創建一個React元素
const text =
{‘HelloWorld‘}
;
//渲染組件到div中
ReactDOM.render(text,div);
4,React組件
組件化開發是React.js以及後續的ReactNative開發的核心思想。
通過對業務是視圖進行封裝,組件化開發可以最大化的簡化開發過程,增強代碼的可復用性和可維護性。
React組件是通過JavaScript類實現的。
通過繼承react框架中提供的Component基礎類,構造一個React組件類。
import React , { Component } from ‘react‘;
class MyComponent extends Component {
}
MyComponent即為React組件,通過React組件也可以創建React元素,讓組件顯示在屏幕上。
const div = document.getElementById(‘root‘);
const myComponent = ;
ReactDOM.render(myComponent,div);
但是這樣屏幕上沒有任何現實,因為我們還沒有實現React組件的內容,但此語法沒有問題。
下面我們開始實現React組件
MyComponent通過react框架提供的Component基礎類繼承了以下方法:
constructor()
componentDidMount()
render()
componentWillUnmount()
import React , { Component } from ‘react‘;
class MyComponent extends Component {
//組件構造方法,在此方法中對組件內數據進行初始化
//此方法傳入參數為props固定不可變更,對於此參數後續介紹
constructor(props){
//此方法中固定在第一行調用super(props)對父類進行初始化
super(props);
}
//此方法為聲明周期方法,在該組件顯示在屏幕上時,該方法被自動調用
componentDidMount(){
}
//組件內渲染方法
//此方法返回一個React元素作為該組件的外觀
render(){
return (
);
}
//此方法為聲明周期方法,在該組件從屏幕上消失時,該方法被自動調用
//此方法不常用
componentWillUnmount(){
}
}
實現組件主要實現組件以下兩個方面:
外觀
邏輯
這也是React組件和html標簽最本質的區別。React組件和外觀和html標簽很像但組件可以封裝自己的業務邏輯,HTML僅僅是展示內容。
我們先實現一個最簡單的組件,只顯示一個HelloWorld
import React , { Component } from ‘react‘;
class MyComponent extends Component {
render(){
return (
{‘HelloWorld‘}
);
}
}
此組件只有一個單純的顯示功能,只用到一個render方法。
實現更多負責的組件,需要學習一下兩個章節。
5,Props
props是組件屬性,通過組件創建元素時,可以為該元素傳入屬性,所傳入的屬性可以在組件內部通過this.props字段訪問。
例如我們聲明一個顯示文字的:
import React , { Component } from ‘react‘;
class MyComponent extends Component {
render(){
return (
{this.props.text}
);
}
}
此組件可以動態顯示內容,使用該組件是,只需要向其屬性傳入相應的值既可以。
const div = document.getElementById(‘root‘);
//為元素傳入屬性的語法在JSX中類似html
const myComponent =
ReactDOM.render(myComponent,div)
展開操作符
在組件屬性字段較多時,賦值語句會使標簽語法不方便閱讀,此時,我們可以采用展開操作符,簡化賦值語句
const params = {
name:‘Tom‘,
age:10,
roomName:‘101‘,
}
//相當於
name={‘Tom‘}
age={10}
roomName={‘101‘}
/>
6,State
state是react框架提供了一個頁面刷新的機制。它通過this.state和this.setState()來實現。
state是React組件通過繼承Component獲取的一個屬性接口。
state是一個對象,在constructor方法中進行初始化,在render方法中使用。
state對象中的值不能直接修改,需要通過this.setState()方法進行修改。
具體方法,我們通過一個計數器案例來進行講解:
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
該技術實現了一個非常簡單的計數功能。這個功能中,我們需要根據用戶的點擊事件來更新頁面上的數字。
import React , { Component } from ‘react‘;
export default App extends Component {
constructor(props){
super(props);
this.state = {
count:0,
}
}
render(){
return(
{‘計數器‘}
{this.state.count}
{
this.setState({
count:this.state.count+1,
})
}}>{‘增加‘}
{
this.setState({
count:this.state.count-1,
})
}}>{‘減少‘}
{
this.setState({
count:0,
})
}}>{‘歸零‘}
)
}
}
文章持續更新如有問題,歡迎致電:18333103619.
關於本書出現的問題,筆者提供有償解答,歡迎加微信:jkxx123321
React Native 入門寶典