1.Typescript中的&理解
constructor(props: TagManagementStateProps & TagManagementOwnProps & TagManagementDispatchProps)
參數(shù)中的 & 表示props對(duì)象同時(shí)擁有了TagManagementStateProps骨宠、TagManagementOwnProps箩帚、TagManagementDispatchProps這三種類型的成員。交叉類型:將多個(gè)類型合并為一個(gè)類型锁右,這讓我們可以把現(xiàn)有的多種類型疊加到一起成為一種類型,它包含了所需的所有類型的特性
2.takeEvery
export default function* () {
yield takeEvery(TAG_LISTEN_QUERY, queryListSaga);
yield takeEvery(TAG_LISTEN_QUERY_INIT_DATA, queryInitDataSaga);
yield takeLatest(TAG_LISTEN_FETCH_MATERIAL_TAGS_SAGA, queryMaterialTagsSaga);
yield takeEvery(TAG_LISTEN_SAVE_QUESTION_TAGS, saveTagsSaga);
}
takeEvery:允許多個(gè) fetchData 實(shí)例同時(shí)啟動(dòng)。在某個(gè)特定時(shí)刻虑啤,我 們 可以啟動(dòng)一個(gè)新的 fetchData 任務(wù), 盡管之前還有一個(gè)或多個(gè) fetchData 尚未結(jié)束
takeLatest:只允許執(zhí)行一個(gè) fetchData 任務(wù)架馋,并且這個(gè)任務(wù)是最后被啟動(dòng)的那個(gè)狞山,如果之前已經(jīng)有一個(gè)任務(wù)在執(zhí)行,那之前的這個(gè)任務(wù)會(huì)自動(dòng)被取消叉寂。
3.由function*定義的generator(生成器)
generator(生成器)是ES6標(biāo)準(zhǔn)引入的新的數(shù)據(jù)類型萍启。一個(gè)generator看上去像一個(gè)函數(shù),但可以返回多次屏鳍。 generator和函數(shù)不同的是勘纯,generator由function定義(注意多出的號(hào)),并且钓瞭,除了return語(yǔ)句驳遵,還可以用yield返回多次。
4.encodeURI山涡、encodeURIComponent堤结、decodeURI、decodeURIComponent
-
這四個(gè)方法的用處
1鸭丛、用來(lái)編碼和解碼URI的
統(tǒng)一資源標(biāo)識(shí)符竞穷,或叫做 URI,是用來(lái)標(biāo)識(shí)互聯(lián)網(wǎng)上的資源(例如系吩,網(wǎng)頁(yè)或文件)和怎樣訪問(wèn)這些資源的傳輸協(xié)議(例如来庭,HTTP 或 FTP)的字符串。除了encodeURI穿挨、encodeURIComponent月弛、decodeURI肴盏、decodeURIComponent四個(gè)用來(lái)編碼和解碼 URI 的函數(shù)之外 ECMAScript 語(yǔ)言自身不提供任何使用 URL 的支持。2帽衙、URI組成形式
一個(gè) URI 是由組件分隔符分割的組件序列組成菜皂。其一般形式是:
Scheme : First / Second ; Third ? Fourth
其中斜體的名字代表組件;“:”, “/”, “;”厉萝,“?”是當(dāng)作分隔符的保留字符恍飘。3、有和不同谴垫?
encodeURI 和 decodeURI 函數(shù)操作的是完整的 URI章母;這倆函數(shù)假定 URI 中的任何保留字符都有特殊意義,所有不會(huì)編碼它們翩剪。
encodeURIComponent 和 decodeURIComponent 函數(shù)操作的是組成 URI 的個(gè)別組件乳怎;這倆函數(shù)假定任何保留字符都代表普通文本,所以必須編碼它們前弯,所以它們(保留字符)出現(xiàn)在一個(gè)完整 URI 的組件里面時(shí)不會(huì)被解釋成保留字符了蚪缀。
以上說(shuō)明摘自ECMAScript標(biāo)準(zhǔn),為了容易讀懂做了點(diǎn)編輯加工恕出。
4询枚、圖解四個(gè)函數(shù)的不同:
當(dāng) URI 里包含一個(gè)沒(méi)在上面列出的字符或有時(shí)不想讓給定的保留字符有特殊意義,那么必須編碼這個(gè)字符浙巫。字符被轉(zhuǎn)換成 UTF-8 編碼金蜀,首先從 UT??F-16 轉(zhuǎn)換成相應(yīng)的代碼點(diǎn)值的替代。然后返回的字節(jié)序列轉(zhuǎn)換為一個(gè)字符串狈醉,每個(gè)字節(jié)用一個(gè)“%xx”形式的轉(zhuǎn)移序列表示廉油。(具體轉(zhuǎn)換規(guī)則可以參考抽象操作Encode和Decode的說(shuō)明)
5.toUTCString
可根據(jù)世界時(shí)(UTC)把Data對(duì)象轉(zhuǎn)換為字符串,并返回結(jié)果
6.Infinity:無(wú)窮大
7.@keyframes:創(chuàng)建動(dòng)畫(一般要注意瀏覽器的兼容性)
@keyframes animationname {keyframes-selector {css-styles;}}
animationname:聲明動(dòng)畫的名稱苗傅。
keyframes-selector:用來(lái)劃分動(dòng)畫的時(shí)長(zhǎng)抒线,可以使用百分比形式,也可以使用 "from"和 "to"的形式渣慕。"from" 和 "to"的形式等價(jià)于 0% 和 100%建議始終使用百分比形式嘶炭。
8.git clone時(shí),報(bào)403錯(cuò)誤
剛開始以為是項(xiàng)目組那邊沒(méi)有授權(quán)逊桦,但感覺(jué)又不對(duì)眨猎,找了一下發(fā)現(xiàn)是git 客戶端緩存了錯(cuò)誤的密碼,解決方法:
1强经、增加遠(yuǎn)程地址的時(shí)候帶上密碼睡陪。(推薦)
git clone https://zhuyan.luo:[welcome123@git.zhishinet.com](mailto:welcome123@git.zhishinet.com)/zhishinet/TeacherClient/
2、運(yùn)行命令:rm ~/.git-credentials,刪掉git config --global credential.helper store保存的賬號(hào)和密碼兰迫⌒攀猓回到每次輸入用戶名和密碼。
~/.git-credentials
9.Object.assign()
[FROM_DRAFT_TO_PERSON]: (state, action: Action<any>) => {
return Object.assign({},state,{
fromDraftsToPersonFlag: action.payload
})
},
Object.assign()用于把一個(gè)或多個(gè)源對(duì)象的可枚舉屬性復(fù)制到目標(biāo)對(duì)象中汁果,返回值為目標(biāo)對(duì)象
10.JavaScript中的可枚舉屬性與不可枚舉屬性
在JavaScript中涡拘,對(duì)象的屬性分為可枚舉和不可枚舉之分,它們是由屬性的enumerable值決定的据德■Γ可枚舉性決定了這個(gè)屬性能否被for…in查找遍歷到。js中基本包裝類型的原型屬性是不可枚舉的棘利,如Object, Array, Number等橱野,
11.count = (count + '') === '0' ? '0' : count; (count是id)
這樣做可避免 !1=false,!0=true (!'0'=false)
12.Store
Store 是保存數(shù)據(jù)的地方,可以把它看成一個(gè)容器,整個(gè)應(yīng)用只能有一個(gè) Store赡译。Redux 提供createStore這個(gè)函數(shù)來(lái)生成 Store仲吏。
import { createStore } from 'redux';
const store = createStore(fn);
上面代碼中聋亡,createStore函數(shù)接受另一個(gè)函數(shù)作為參數(shù)夫嗓,返回新生成的 Store 對(duì)象喜喂。
13.State
Store對(duì)象包含所有數(shù)據(jù)。如果想得到某個(gè)時(shí)點(diǎn)的數(shù)據(jù)只洒,就要對(duì) Store 生成快照。這種時(shí)點(diǎn)的數(shù)據(jù)集合劳坑,就叫做 State毕谴。
當(dāng)前時(shí)刻的 State,可以通過(guò)store.getState()拿到距芬。
14.box-shadow 陰影
用法:box-shadow: 水平陰影的位置(可為負(fù)值) 垂直陰影的位置(可為負(fù)值) [模糊距離] [陰影的尺寸] [陰影的顏色] [陰影類型 (outset涝开、inset)];
實(shí)現(xiàn)鼠標(biāo)hover時(shí)延遲出現(xiàn)陰影(結(jié)合transition-duration、transition-property兩個(gè)屬性使用)
#edit_card {
width: 100%;
height: auto;
transition-duration: .8s;
transition-property: box-shadow;
&:hover{
box-shadow: 0 0 12px rgb(153,153,153);
}
}
15.多重邊框?qū)崿F(xiàn)
1框仔、 outline實(shí)現(xiàn)
不足之處:
2舀武、 box-shadow實(shí)現(xiàn)
16.在入口文件app.tsx中引入了react-hot-loader中的AppContainer組件,這個(gè)組件下的所有子組件都會(huì)在發(fā)生變化時(shí)觸發(fā)熱更新
17. 在Typescript中Table組件使用fixed屬性報(bào)錯(cuò)
解決方法:https://github.com/ant-design/ant-design/issues/3772#issuecomment-259358384
①定義columns時(shí)TableColumnConfig給any的類型:columns: TableColumnConfig<any>[] = [...]
②給列定義fixed屬性時(shí)寫成:fixed: 'right' as 'right'
③或者寫成下面這樣
import React, { Component } from 'react';
import { Table } from 'antd';
import { TableColumnConfig } from 'antd/lib/table/Table';
interface Person {
name: string;
}
const columns: TableColumnConfig<Person>[] = [{
title: 'Name',
dataIndex: 'name',
fixed: 'right',
}];
const data: Person[] = [{
name: 'Jack',
}];
class PersonTable extends Table<Person> {}
class App extends Component<null, null> {
render() {
return (
<PersonTable columns={columns} dataSource={data} />
)
}
}
18.antd的Select組件离斩,普通的在輸入框后面都帶有向下的箭頭银舱,并且不可輸入,加上 mode="combobox" 屬性后跛梗,下拉框就像一個(gè)輸入框寻馏,既可以輸入又能選擇;加上showSearch optionFilterProp="children" 后可過(guò)濾搜索
19.antd在給組件添加默認(rèn)值時(shí),不在Form組件中直接使用 defaultValue 就行核偿,但在Form表單中需要寫成:initialValue
<FormItem {...formItemLayout} label='保單編號(hào)' style={{marginBottom:'0'}}>
{getFieldDecorator('policyNumber',{
initialValue:fields.policyNumber?fields.policyNumber:''
})(
<Input disabled="disabled"/>
)}
</FormItem>
20.table排序:
本地排序使用一個(gè)函數(shù)(參考 Array.sort 的 compareFunction)诚欠,需要服務(wù)端排序可設(shè)為 true
21.新增的時(shí)候要傳空對(duì)象過(guò)去,否則先點(diǎn)擊編輯再點(diǎn)擊新增,新增界面會(huì)和編輯界面一樣(對(duì)象會(huì)被緩存)
const handleAdd = () => {
debugger;
onShowModal({
modalType: 'create',
currentItem: {},
});
}
const handleEdit = (item: any) => {
debugger;
onShowModal({
modalType: 'update',
currentItem: item,
});
};
22.Moment.js
日期轉(zhuǎn)時(shí)間戳:Date.parse(this.props.form.getFieldValue('startDate')[0])
時(shí)間戳轉(zhuǎn)日期:moment.unix(text).format('YYYY-MM-DD HH:mm')
23.需要全局使用的數(shù)據(jù)在 根RootContainer中獲取
24.對(duì)于一個(gè)查詢最好定義四個(gè)action
//獲取排課表信息周\月數(shù)據(jù)量
export const COUNT_QUERY = 'scheduleValues/COUNT';
export const COUNT_QUERY_SUCCESS = 'scheduleValues/COUNT_SUCCESS';
export const COUNT_QUERY_ERROR = 'scheduleValues/COUNT_ERROR';
export const COUNT_QUERY_FAILED = 'scheduleValues/COUNT_FAILED';
25.對(duì)于請(qǐng)求返回的data的類型不同(對(duì)象轰绵、數(shù)組)粉寞,要注意yield put(queryCountSuccess(data));,對(duì)象傳data,數(shù)組傳data.rows
//獲取排課表信息周\月數(shù)據(jù)量
function* queryCount(action: Action<any>) {
try {
let params = {};
const data = yield request({
url: countUrl,
method: 'get',
data: params,
});
if(data.success){
yield put(queryCountSuccess(data));
} else {
yield put(queryCountError(data.status));
}
} catch (e) {
yield put(queryCountFailed(e.message));
}
}
26.注意下這個(gè) as Array,as Object
[LEVELS_QUERY_ERROR]: (state, action: Action<any>) => {
return Object.assign({}, state, {
levelList: action.payload as Array<any>,
});
},
[LEVELS_QUERY_FAILED]: (state, action: Action<Array<Object>>) => {
return Object.assign({}, state, {
levelList: action.payload as Object,
});
},
27.下拉列表聯(lián)動(dòng)
studentSelect(value: any){
let school = null;
for(let i in this.props.studentList){
if(value === this.props.studentList[i].userId ){
school = this.props.studentList[i].school;
break;
}
}
this.props.form.setFieldsValue({school: school}) ;
}
<Select
placeholder="學(xué)生/手機(jī)"
style={{ width: '100%' }}
onChange={this.studentSelect.bind(this)}
>
{
this.props.studentList !== undefined && this.props.studentList!=="" &&
this.props.studentList.map((item: any) =>
<Option key={item.userId} value={item.userId} >{item.firstName} / {item.cellNumber}</Option>
)
}
</Select>
28.根據(jù)接口返回?cái)?shù)據(jù)的類型調(diào)用不同的請(qǐng)求方法藏澳,返回是json使用request; 返回字符串或者無(wú)返回值的使用autoRefreshTokenFetch,再將返回?cái)?shù)據(jù)使用 .json()轉(zhuǎn)化成json
//獲取活躍人數(shù) (接口只返回了 11)
function* queryActiveCount(action: Action<any>) {
try {
const request = {
method: 'GET',
credentials: 'include',
headers: {
'Authorization': (window as GlobalDefinitions).authorization,
'Accept': 'application/json',
'Content-Type': 'application/json',
'Cache-Control':' no-cache'
},
url: activeCountUrl +'/TEACHER'
};
const data = (yield call(autoRefreshTokenFetch, request));
if(data.ok){
let json = yield data.json();
yield put(queryActiveCountSuccess(json));
} else {
yield put(queryActiveCountError(data.status));
}
} catch (e) {
yield put(queryActiveCountFailed(e.message));
}
}
//獲取英語(yǔ)仁锯、數(shù)學(xué)人數(shù)(接口返回json {English: 8, Math: 3} )
function* querySubjectCount(action: Action<any>) {
try {
let params = {};
const data = yield request({
url: subjectCountUrl,
method: 'get',
data: params,
});
if(data.success){
yield put(querySubjectCountSuccess(data));
} else {
yield put(querySubjectCountError(data.statusCode));
}
} catch (e) {
yield put(querySubjectCountFailed(e.message));
}
}
29.Select的value只能是String類型的數(shù)據(jù),有時(shí)候數(shù)據(jù)庫(kù)取出來(lái)的是Number的翔悠,想要利用initialValue初始顯示在Form表單中的話需要將Number的轉(zhuǎn)化成String,否則在下拉框中將會(huì)直接顯示數(shù)字
initialValue: item.gender? item.gender.toString():'',
30.在Form表單中业崖,想要使按Enter鍵的作用和點(diǎn)擊某個(gè)按鈕的作用一樣,可以在那個(gè)按鈕上加 htmlType="submit" 屬性
比如在輸入框輸入完?yáng)|西后想按enter鍵進(jìn)行查詢蓄愁,那么可以在 查詢 按鈕上加該屬性
31.省份provinceList和學(xué)校schoolList級(jí)聯(lián)
componentWillMount(){
let provinceList = this.props.provinceList || [];
let schoolList = this.props.schoolList || [];
let options = [];
for(let i in provinceList){
debugger
let temp:any = {};
temp.value = provinceList[i].lookupCode;
temp.label = provinceList[i].lookupValue;
temp.children = [];
for(let j in schoolList){
if(schoolList[j].parentValue == provinceList[i].value){
let subTemp: any = {};
subTemp.value = schoolList[j].lookupCode;
subTemp.label = schoolList[j].lookupValue;
temp.children.push(subTemp);
}
}
options.push(temp);
}
this.setState({
options: options,
})
}
32.正則表達(dá)式
/^(?![0-9]+)[0-9A-Za-z]{6,20}) 預(yù)測(cè)該位置后面不全是數(shù)字
(?![a-zA-Z]+ 匹配行結(jié)尾位置
33.登錄按鈕loading狀態(tài)做法
在點(diǎn)擊按鈕請(qǐng)求登錄接口之前將loading置為true,請(qǐng)求登錄接口成功(requestLoginSuccess),在成功那里將loading置為false,請(qǐng)求接口失敗同理
34.返回上一頁(yè)
window.location.reload(); //刷新
window.history.go(1); //前進(jìn)
window.history.go(-1); //返回+刷新
window.history.forward(); //前進(jìn)
window.history.back(); //返回
location.href=document.referrer; //document.referrer是獲取上一頁(yè)的url
history.length; //查看歷史中的頁(yè)面數(shù)
35.<Link style={{color: '#666'}} to={/CourseManagement/course/schedule
}><Icon type="left"/> 返回</Link>
36.分頁(yè)組件自定義每頁(yè)條數(shù)pageSizeOptions
pagination: {
...pagination,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: ['10','20','50','100','200','500'],
},
37.Select要求value的類型要為string双炕,將number轉(zhuǎn)化為string的方法為:加個(gè)'',但要注意在初始化時(shí)也要給初始值加上'',否則顯示不出value對(duì)應(yīng)的值撮抓,同時(shí)后臺(tái)需要number類型的數(shù)據(jù)時(shí)記得傳過(guò)去的時(shí)候要用parseInt將字符串轉(zhuǎn)成數(shù)字
<FormItem {...formItemLayout} label="學(xué)生">
{getFieldDecorator('userId', {
initialValue: ''+item.userId,
rules: [
{ required: true, message:'學(xué)生不能為空妇斤!',},
],
})(
<Select
placeholder="學(xué)生/手機(jī)"
style={{ width: '100%' }}
onChange={this.studentSelect.bind(this)}
>
{
studentList !== undefined && studentList!=="" &&
studentList.map((item: any, i: any) =>
<Option key={item.userId} value={''+item.userId} >{item.firstName} / {item.cellNumber} {item.school}</Option>
)
}
</Select>
)}
</FormItem>
38.芝士網(wǎng)登錄流程
userLogin: `${baseUrl}/api/zauth/v1/token/access`, //登錄認(rèn)證,獲取token
refreshToken: `${baseUrl}/api/zauth/v1/token/refresh`, //token有過(guò)期時(shí)間的,過(guò)期了 需要通過(guò) refreshToken 重新拿 token
userInfo: `${baseUrl}/api/HomePageAPI/GetUserInfo`, //傳一個(gè)userId獲取用戶信息丹拯。(userId是在 知識(shí)網(wǎng) 登錄頁(yè)面登錄成功后會(huì)把userId保存到localStorage里面,現(xiàn)在在我們的工程里沒(méi)有存userId的過(guò)程只有取的過(guò)程站超,在app.tsx中可看到)
39.控制臺(tái)報(bào)錯(cuò)
Cannot read property 'getFieldDecorator' of undefined
是因?yàn)槭褂昧薋orm沒(méi)有調(diào)用Form.create()
40.import一個(gè)組件時(shí),如果組件導(dǎo)出時(shí)使用了關(guān)鍵字default乖酬,則導(dǎo)入時(shí)不需將組件用{},若沒(méi)有default則需要
export const Login = Form.create()(LoginForm);
import {Login} from "./containers/CourseManagement/Login/RootContainer/index";
41.JS在1.6中為Array新增了幾個(gè)方法map()死相,filter(),some()咬像,every()算撮,forEach(),也就是一共有這么多方法了县昂。
map():返回一個(gè)新的Array肮柜,每個(gè)元素為調(diào)用func的結(jié)果
filter():返回一個(gè)符合func條件的元素?cái)?shù)組
some():返回一個(gè)boolean,判斷是否有元素是否符合func條件
every():返回一個(gè)boolean倒彰,判斷每個(gè)元素是否符合func條件
forEach():沒(méi)有返回值审洞,只是針對(duì)每個(gè)元素調(diào)用func
42.Promise (https://www.cnblogs.com/lvdabao/p/es6-promise-1.html)
Promise是一個(gè)構(gòu)造函數(shù),自己身上有all狸驳、reject预明、resolve這幾個(gè)眼熟的方法,原型上有then耙箍、catch等同樣很眼熟的方法撰糠。這么說(shuō)用Promise new出來(lái)的對(duì)象肯定就有then、catch方法辩昆。
var p = new Promise(function(resolve, reject){
//做一些異步操作
setTimeout(function(){
console.log('執(zhí)行完成');
resolve('隨便什么數(shù)據(jù)');
}, 2000);
});
Promise的構(gòu)造函數(shù)接收一個(gè)參數(shù)(是函數(shù))阅酪,這個(gè)參數(shù)又傳入兩個(gè)參數(shù):resolve,reject,分別表示異步操作執(zhí)行成功后的回調(diào)函數(shù)和異步操作執(zhí)行失敗后的回調(diào)函數(shù)术辐。其實(shí)這里用“成功”和“失敗”來(lái)描述并不準(zhǔn)確砚尽,按照標(biāo)準(zhǔn)來(lái)講,resolve是將Promise的狀態(tài)置為fullfiled辉词,reject是將Promise的狀態(tài)置為rejected必孤。
在上面的代碼中,我們執(zhí)行了一個(gè)異步操作瑞躺,也就是setTimeout敷搪,2秒后,輸出“執(zhí)行完成”幢哨,并且調(diào)用resolve方法赡勘。
運(yùn)行代碼,會(huì)在2秒后輸出“執(zhí)行完成”捞镰。注意闸与!我只是new了一個(gè)對(duì)象,并沒(méi)有調(diào)用它岸售,我們傳進(jìn)去的函數(shù)就已經(jīng)執(zhí)行了践樱,這是需要注意的一個(gè)細(xì)節(jié)。所以我們用Promise的時(shí)候一般是包在一個(gè)函數(shù)中凸丸,在需要的時(shí)候去運(yùn)行這個(gè)函數(shù)映胁,如
function runAsync(){
var p = new Promise(function(resolve, reject){
//做一些異步操作
setTimeout(function(){
console.log('執(zhí)行完成');
resolve('隨便什么數(shù)據(jù)');
}, 2000);
});
return p;
}
runAsync()
在我們包裝好的函數(shù)最后,會(huì)return出Promise對(duì)象甲雅,也就是說(shuō),執(zhí)行這個(gè)函數(shù)我們得到了一個(gè)Promise對(duì)象坑填。還記得Promise對(duì)象上有then抛人、catch方法吧?這就是強(qiáng)大之處了脐瑰,看下面的代碼
runAsync().then(function(data){
console.log(data);
//后面可以用傳過(guò)來(lái)的數(shù)據(jù)做些其他操作
//......
});
在runAsync()的返回上直接調(diào)用then方法妖枚,then接收一個(gè)參數(shù),是函數(shù)苍在,并且會(huì)拿到我們?cè)趓unAsync中調(diào)用resolve時(shí)傳的的參數(shù)绝页。運(yùn)行這段代碼,會(huì)在2秒后輸出“執(zhí)行完成”寂恬,緊接著輸出“隨便什么數(shù)據(jù)”续誉。
這時(shí)候你應(yīng)該有所領(lǐng)悟了,原來(lái)then里面的函數(shù)就跟我們平時(shí)的回調(diào)函數(shù)一個(gè)意思初肉,能夠在runAsync這個(gè)異步任務(wù)執(zhí)行完成之后被執(zhí)行酷鸦。這就是Promise的作用了,簡(jiǎn)單來(lái)講,就是能把原來(lái)的回調(diào)寫法分離出來(lái)臼隔,在異步操作執(zhí)行完后嘹裂,用鏈?zhǔn)秸{(diào)用的方式執(zhí)行回調(diào)函數(shù)。
你可能會(huì)不屑一顧摔握,那么牛逼轟轟的Promise就這點(diǎn)能耐寄狼?我把回調(diào)函數(shù)封裝一下,給runAsync傳進(jìn)去不也一樣嗎氨淌,就像這樣:
function runAsync(callback){
setTimeout(function(){
console.log('執(zhí)行完成');
callback('隨便什么數(shù)據(jù)');
}, 2000);
}
runAsync(function(data){
console.log(data);
});
效果也是一樣的泊愧,還費(fèi)勁用Promise干嘛。那么問(wèn)題來(lái)了宁舰,有多層回調(diào)該怎么辦拼卵?如果callback也是一個(gè)異步操作,而且執(zhí)行完后也需要有相應(yīng)的回調(diào)函數(shù)蛮艰,該怎么辦呢腋腮?總不能再定義一個(gè)callback2,然后給callback傳進(jìn)去吧壤蚜。而Promise的優(yōu)勢(shì)在于即寡,可以在then方法中繼續(xù)寫Promise對(duì)象并返回,然后繼續(xù)調(diào)用then來(lái)進(jìn)行回調(diào)操作袜刷。
(鏈?zhǔn)讲僮鞯挠梅ǎ┧源细唬瑥谋砻嫔峡矗琍romise只是能夠簡(jiǎn)化層層回調(diào)的寫法著蟹,而實(shí)質(zhì)上墩蔓,Promise的精髓是“狀態(tài)”,用維護(hù)狀態(tài)萧豆、傳遞狀態(tài)的方式來(lái)使得回調(diào)函數(shù)能夠及時(shí)調(diào)用奸披,它比傳遞callback函數(shù)要簡(jiǎn)單、靈活的多涮雷。所以使用Promise的正確場(chǎng)景是這樣的:
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return runAsync3();
})
.then(function(data){
console.log(data);
});
這樣能夠按順序阵面,每隔兩秒輸出每個(gè)異步回調(diào)中的內(nèi)容,在runAsync2中傳給resolve的數(shù)據(jù)洪鸭,能在接下來(lái)的then方法中拿到样刷。
在then方法中,你也可以直接return數(shù)據(jù)而不是Promise對(duì)象览爵,在后面的then中就可以接收到數(shù)據(jù)了置鼻,比如我們把上面的代碼修改成這樣:
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return '直接返回?cái)?shù)據(jù)'; //這里直接返回?cái)?shù)據(jù)
})
.then(function(data){
console.log(data);
});
(reject的用法)
到這里,你應(yīng)該對(duì)“Promise是什么玩意”有了最基本的了解拾枣。那么我們接著來(lái)看看ES6的Promise還有哪些功能沃疮。我們光用了resolve盒让,還沒(méi)用reject呢,它是做什么的呢司蔬?事實(shí)上邑茄,我們前面的例子都是只有“執(zhí)行成功”的回調(diào),還沒(méi)有“失敗”的情況俊啼,reject的作用就是把Promise的狀態(tài)置為rejected肺缕,這樣我們?cè)趖hen中就能捕捉到,然后執(zhí)行“失敗”情況的回調(diào)授帕⊥荆看下面的代碼。
function getNumber(){
var p = new Promise(function(resolve, reject){
//做一些異步操作
setTimeout(function(){
var num = Math.ceil(Math.random()*10); //生成1-10的隨機(jī)數(shù)
if(num<=5){
resolve(num);
}
else{
reject('數(shù)字太大了');
}
}, 2000);
});
return p;
}
getNumber()
.then(
function(data){
console.log('resolved');
console.log(data);
},
function(reason, data){
console.log('rejected');
console.log(reason);
}
);
(catch的用法)
我們知道Promise對(duì)象除了then方法跛十,還有一個(gè)catch方法彤路,它是做什么用的呢?其實(shí)它和then的第二個(gè)參數(shù)一樣芥映,用來(lái)指定reject的回調(diào)洲尊,用法是這樣:
getNumber()
.then(function(data){
console.log('resolved');
console.log(data);
})
.catch(function(reason){
console.log('rejected');
console.log(reason);
});
效果和寫在then的第二個(gè)參數(shù)里面一樣。不過(guò)它還有另外一個(gè)作用:在執(zhí)行resolve的回調(diào)(也就是上面then中的第一個(gè)參數(shù))時(shí)奈偏,如果拋出異常了(代碼出錯(cuò)了)坞嘀,那么并不會(huì)報(bào)錯(cuò)卡死js,而是會(huì)進(jìn)到這個(gè)catch方法中惊来。請(qǐng)看下面的代碼:
getNumber()
.then(function(data){
console.log('resolved');
console.log(data);
console.log(somedata); //此處的somedata未定義
})
.catch(function(reason){
console.log('rejected');
console.log(reason);
});
在resolve的回調(diào)中丽涩,我們console.log(somedata);而somedata這個(gè)變量是沒(méi)有被定義的。如果我們不用Promise裁蚁,代碼運(yùn)行到這里就直接在控制臺(tái)報(bào)錯(cuò)了矢渊,不往下運(yùn)行了。但
也就是說(shuō)進(jìn)到catch方法里面去了枉证,而且把錯(cuò)誤原因傳到了reason參數(shù)中昆淡。即便是有錯(cuò)誤的代碼也不會(huì)報(bào)錯(cuò)了,這與我們的try/catch語(yǔ)句有相同的功能刽严。
(all的用法)
Promise的all方法提供了并行執(zhí)行異步操作的能力咸这,并且在所有異步操作執(zhí)行完后才執(zhí)行回調(diào)采够。我們?nèi)耘f使用上面定義好的runAsync1报破、runAsync2滔悉、runAsync3這三個(gè)函數(shù)啸胧,看下面的例子Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});
用Promise.all來(lái)執(zhí)行借杰,all接收一個(gè)數(shù)組參數(shù)斩箫,里面的值最終都算返回Promise對(duì)象里伯。這樣含思,三個(gè)異步操作的并行執(zhí)行的崎弃,等到它們都執(zhí)行完后才會(huì)進(jìn)到then里面甘晤。那么,三個(gè)異步操作返回的數(shù)據(jù)哪里去了呢饲做?都在then里面呢线婚,all會(huì)把所有異步操作的結(jié)果放進(jìn)一個(gè)數(shù)組中傳給then,就是上面的results盆均。
有了all塞弊,你就可以并行執(zhí)行多個(gè)異步操作,并且在一個(gè)回調(diào)中處理所有的返回?cái)?shù)據(jù)泪姨,是不是很酷游沿?有一個(gè)場(chǎng)景是很適合用這個(gè)的,一些游戲類的素材比較多的應(yīng)用肮砾,打開網(wǎng)頁(yè)時(shí)诀黍,預(yù)先加載需要用到的各種資源如圖片、flash以及各種靜態(tài)文件仗处。所有的都加載完后眯勾,我們?cè)龠M(jìn)行頁(yè)面的初始化。
(race的用法)
all方法的效果實(shí)際上是「誰(shuí)跑的慢疆柔,以誰(shuí)為準(zhǔn)執(zhí)行回調(diào)」咒精,那么相對(duì)的就有另一個(gè)方法「誰(shuí)跑的快,以誰(shuí)為準(zhǔn)執(zhí)行回調(diào)」旷档,這就是race方法模叙,這個(gè)詞本來(lái)就是賽跑的意思。race的用法與all一樣鞋屈,我們把上面runAsync1的延時(shí)改為1秒來(lái)看一下:
Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});
這三個(gè)異步操作同樣是并行執(zhí)行的范咨。結(jié)果你應(yīng)該可以猜到,1秒后runAsync1已經(jīng)執(zhí)行完了厂庇,此時(shí)then里面的就執(zhí)行了渠啊,你猜對(duì)了嗎?不完全权旷,是吧替蛉。在then里面的回調(diào)開始執(zhí)行時(shí),runAsync2()和runAsync3()并沒(méi)有停止拄氯,仍舊再執(zhí)行躲查。于是再過(guò)1秒后,輸出了他們結(jié)束的標(biāo)志译柏。
這個(gè)race有什么用呢镣煮?使用場(chǎng)景還是很多的,比如我們可以用race給某個(gè)異步請(qǐng)求設(shè)置超時(shí)時(shí)間鄙麦,并且在超時(shí)后執(zhí)行相應(yīng)的操作典唇,代碼如下:
//請(qǐng)求某個(gè)圖片資源function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx';
});
return p;
}
//延時(shí)函數(shù)镊折,用于給請(qǐng)求計(jì)時(shí)function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('圖片請(qǐng)求超時(shí)');
}, 5000);
});
return p;
}
Promise
.race([requestImg(), timeout()])
.then(function(results){
console.log(results);
})
.catch(function(reason){
console.log(reason);
});
requestImg函數(shù)會(huì)異步請(qǐng)求一張圖片,我把地址寫為"xxxxxx"介衔,所以肯定是無(wú)法成功請(qǐng)求到的恨胚。timeout函數(shù)是一個(gè)延時(shí)5秒的異步操作。我們把這兩個(gè)返回Promise對(duì)象的函數(shù)放進(jìn)race夜牡,于是他倆就會(huì)賽跑与纽,如果5秒之內(nèi)圖片請(qǐng)求成功了,那么遍進(jìn)入then方法塘装,執(zhí)行正常的流程急迂。如果5秒鐘圖片還未成功返回,那么timeout就跑贏了蹦肴,則進(jìn)入catch僚碎,報(bào)出“圖片請(qǐng)求超時(shí)”的信息。運(yùn)行結(jié)果如下:
43.Array.from
ES6為Array增加了from函數(shù)用來(lái)將其他對(duì)象轉(zhuǎn)換成數(shù)組阴幌。
當(dāng)然勺阐,其他對(duì)象也是有要求,也不是所有的矛双,可以將兩種對(duì)象轉(zhuǎn)換成數(shù)組渊抽。
1.部署了Iterator接口的對(duì)象,比如:Set议忽,Map懒闷,Array。
2.類數(shù)組對(duì)象栈幸,什么叫類數(shù)組對(duì)象愤估,就是一個(gè)對(duì)象必須有l(wèi)ength屬性,沒(méi)有l(wèi)ength速址,轉(zhuǎn)出來(lái)的就是空數(shù)組玩焰。
44.dva/dynamic
解決組件動(dòng)態(tài)加載問(wèn)題的 util 方法。
比如:
import dynamic from 'dva/dynamic';
const UserPageComponent = dynamic({
app,
models: () => [
import('./models/users'),
],
component: () => import('./routes/UserPage'),
});
opts 包含:
app: dva 實(shí)例芍锚,加載 models 時(shí)需要
models: 返回 Promise 數(shù)組的函數(shù)昔园,Promise 返回 dva model
component:返回 Promise 的函數(shù),Promise 返回 React Component
45.dva API
* app = dva(opts) --創(chuàng)建應(yīng)用并炮,返回 dva 實(shí)例蒿赢。(注:dva 支持多實(shí)例)
opts 包含:
*history*:指定給路由用的 history,默認(rèn)是 hashHistory
*initialState*:指定初始數(shù)據(jù)渣触,優(yōu)先級(jí)高于 model 中的 state,默認(rèn)是 {}
* app.use({}) --配置 hooks 或者注冊(cè)插件
* app.model(model) --注冊(cè) model
* app.unmodel(namespace) --取消 model 注冊(cè)壹若,清理 reducers, effects 和 subscriptions嗅钻。subscription 如果沒(méi)有返回 unlisten 函數(shù)皂冰,使用 app.unmodel 會(huì)給予警告
* app.router(router) --注冊(cè)路由表
* app.start('#root') --啟動(dòng)應(yīng)用
46.react項(xiàng)目使用npm build命令(將開發(fā)完的前端代碼,利用webpack打包成靜態(tài)壓縮文件)構(gòu)建出靜態(tài)文件养篓,這些靜態(tài)文件可以直接在瀏覽器打開秃流,之前的財(cái)聯(lián)邦項(xiàng)目發(fā)布就是使用的這個(gè)方式,同樣還可以在服務(wù)器安裝nodejs柳弄,然后把代碼clone過(guò)去直接用npm start命令也可以啟動(dòng)項(xiàng)目訪問(wèn)頁(yè)面(在本地開發(fā)的時(shí)候就是這樣)
47.nodejs前端服務(wù)器的職責(zé)
* 作為靜態(tài)文件服務(wù)器舶胀,當(dāng)用戶訪問(wèn)網(wǎng)站的時(shí)候,將index.html以及其引入的js碧注、css嚣伐、fonts以及圖片返回給用戶
* 負(fù)責(zé)將客戶端發(fā)來(lái)的ajax請(qǐng)求轉(zhuǎn)發(fā)給后臺(tái)服務(wù)器
48.map()中的元素都需要屬性key。在哪兒循環(huán)就在哪兒設(shè)置key
49.key用來(lái)作為React的觀察點(diǎn)萍丐,但它們不會(huì)傳遞給組件轩端。 如果你需要在組件中使用相同的值,則使用不同的名稱顯式地將它作為props傳遞:
const content = posts.map(post =>
<Post key={post.id} id={post.id} title={post.title} />
);
使用上面的示例逝变,Post組件可以讀取props.id基茵,但不能讀取props.key
50.如果有幾個(gè)組件需要反映相同的變化數(shù)據(jù),建議將共享state提升到層級(jí)最近的壳影,并且是共同的父組件上拱层。
對(duì)于在React應(yīng)用程序中更改的任何數(shù)據(jù),都應(yīng)該有一個(gè)唯一的“數(shù)據(jù)來(lái)源”宴咧,也就是state根灯。通常,首先將state添加到需要渲染的組件悠汽。如果其他組件也需要它箱吕,你可以將其提升到它們層級(jí)最近的共同父級(jí)組件中。而不是嘗試在不同組件之間去同步狀態(tài)柿冲,總歸就一句話:你應(yīng)該依賴于自上而下的數(shù)據(jù)流
51.devtools
* eval 文檔上解釋的很明白茬高,每個(gè)模塊都封裝到 eval 包裹起來(lái),并在后面添加 //# sourceURL
* source-map 這是最原始的 source-map 實(shí)現(xiàn)方式假抄,其實(shí)現(xiàn)是打包代碼同時(shí)創(chuàng)建一個(gè)新的 sourcemap 文件怎栽, 并在打包文件的末尾添加 //# sourceURL 注釋行告訴 JS 引擎文件在哪兒
* hidden-source-map 文檔上也說(shuō)了,就是 soucremap 但沒(méi)注釋宿饱,沒(méi)注釋怎么找文件呢熏瞄?貌似只能靠后綴,譬如 xxx/bundle.js 文件谬以,某些引擎會(huì)嘗試去找 xxx/bundle.js.map
* inline-source-map 為每一個(gè)文件添加 sourcemap 的 DataUrl强饮,注意這里的文件是打包前的每一個(gè)文件而不是最后打包出來(lái)的,同時(shí)這個(gè) DataUrl 是包含一個(gè)文件完整 souremap 信息的 Base64 格式化后的字符串为黎,而不是一個(gè) url邮丰。
* eval-source-map 這個(gè)就是把 eval 的 sourceURL 換成了完整 souremap 信息的 DataUrl
* cheap-source-map 不包含列信息行您,不包含 loader 的 sourcemap,(譬如 babel 的 sourcemap)
* cheap-module-source-map 不包含列信息剪廉,同時(shí) loader 的 sourcemap 也被簡(jiǎn)化為只包含對(duì)應(yīng)行的娃循。最終的 sourcemap 只有一份,它是 webpack 對(duì) loader 生成的 sourcemap 進(jìn)行簡(jiǎn)化斗蒋,然后再次生成的捌斧。
* 這么多模式,到底該用哪個(gè)泉沾?
* cheap-module-eval-source-map 絕大多數(shù)情況下都會(huì)是最好的選擇捞蚂,這也是下版本 webpack 的默認(rèn)選項(xiàng)。
* 相關(guān)解釋:
* 大部分情況我們調(diào)試并不關(guān)心列信息爆哑,而且就算 sourcemap 沒(méi)有列洞难,有些瀏覽器引擎(例如 v8) 也會(huì)給出列信息,所以我們使用 cheap 模式可以大幅提高 souremap 生成的效率揭朝。
* 使用 eval 方式可大幅提高持續(xù)構(gòu)建效率队贱,參考 [webapck devtool 文檔](https://webpack.github.io/docs/configuration.html#devtool) 下方速度對(duì)比表格,這對(duì)經(jīng)常需要邊改邊調(diào)的前端開發(fā)而言潭袱,非常重要柱嫌!
* 使用 module 可支持 babel 這種預(yù)編譯工具(在 webpack 里做為 loader 使用)。
* eval-source-map 使用 DataUrl 本身包含完整 sourcemap 信息屯换,并不需要像 sourceURL 那樣编丘,瀏覽器需要發(fā)送一個(gè)完整請(qǐng)求去獲取 sourcemap 文件,這會(huì)略微提高點(diǎn)效率
- 52.React Developer Tools介紹
React Developer Tools 是一款由 facebook 開發(fā)的有用的 Chrome瀏覽器擴(kuò)展彤悔。通過(guò)它我們可以查看應(yīng)用程序的 React 組件分層結(jié)構(gòu)嘉抓,而不是更加神秘的瀏覽器 DOM 表示。
注意:該插件只對(duì) ReactJS 開發(fā)有效晕窑。如果是 React Native 的話則無(wú)法使用這個(gè)插件調(diào)試抑片。
安裝完擴(kuò)展程序后打開擴(kuò)展程序管理頁(yè)面。將 React Developer Tools 的“允許訪問(wèn)文件網(wǎng)址”勾選杨赤。
-
React Developer Tools使用說(shuō)明
(1)首先使用 Chrome 打開需要調(diào)試的 React 頁(yè)面敞斋,并打開“開發(fā)者工具”。
(2)在“開發(fā)者工具”上方工具欄最右側(cè)會(huì)有個(gè) react 標(biāo)簽疾牲。點(diǎn)擊這個(gè)標(biāo)簽就可以看到當(dāng)前應(yīng)用的結(jié)構(gòu)植捎。
通過(guò) React Developer Tools 我們可以很方便地看到各個(gè)組件之間的嵌套關(guān)系以及每個(gè)組件的事件、屬性阳柔、狀態(tài)等信息焰枢。
(3)React Developer Tools會(huì)自動(dòng)檢測(cè)React組件,不過(guò)在webpack-dev-server模式下,webpack會(huì)自動(dòng)將React組件放入到iframe下济锄,導(dǎo)致React組件檢測(cè)失敗枫匾,變通方法是webpack-dev-server配置在--inline模式下即可:
webpack-dev-server --inline
(5)修改某一處為錯(cuò)誤,然后觀察結(jié)果
56. this.props.children
this.props 對(duì)象的屬性與組件的屬性一一對(duì)應(yīng)拟淮,但是有一個(gè)例外,就是 this.props.children 屬性谴忧。它表示組件的所有子節(jié)點(diǎn)(查看 demo05)很泊。
var NotesList = React.createClass({
render: function() {
return (
<ol>
{
React.Children.map(this.props.children, function (child) {
return <li>{child}</li>;
})
}
</ol>
);
}});
ReactDOM.render(
<NotesList>
<span>hello</span>
<span>world</span>
</NotesList>,
document.body
);
上面代碼的 NoteList 組件有兩個(gè) span 子節(jié)點(diǎn),它們都可以通過(guò) this.props.children 讀取沾谓。
這里需要注意, this.props.children 的值有三種可能:如果當(dāng)前組件沒(méi)有子節(jié)點(diǎn),它就是 undefined ;如果有一個(gè)子節(jié)點(diǎn)菲盾,數(shù)據(jù)類型是 object 竿屹;如果有多個(gè)子節(jié)點(diǎn),數(shù)據(jù)類型就是 array 妇穴。所以爬虱,處理 this.props.children 的時(shí)候要小心。
React 提供一個(gè)工具方法 React.Children 來(lái)處理 this.props.children 腾它。我們可以用 React.Children.map 來(lái)遍歷子節(jié)點(diǎn)跑筝,而不用擔(dān)心 this.props.children 的數(shù)據(jù)類型是 undefined 還是 object。更多的 React.Children 的方法瞒滴,請(qǐng)參考官方文檔曲梗。
props.children可以像任何其他props那樣工作,它可以傳遞任何類型的數(shù)據(jù)妓忍,并不局限于那些告訴React應(yīng)該如何渲染的東東虏两。 例如,如果您有一個(gè)自定義組件世剖,您可以將props.children作為一個(gè)回調(diào)函數(shù):
-
布爾值定罢、null、undefined在渲染時(shí)會(huì)被自動(dòng)忽略
false搁廓,null引颈,undefined和true是有效的子元素,不過(guò)他們從根本上講是不參與渲染的境蜕。 這些JSX表達(dá)式將渲染處相同的東西:
如果你想要一個(gè)值如false蝙场,true,null或undefined出現(xiàn)在輸出中粱年,你必須先將它轉(zhuǎn)換為字符串:
57.JSX會(huì)刪除行的開始和結(jié)尾處的空格售滤。 它也會(huì)刪除中間的空行。 與標(biāo)簽相鄰的空行被會(huì)被刪除;
在字符串文本中間出現(xiàn)的空行會(huì)縮合成一個(gè)空格。
58.instanceof 運(yùn)算符用來(lái)測(cè)試一個(gè)對(duì)象在其原型鏈中是否存在一個(gè)構(gòu)造函數(shù)的 prototype 屬性完箩。
object instanceof constructor (object--要檢測(cè)的對(duì)象赐俗,constructor--某個(gè)構(gòu)造函數(shù))
- 59.window.scrollTo和window.scrollBy (to是絕對(duì)的意思(從整體而言),by是相對(duì)的意思(從原先的位置而言)
scrollTo:在窗體中如果有滾動(dòng)條弊知,將橫向滾動(dòng)條移動(dòng)到相對(duì)于窗體寬度為x個(gè)
像素的位置阻逮,將縱向滾動(dòng)條移動(dòng)到相對(duì)于窗體高度為y個(gè)像素的位置
scrollBy:(要使此方法工作 window 滾動(dòng)條的可見屬性必須設(shè)置為true!)
如果有滾動(dòng)條秩彤,將橫向滾動(dòng)條移動(dòng)到相對(duì)于當(dāng)前橫向滾動(dòng)條的x個(gè)像素的位置
(就是向左移動(dòng)x像素)叔扼,將縱向滾動(dòng)條移動(dòng)到相對(duì)于當(dāng)前縱向滾動(dòng)條高度為y個(gè)像素的位置(就是向下移動(dòng)y像素)
60.npm --save-dev --save 的區(qū)別
npm install 在安裝 npm 包時(shí),有兩種命令參數(shù)可以把它們的信息寫入 package.json 文件漫雷,一個(gè)是npm install--save另一個(gè)是 npm install –save-dev瓜富,他們表面上的區(qū)別是--save 會(huì)把依賴包名稱添加到 package.json 文件 dependencies 鍵下,--save-dev 則添加到 package.json 文件 devDependencies 鍵下降盹,不過(guò)這只是它們的表面區(qū)別与柑。它們真正的區(qū)別是,npm自己的文檔說(shuō)dependencies是運(yùn)行時(shí)依賴蓄坏,devDependencies是開發(fā)時(shí)的依賴价捧。即devDependencies 下列出的模塊,是我們開發(fā)時(shí)用的剑辫,比如 我們安裝 js的壓縮包gulp-uglify 時(shí)干旧,我們采用的是 “npm install –save-dev gulp-uglify ”命令安裝,因?yàn)槲覀冊(cè)诎l(fā)布后用不到它妹蔽,而只是在我們開發(fā)才用到它椎眯。dependencies 下的模塊,則是我們發(fā)布后還需要依賴的模塊胳岂,譬如像jQuery庫(kù)或者Angular框架類似的编整,我們?cè)陂_發(fā)完后后肯定還要依賴它們,否則就運(yùn)行不了乳丰。
另外需要補(bǔ)充的是:
正常使用npm install時(shí)掌测,會(huì)下載dependencies和devDependencies中的模塊,當(dāng)使用npm install –production或者注明NODE_ENV變量值為production時(shí)产园,只會(huì)下載dependencies中的模塊
61.利用window.onscroll事件實(shí)現(xiàn)滾動(dòng)條滾動(dòng)分頁(yè)
//滾動(dòng)滑輪觸發(fā)scrollFunc方法 //ie 谷歌
window.onscroll = () => {
this.loadMore();
};
//加載更多
loadMore = () => {
const {form: {getFieldValue}, chechData} = this.props;
let tempTotal = 0,page;
for (let index in chechData.groups) {
tempTotal += chechData.groups[index].homework.length;
}
page = Math.floor(tempTotal/10) + 1;
this.isVisible = this.isMoreVisible("#loadMore");
if (this.isVisible) {
let homewordParas: any = {
page: page,
pageSize: this.state.pageSize,
subjectId: this.props.subjectId,
sessionId: getFieldValue('classId')?getFieldValue('classId'):null,
timeRangeCode: getFieldValue('fromDate')?(getFieldValue('fromDate') === '近兩周'?'TWO_WEEKS':getFieldValue('fromDate')):null,
assessmentTitle:getFieldValue('homeworkName')?getFieldValue('homeworkName'):null,
};
if (tempTotal < this.props.chechData.total ) {
this.setState({
page: homewordParas.page
});
this.props.getHttpCheckData(homewordParas);
} else {
this.props.chechData? (this.refs.loadMore as any).innerHTML = "已沒(méi)有更多作業(yè)汞斧!":(this.refs.loadMore as any).innerHTML = "";
}
window.onscroll = null;
}
};
62.HTML5 的 Audio 標(biāo)簽
到今天為止,大多數(shù)的音頻文件播放什燕,是通過(guò) Flash 來(lái)實(shí)現(xiàn)的粘勒。而 HTML5 定義了一個(gè)新元素「audio」,在播放音頻上為我們提供了很多方便的功能屎即。
在瀏覽器的支持上庙睡,<audio> 標(biāo)簽?zāi)壳爸恢С?Internet Explorer 9+, Firefox, Opera, Chrome 和 Safari事富。也就是說(shuō),IE 9 以下是不支持的乘陪。
標(biāo)簽屬性:
* src: 要播放的音頻的 URL统台。
* preload: 是否預(yù)加載,如果使用 "autoplay"啡邑,則忽略該屬性贱勃。
* autoplay: 是否自動(dòng)播放。
* loop: 是否循環(huán)播放谤逼。
* controls: 是否顯示瀏覽器自帶的控制條募寨,例如播放按鈕。
html的寫法:
audio對(duì)象的方法和屬性:
我們可以動(dòng)態(tài)把一個(gè)audio元素插入到頁(yè)面中森缠,從而通過(guò) JS 來(lái)獲取這個(gè)對(duì)象,簡(jiǎn)單的方法如下:
事件:
63. addEventListener 用法 (https://www.cnblogs.com/Andyudd/p/5583563.html)
addEventListener 用于注冊(cè)事件處理程序仪缸,IE 中為 attachEvent贵涵,我們?yōu)槭裁粗v addEventListener 而不講 attachEvent 呢?一來(lái) attachEvent 比較簡(jiǎn)單恰画,二來(lái) addEventListener 才是 DOM 中的標(biāo)準(zhǔn)內(nèi)容宾茂。
addEventListener 為文檔節(jié)點(diǎn)、document拴还、window 或 XMLHttpRequest 注冊(cè)事件處理程序跨晴,在以前我們一般是 <input type="button" onclick="...",或 document.getElementById("testButton").onclick = FuncName片林, 而在 DOM 中端盆,我們用 addEventListener(IE 中用 attachEvent)。
語(yǔ)法:
target.addEventListener(type, listener, useCapture);
- target 文檔節(jié)點(diǎn)费封、document焕妙、window 或 XMLHttpRequest。
- type 字符串弓摘,事件名稱焚鹊,不含“on”,比如“click”韧献、“mouseover”末患、“keydown”等。
- listener 實(shí)現(xiàn)了 EventListener 接口或者是 JavaScript 中的函數(shù)锤窑。
- useCapture 是否使用捕捉璧针,看了后面的事件流一節(jié)后就明白了,一般用 false果复。
64.addEventListener-事件流
當(dāng)一個(gè)事件發(fā)生時(shí)陈莽,分為三個(gè)階段:
捕獲階段-- 從根節(jié)點(diǎn)開始順序而下,檢測(cè)每個(gè)節(jié)點(diǎn)是否注冊(cè)了事件處理程序。如果注冊(cè)了事件處理程序走搁,并且 useCapture 為 true独柑,則調(diào)用該事件處理程序。(IE 中無(wú)此階段私植。)
目標(biāo)階段-- 觸發(fā)在目標(biāo)對(duì)象本身注冊(cè)的事件處理程序忌栅,也稱正常事件派發(fā)階段。
冒泡階段-- 從目標(biāo)節(jié)點(diǎn)到根節(jié)點(diǎn)曲稼,檢測(cè)每個(gè)節(jié)點(diǎn)是否注冊(cè)了事件處理程序索绪,如果注冊(cè)了事件處理程序,并且 useCapture 為 false贫悄,則調(diào)用該事件處理程序瑞驱。
舉例
<div id="div1">
<div id="div2">
<div id="div3">
<div id="div4">
</div>
</div>
</div>
</div>
如果在 d3 上點(diǎn)擊鼠標(biāo),事件流是這樣的:
捕獲階段 在 div1 處檢測(cè)是否有 useCapture 為 true 的事件處理程序窄坦,若有唤反,則執(zhí)行該程序,然后再同樣地處理 div2鸭津。
目標(biāo)階段 在 div3 處彤侍,發(fā)現(xiàn) div3 就是鼠標(biāo)點(diǎn)擊的節(jié)點(diǎn),所以這里為目標(biāo)階段逆趋,若有事件處理程序盏阶,則執(zhí)行該程序,這里不論 useCapture 為 true 還是 false闻书。
冒泡階段 在 div2 處檢測(cè)是否有 useCapture 為 false 的事件處理程序名斟,若有,則執(zhí)行該程序魄眉,然后再同樣地處理 div1蒸眠。
注意,上述捕獲階段和冒泡階段中杆融,實(shí)際上 div1 之上還應(yīng)該有結(jié)點(diǎn)楞卡,比如有 body,但這里不討論脾歇。
65. addEventListener-第三個(gè)參數(shù) useCapture
addEventListener 用于注冊(cè)事件處理程序蒋腮,IE 中為 attachEvent,我們?yōu)槭裁粗v addEventListener 而不講 attachEvent 呢藕各?一來(lái) attachEvent 比較簡(jiǎn)單池摧,二來(lái) addEventListener 才是 DOM 中的標(biāo)準(zhǔn)內(nèi)容。
- 簡(jiǎn)介
addEventListener 為文檔節(jié)點(diǎn)激况、document作彤、window 或 XMLHttpRequest 注冊(cè)事件處理程序膘魄,在以前我們一般是 <input type="button" onclick="...",或 document.getElementById("testButton").onclick = FuncName竭讳, 而在 DOM 中创葡,我們用 addEventListener(IE 中用 attachEvent)。
2.語(yǔ)法
target.addEventListener(type, listener, useCapture);
- target 文檔節(jié)點(diǎn)绢慢、document灿渴、window 或 XMLHttpRequest。
- type 字符串胰舆,事件名稱骚露,不含“on”,比如“click”缚窿、“mouseover”棘幸、“keydown”等。
- listener 實(shí)現(xiàn)了 EventListener 接口或者是 JavaScript 中的函數(shù)倦零。
- useCapture 是否使用捕捉够话,看了后面的事件流一節(jié)后就明白了,一般用 false光绕。
3.示例
function Go()
{
//...
}
document.getElementById("testButton").addEventListener("click", Go, false);
或者 listener 直接就是函數(shù)
document.getElementById("testButton").addEventListener("click", function () { ... }, false);
addEventListener-事件流
說(shuō)到 addEventListener 不得不說(shuō)到事件流,先說(shuō)事件流對(duì)后面的解釋比較方便畜份。
當(dāng)一個(gè)事件發(fā)生時(shí)诞帐,分為三個(gè)階段:
捕獲階段 從根節(jié)點(diǎn)開始順序而下,檢測(cè)每個(gè)節(jié)點(diǎn)是否注冊(cè)了事件處理程序爆雹。如果注冊(cè)了事件處理程序停蕉,并且 useCapture 為 true,則調(diào)用該事件處理程序钙态。(IE 中無(wú)此階段慧起。)
目標(biāo)階段 觸發(fā)在目標(biāo)對(duì)象本身注冊(cè)的事件處理程序,也稱正常事件派發(fā)階段册倒。
冒泡階段 從目標(biāo)節(jié)點(diǎn)到根節(jié)點(diǎn)蚓挤,檢測(cè)每個(gè)節(jié)點(diǎn)是否注冊(cè)了事件處理程序,如果注冊(cè)了事件處理程序驻子,并且 useCapture 為 false灿意,則調(diào)用該事件處理程序。
舉例
<div id="div1">
<div id="div2">
<div id="div3">
<div id="div4">
</div>
</div>
</div>
</div>
如果在 d3 上點(diǎn)擊鼠標(biāo)崇呵,事件流是這樣的:
捕獲階段 在 div1 處檢測(cè)是否有 useCapture 為 true 的事件處理程序缤剧,若有,則執(zhí)行該程序域慷,然后再同樣地處理 div2荒辕。
目標(biāo)階段 在 div3 處汗销,發(fā)現(xiàn) div3 就是鼠標(biāo)點(diǎn)擊的節(jié)點(diǎn),所以這里為目標(biāo)階段抵窒,若有事件處理程序弛针,則執(zhí)行該程序,這里不論 useCapture 為 true 還是 false。
冒泡階段 在 div2 處檢測(cè)是否有 useCapture 為 false 的事件處理程序的止,若有花鹅,則執(zhí)行該程序,然后再同樣地處理 div1付材。
注意,上述捕獲階段和冒泡階段中圃阳,實(shí)際上 div1 之上還應(yīng)該有結(jié)點(diǎn)厌衔,比如有 body,但這里不討論捍岳。
addEventListener-第三個(gè)參數(shù) useCapture
addEventListener 有三個(gè)參數(shù):第一個(gè)參數(shù)表示事件名稱(不含 on富寿,如 "click");第二個(gè)參數(shù)表示要接收事件處理的函數(shù)锣夹;第三個(gè)參數(shù)為 useCapture页徐,本文就講解它。
<div id="outDiv">
<div id="middleDiv">
<div id="inDiv">請(qǐng)?jiān)诖它c(diǎn)擊鼠標(biāo)银萍。</div>
</div>
</div>
<div id="info"></div>
var outDiv = document.getElementById("outDiv");
var middleDiv = document.getElementById("middleDiv");
var inDiv = document.getElementById("inDiv");
var info = document.getElementById("info");
outDiv.addEventListener("click", function () { info.innerHTML += "outDiv" + "<br>"; }, false);
middleDiv.addEventListener("click", function () { info.innerHTML += "middleDiv" + "<br>"; }, false);
inDiv.addEventListener("click", function () { info.innerHTML += "inDiv" + "<br>"; }, false);
上述是我們測(cè)試的代碼变勇,根據(jù) info 的顯示來(lái)確定觸發(fā)的順序,有三個(gè) addEventListener贴唇,而 useCapture 可選值為 true 和 false搀绣,所以 222,可以得出 8 段不同的程序戳气。
全為 false 時(shí)链患,觸發(fā)順序?yàn)椋篿nDiv、middleDiv瓶您、outDiv麻捻;
全為 true 時(shí),觸發(fā)順序?yàn)椋簅utDiv呀袱、middleDiv芯肤、inDiv;
outDiv 為 true压鉴,其他為 false 時(shí)崖咨,觸發(fā)順序?yàn)椋簅utDiv、inDiv油吭、middleDiv击蹲;
middleDiv 為 true署拟,其他為 false 時(shí),觸發(fā)順序?yàn)椋簃iddleDiv歌豺、inDiv推穷、outDiv;
……
最終得出如下結(jié)論:true 的觸發(fā)順序總是在 false 之前类咧;
如果多個(gè)均為 true馒铃,則外層的觸發(fā)先于內(nèi)層;
如果多個(gè)均為 false痕惋,則內(nèi)層的觸發(fā)先于外層区宇。
66.react中樣式通過(guò)className引入
①className={style["simple-audio-choice-wrap"]}
②className={style.ors_row_pc_list}
第一種方法的格式是因?yàn)闃邮矫Q使用了“-”,如果用第二種引入會(huì)報(bào)錯(cuò)
67.className引入多個(gè)樣式
className={${style.a} ${style.b}
}
68.pop() 方法將刪除 arrayObject 的最后一個(gè)元素值戳,把數(shù)組長(zhǎng)度減 1议谷,并且返回它刪除的元素的值。如果數(shù)組已經(jīng)為空堕虹,則 pop() 不改變數(shù)組卧晓,并返回 undefined 值。
69.在package.json文件的webpack-dev-server.js 加--host 0.0.0.0赴捞,啟動(dòng)項(xiàng)目逼裆,可以使用手機(jī)輸入電腦的ip對(duì)本地項(xiàng)目進(jìn)行訪問(wèn)。這個(gè)配置的含義是赦政,既可以再本地用http://localhost/yoursite的url訪問(wèn)項(xiàng)目胜宇,也可以用http://yourip/yoursite訪問(wèn)項(xiàng)目。
比如你的計(jì)算機(jī)IP地址是192.168.1.10昼钻,項(xiàng)目名稱是app,那么你的訪問(wèn)url就可以是http://localhost/app封寞,或者h(yuǎn)ttp://192.168.1.10/app然评。
這樣設(shè)置的好處是,當(dāng)你想用非本機(jī)訪問(wèn)項(xiàng)目進(jìn)行測(cè)試時(shí)狈究,由ip地址構(gòu)建的url可以對(duì)項(xiàng)目進(jìn)行訪問(wèn)碗淌,同時(shí)本地還可以用localhost進(jìn)行訪問(wèn)。如果你將ip寫死了抖锥,那么localhost就無(wú)法訪問(wèn)了亿眠;
70.reduce() 方法接收一個(gè)函數(shù)作為累加器,數(shù)組中的每個(gè)值(從左到右)開始縮減磅废,最終計(jì)算為一個(gè)值纳像。
reduce() 可以作為一個(gè)高階函數(shù),用于函數(shù)的 compose拯勉。
注意: reduce() 對(duì)于空數(shù)組是不會(huì)執(zhí)行回調(diào)函數(shù)的竟趾。
71.new Date().toLocaleString() toLocaleString() 方法可根據(jù)本地時(shí)間把 Date 對(duì)象轉(zhuǎn)換為字符串憔购,并返回結(jié)果。2018/3/19 下午8:45:14
72.cordova plugin add cordova-plugin-statusbar
Android 5.0以下 支持的接口比較少show()和hide() 等
1. StatusBar.isVisible 是否已經(jīng)顯示
2. StatusBar.hide(); 隱藏狀態(tài)欄
3. StatusBar.show(); 顯示狀態(tài)欄
Android 5.0以上岔帽,支持設(shè)置背景
使用十六進(jìn)制設(shè)置背景:
StatusBar.backgroundColorByHexString("#C0C0C0");
StatusBar.backgroundColorByHexString("#333"); // => #333333
StatusBar.backgroundColorByHexString("#FAB"); // => #FFAABB
使用名稱設(shè)置背景:
StatusBar.backgroundColorByName("red");
document.addEventListener("deviceready", () => {
// set statusbar background color
if (cordova.platformId == 'android') {
StatusBar.backgroundColorByHexString("#f9f9f9");
}
}
73.typescript中使用Form報(bào)錯(cuò)但不影響運(yùn)行
先這樣寫吧玫鸟,這個(gè)類型暫時(shí)有點(diǎn)搞不定。
Form.create<any>()(LoginForm)
74.改變當(dāng)前組件的state值用setState犀勒,想改變props里面的值怎么做:
①當(dāng)前組件如果是 connect 到 redux 就通過(guò) dispatch 改屎飘。
第一: 就是 dispatch 一個(gè) action 在 reduce 里面修改 store 的 state
第二:再組件加載完數(shù)據(jù)之后,把 props 的數(shù)據(jù) 放到組件的 state 里面贾费,組件怎么變钦购,就用setState 去讓組件重新渲染≈荆可以在
componentWillReceiveProps函數(shù)中把props 的數(shù)據(jù) 放到組件的 state中
②當(dāng)前組件如果是 某個(gè)父組件 傳遞的 props 組件 的子組件肮雨, 子組件內(nèi)部可以調(diào)用 this.props.onChange 通過(guò)事件的方式 把新的 props 傳給父組件
然后父親組件去改。Input 顯示的值value就是 通過(guò) props 傳進(jìn)去的箱玷,然后 Input 的值更新怨规。需要改變 props的 value是直接通過(guò) onChange 通知父組件 改變
75.Object.assign() 方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象。它將返回目標(biāo)對(duì)象锡足。如果目標(biāo)對(duì)象中的屬性具有相同的鍵波丰,則屬性將被源中的屬性覆蓋。后來(lái)的源的屬性將類似地覆蓋早先的屬性舶得,但是Object.assign 不會(huì)跳過(guò)那些值為 null 或 undefined 的源對(duì)象
76.hasOwnProperty() 方法會(huì)返回一個(gè)布爾值掰烟,指示對(duì)象自身屬性中是否具有指定的屬性
77.在saga文件里面獲取store上的數(shù)據(jù):
①可以通過(guò)select方法獲取,如const cartData = yield select((state: any) => state.homeworkCartReducer.cartData);
②(window as GlobalDefinitions).store.getState().homeworkCenterReducer.subjectId
78.map只能遍歷數(shù)組沐批,其他用for...in...,或者排除掉那個(gè)非枚舉屬性再map
79..遇到過(guò)兩次setState設(shè)置某個(gè)屬性的值纫骑,在回調(diào)函數(shù)中打印發(fā)現(xiàn)沒(méi)設(shè)置成功,都是因?yàn)橥粋€(gè)函數(shù)里面寫了多個(gè)setState,一定要注意九孩,后面的setState可能會(huì)把前面set的值給覆蓋掉
80.可利用Jquery的 .text方法實(shí)時(shí)計(jì)算文本域還能輸入多少字符:總數(shù)-已輸入
81.html文件是自上而下的執(zhí)行方式先馆,但引入的css和javascript的順序有所不同,css引入執(zhí)行加載時(shí)躺彬,程序仍然往下執(zhí)行煤墙,而執(zhí)行到<script>腳本是則中斷線程,待該script腳本執(zhí)行結(jié)束之后程序才繼續(xù)往下執(zhí)行宪拥。所以仿野,大部分網(wǎng)上討論是將script腳本放在<body>之后,那樣dom的生成就不會(huì)因?yàn)殚L(zhǎng)時(shí)間執(zhí)行script腳本而延遲阻塞她君,加快了頁(yè)面的加載速度脚作。但又不能將所有的script放在body之后,因?yàn)橛幸恍╉?yè)面的效果的實(shí)現(xiàn)缔刹,是需要預(yù)先動(dòng)態(tài)的加載一些js腳本鳖枕。所以這些腳本應(yīng)該放在<body>之前魄梯。其次,不能將需要訪問(wèn)dom元素的js放在body之前宾符,因?yàn)榇藭r(shí)還沒(méi)有開始生成dom酿秸,所以在body之前的訪問(wèn)dom元素的js會(huì)出錯(cuò),或者無(wú)效魏烫。所以辣苏,我認(rèn)為script放置位置的原則“頁(yè)面效果實(shí)現(xiàn)類的js應(yīng)該放在body之前,動(dòng)作哄褒,交互稀蟋,事件驅(qū)動(dòng),需要訪問(wèn)dom屬性的js都可以放在body之后”呐赡。
82.<script> 標(biāo)簽的 defer 屬性
defer 屬性規(guī)定是否對(duì)腳本執(zhí)行進(jìn)行延遲退客,直到頁(yè)面加載為止。
有的 javascript 腳本 document.write 方法來(lái)創(chuàng)建當(dāng)前的文檔內(nèi)容链嘀,其他腳本就不一定是了萌狂。
如果您的腳本不會(huì)改變文檔的內(nèi)容,可將 defer 屬性加入到 <script> 標(biāo)簽中怀泊,以便加快處理文檔的速度茫藏。因?yàn)闉g覽器知道它將能夠安全地讀取文檔的剩余部分而不用執(zhí)行腳本,它將推遲對(duì)腳本的解釋霹琼,直到文檔已經(jīng)顯示給用戶為止务傲。
83.css
怎么找到下面的ant-menu-item-selecte這個(gè)class?
①.main_left_content :global(.ant-menu-item-selected)
②.main_left_content>:global(.ant-menu-item-selected)
注意:>隔開表示 子集(向下一層)枣申;空格 隔開表示 子集或子孫集 (向下多層售葡,范圍更廣)
84.&
.el-row {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
注意:& 代表上一級(jí)選擇器,實(shí)際編譯成css就是 .el-row:last-child{}
85.覆蓋antd樣式不生效時(shí)忠藤,試著在需要覆蓋的樣式前加 :gloabal
antd 的類都要加上 global 挟伙,要不然會(huì)被 webpack css modules 轉(zhuǎn)換 class 的字符串
86.css選擇器
87.7制造間距的方法
①將一個(gè)div設(shè)成間距,間距的顏色為div的背景色
②給其中一個(gè)div設(shè)置border,border的寬度即為間距的寬度
③利用box-shadow熄驼,將第一個(gè)和第三個(gè)參數(shù)都設(shè)置為0像寒,第二個(gè)參數(shù)為間距的寬度烘豹,注意:同時(shí)要給margin值瓜贾,投影到top方向就要給margin-top
88.onsenui實(shí)現(xiàn)下拉列表展開樣式仿淘寶
89.充分利用before和after屬性
90.js的delete屬性
delete 操作符用于刪除對(duì)象的某個(gè)屬性;如果沒(méi)有指向這個(gè)屬性的引用携悯,那它最終會(huì)被釋放
91. javascript 6個(gè)falsy值:null,undefined,NaN,0,false,空字符串
92.從數(shù)組中移除某些值(lodash)http://www.bubuko.com/infodetail-794683.html
①.difference(array,[values]) 兩個(gè)參數(shù)都是數(shù)組祭芦,array:要被檢查/過(guò)濾的數(shù)組, array:要被檢查/過(guò)濾的數(shù)組
② .drop(array,number) 類似于原生js方法中的slice憔鬼。從頭開始刪除number個(gè)數(shù)組元素龟劲。number不傳的話默認(rèn)按1處理
③.without(array, [values]) 不同于difference方法胃夏。其values參數(shù)可以不是一個(gè)數(shù)組,而是接在array參數(shù)之后的零散參數(shù)昌跌。
④.remove(array, [predicate=_.identity], [thisArg]) (對(duì)原數(shù)組操作) 第二個(gè)參數(shù)為function
⑤ .pull(array, [values]) (對(duì)原數(shù)組操作)
⑥.rest(array) 移除數(shù)組首元素 和initial相反
85.js原生的indexOf和lodash中的indexOf
js:
①語(yǔ)法: stringObject.indexOf(searchvalue,fromindex)
②注意: 對(duì)大小寫敏感仰禀! 如果要檢索的字符串值沒(méi)有出現(xiàn),則該方法返回 -1蚕愤。
③例子:
lodash:
①語(yǔ)法: _.indexOf(array, value, [fromIndex=0])
②注意:第一個(gè)參數(shù)必須是數(shù)組
③例子:
93.一個(gè)大div包含兩個(gè)div答恶,怎么讓左邊的固定寬度,另一個(gè)撐滿剩下寬度
(1)使用float
<div class="use-float">
<div></div>
<div></div></div>
.use-float>div:first-child{
width:100px;
float:left;}.use-float>div:last-child{
overflow:hidden;}
(2)使用table
<table class="use-table">
<tr>
<td></td>
<td></td>
</tr>
</table>
.use-table{
border-collapse:collapse;
width:100%;}.use-table>tbody>tr>td:first-child{
width:100px;}
(3)用div模擬table
<div class="use-mock-table">
<div></div>
<div></div></div>
.use-mock-table{
display:table;
width:100%;}.use-mock-table>div{
display:table-cell;}.use-mock-table>div:first-child{
width:100px;}
(4)使用flex
<div class="use-flex">
<div></div>
<div></div></div>
.use-flex{
display:flex;}.use-flex>div:first-child{
flex:none;
width:100px;}.use-flex>div:last-child{
flex:1;}
94.數(shù)組去重
① Set是ES6中新的對(duì)象萍诱。 利用它可以迅速為數(shù)組去重
簡(jiǎn)單來(lái)說(shuō)悬嗓,Set于Array的區(qū)別在于:Array中允許出現(xiàn)重復(fù)的元素,例如[1,2,2,3]裕坊;而Set中的所有元素都是唯一的包竹,只能是{1,2,3}。利用這一特性籍凝,我們就可以迅速地去掉數(shù)組中重復(fù)的元素周瞎。
let sessionListAll = Array.from(new Set(sessionData));
classchollArrayId= [...new Set(classchollArrayId)]//數(shù)組去重
②lodash uniq/unique 數(shù)組去重
③lodash union數(shù)組合并去重
95.javascript中for of和for in的區(qū)別
①推薦在循環(huán)對(duì)象屬性的時(shí)候,使用for...in,在遍歷數(shù)組的時(shí)候的時(shí)候使用for...of静浴。
②for...in循環(huán)出的是key堰氓,for...of循環(huán)出的是value
③注意,for...of是ES6新引入的特性苹享。修復(fù)了ES5引入的for...in的不足
④for...of不能循環(huán)普通的對(duì)象双絮,需要通過(guò)和Object.keys()搭配使用
95. npm 裝包時(shí)的區(qū)別 -D -S
https://www.limitcode.com/detail/59a15b1a69e95702e0780249.html
回顧 npm install 命令最近在寫Node程序的時(shí)候,突然對(duì) npm install 的-save和-save-dev 這兩個(gè)參數(shù)的使用比較混亂得问。其實(shí)博主在這之前對(duì)這兩個(gè)參數(shù)的理解也是模糊的囤攀,各種查資料和實(shí)踐后對(duì)它們之間的異同點(diǎn)略有理解。遂寫下這篇文章避免自己忘記宫纬,同時(shí)也給node猿友一點(diǎn)指引焚挠。
我們?cè)谑褂?npm install 安裝模塊的模塊的時(shí)候 ,一般會(huì)使用下面這幾種命令形式:
npm install moduleName # 安裝模塊到項(xiàng)目目錄下
npm install -g moduleName # -g 的意思是將模塊安裝到全局漓骚,具體安裝到磁盤哪個(gè)位置蝌衔,要看 npm config prefix 的位置。
npm install -save moduleName # -save 的意思是將模塊安裝到項(xiàng)目目錄下蝌蹂,并在package文件的dependencies節(jié)點(diǎn)寫入依賴噩斟。
npm install -save-dev moduleName # -save-dev 的意思是將模塊安裝到項(xiàng)目目錄下,并在package文件的devDependencies節(jié)點(diǎn)寫入依賴孤个。
那么問(wèn)題來(lái)了剃允,在項(xiàng)目中我們應(yīng)該使用四個(gè)命令中的哪個(gè)呢?這個(gè)就要視情況而定了。下面對(duì)這四個(gè)命令進(jìn)行對(duì)比斥废,看完后你就不再這么問(wèn)了椒楣。
- npm install moduleName 命令
- 安裝模塊到項(xiàng)目node_modules目錄下。
- 不會(huì)將模塊依賴寫入devDependencies或dependencies 節(jié)點(diǎn)牡肉。
- 運(yùn)行 npm install 初始化項(xiàng)目時(shí)不會(huì)下載模塊捧灰。
- npm install -g moduleName 命令
- 安裝模塊到全局侠坎,不會(huì)在項(xiàng)目node_modules目錄中保存模塊包耸峭。
- 不會(huì)將模塊依賴寫入devDependencies或dependencies 節(jié)點(diǎn)志笼。
- 運(yùn)行 npm install 初始化項(xiàng)目時(shí)不會(huì)下載模塊徘郭。
- npm install -save * * moduleName 命令
- 安裝模塊到項(xiàng)目node_modules目錄下亦镶。
- 會(huì)將模塊依賴寫入dependencies 節(jié)點(diǎn)洁段。
- 運(yùn)行 npm install 初始化項(xiàng)目時(shí)秃殉,會(huì)將模塊下載到項(xiàng)目目錄下识埋。
- 運(yùn)行npm install --production或者注明NODE_ENV變量值為production時(shí)免绿,會(huì)自動(dòng)下載模塊到node_modules目錄中唧席。
- npm install -save-dev moduleName 命令
- 安裝模塊到項(xiàng)目node_modules目錄下。
- 會(huì)將模塊依賴寫入devDependencies 節(jié)點(diǎn)嘲驾。
- 運(yùn)行 npm install 初始化項(xiàng)目時(shí)淌哟,會(huì)將模塊下載到項(xiàng)目目錄下。
- 運(yùn)行npm install --production或者注明NODE_ENV變量值為 production時(shí)辽故,不會(huì)自動(dòng)下載模塊到node_modules目錄中徒仓。總結(jié)
devDependencies 節(jié)點(diǎn)下的模塊是我們?cè)陂_發(fā)時(shí)需要用的誊垢,比如項(xiàng)目中使用的 gulp 掉弛,壓縮css、js的模塊喂走。這些模塊在我們的項(xiàng)目部署后是不需要的殃饿,所以我們可以使用 -save-dev 的形式安裝。像 express 這些模塊是項(xiàng)目運(yùn)行必備的芋肠,應(yīng)該安裝在 dependencies 節(jié)點(diǎn)下乎芳,所以我們應(yīng)該使用 -save 的形式安裝。
96.XML DOM - XMLHttpRequest 對(duì)象
97.名詞理解
同構(gòu)應(yīng)用:什么是前后端同構(gòu)呢帖池?就是前后端都可以使用同一套代碼生成頁(yè)面奈惑,頁(yè)面既可以由前端動(dòng)態(tài)生成,也可以由后端服務(wù)器直接渲染出來(lái)
單頁(yè)面應(yīng)用:就是只有一張Web頁(yè)面的應(yīng)用睡汹。單頁(yè)應(yīng)用程序 (SPA) 是加載單個(gè)HTML 頁(yè)面并在用戶與應(yīng)用程序交互時(shí)動(dòng)態(tài)更新該頁(yè)面的Web應(yīng)用程序肴甸。 瀏覽器一開始會(huì)加載必需的HTML、CSS和JavaScript帮孔,所有的操作都在這張頁(yè)面上完成雷滋,都由JavaScript來(lái)控制。直白一點(diǎn)就是只有一個(gè)html文件的應(yīng)用文兢。react,vue等做的都是單頁(yè)面的
98.Redux
① 要想更新 state 中的數(shù)據(jù)晤斩,你需要發(fā)起一個(gè) action
②把 action 和 state 串起來(lái),開發(fā)一些函數(shù)姆坚,這就是 reducer澳泵。reducer 只是一個(gè)接收 state 和 action,并返回新的 state 的函數(shù)
- Redux三大原則
①單一數(shù)據(jù)源: 整個(gè)應(yīng)用的 state 被儲(chǔ)存在一棵 object tree 中兼呵,并且這個(gè) object tree 只存在于唯一一個(gè) store 中兔辅。 可通過(guò)store.getState()取store上的數(shù)據(jù)
②State 是只讀的:唯一改變 state 的方法就是觸發(fā) action,action 是一個(gè)用于描述已發(fā)生事件的普通對(duì)象击喂。
③使用純函數(shù)來(lái)執(zhí)行修改:為了描述 action 如何改變 state tree 维苔,你需要編寫 reducers。
99.在saga中使用setTimeout
const delay =(timeout: any) => new Promise((callback) => setTimeout(callback,timeout))
yield delay(2000);
100. redux-saga
https://redux-saga-in-chinese.js.org/docs/api/index.html
put 就是我們所說(shuō)的一個(gè)調(diào)用 Effect 的例子
call 就像 put懂昂, 返回一個(gè)指示 middleware 以給定參數(shù)調(diào)用給定的函數(shù)的 Effect介时。
takeEvery 允許多個(gè) fetchData 實(shí)例同時(shí)啟動(dòng)。在某個(gè)特定時(shí)刻凌彬,我們可以啟動(dòng)一個(gè)新的 fetchData 任務(wù), 盡管之前還有一個(gè)或多個(gè) fetchData 尚未結(jié)束铲敛。
takeLatest 得到最新那個(gè)請(qǐng)求的響應(yīng)(例如褐澎,始終顯示最新版本的數(shù)據(jù))。 和 takeEvery 不同伐蒋,在任何時(shí)刻 takeLatest 只允許執(zhí)行一個(gè) fetchData 任務(wù)工三。并且這個(gè)任務(wù)是最后被啟動(dòng)的那個(gè)。 如果之前已經(jīng)有一個(gè)任務(wù)在執(zhí)行先鱼,那之前的這個(gè)任務(wù)會(huì)自動(dòng)被取消徒蟆。
在 Generator 函數(shù)中,yield 右邊的任何表達(dá)式都會(huì)被求值型型,結(jié)果會(huì)被 yield 給調(diào)用者
fork 無(wú)阻塞調(diào)用段审。 當(dāng)我們 fork 一個(gè) 任務(wù),任務(wù)會(huì)在后臺(tái)啟動(dòng)闹蒜,調(diào)用者也可以繼續(xù)它自己的流程寺枉,而不用等待被 fork 的任務(wù)結(jié)束。 yield fork 的返回結(jié)果是一個(gè) Task 對(duì)象
cancel 為了取消 fork 任務(wù)绷落,使用的一個(gè)指定的 Effect 姥闪。
race
yield* 操作符來(lái)組合多個(gè) Sagas,使得它們保持順序砌烁。 這讓你可以一種簡(jiǎn)單的程序風(fēng)格來(lái)排列你的 宏觀任務(wù)(macro-tasks)筐喳。
101. request 請(qǐng)求頭
credentials: 'include' : 默認(rèn)情況下催式,標(biāo)準(zhǔn)的跨域請(qǐng)求是不會(huì)發(fā)送cookie等用戶認(rèn)證憑據(jù)的。所以避归,當(dāng)你訪問(wèn)遠(yuǎn)程api的時(shí)候荣月,cookie是不會(huì)被帶上的∈岜校【 當(dāng)這個(gè)屬性為true的時(shí)候哺窄,遠(yuǎn)程服務(wù)器也要作相應(yīng)的處理。在響應(yīng)頭那里設(shè)置 Access-Control-Allow-Credentials: true 】
102.previousSibling屬性返回元素節(jié)點(diǎn)之前的兄弟節(jié)點(diǎn)(包括文本節(jié)點(diǎn)账锹、注釋節(jié)點(diǎn))萌业;
previousElementSibling屬性只返回元素節(jié)點(diǎn)之前的兄弟元素節(jié)點(diǎn)(不包括文本節(jié)點(diǎn)、注釋節(jié)點(diǎn))奸柬;
103.前端文件下載
①<a />標(biāo)簽:<a href={"/api/fms/sys/attach/file/detail?"+stringify(params)} style={{marginLeft:'200px'}}>下載</a>
txt,png,jpg等這些瀏覽器支持直接打開的文件是不會(huì)執(zhí)行下載任務(wù)的生年,而是會(huì)直接打開文件,這個(gè)時(shí)候就需要給a標(biāo)簽添加一個(gè)屬性“download”廓奕;
②window.location.href = "..."
104.圖片預(yù)覽
使用<img />標(biāo)簽晶框,在src屬性中寫上圖片存放的地址:<img src={PICTURE_ADDRESS + srcPath} alt="財(cái)聯(lián)邦" style={{width: '600px',height:'400px'}}/>
105.①_.uniqWith(array, [comparator])
②.xorBy([arrays], [iteratee=.identity])
3)_.xorWith([arrays], [comparator])
-
106.對(duì)象中數(shù)組對(duì)象去重
1)import _ from "lodash";
for (let index in checkData.groups) {
let homework = _.uniqWith(checkData.groups[index].homework, _.isEqual);
checkData.groups[index].homework = homework;
}
2)
/**
*
* @param {*} list 數(shù)組
* @param {*} fields 去重字段
*/
function uniqeItem(list:any, fields:any){
function getUniquKey(item:any, fields:any){
let length = fields.length, key = [];
while(length--){
key.push(item[fields[length]]);
}
return key.join('|');
}
let newList = [];
let keyMap = new Map();
for (let i = 0, j = list.length; i < j; i++) {
let key = getUniquKey(list[i], fields);
if (!keyMap.get(key)) {
keyMap.set(key, true);
newList.push(list[i]);
}
}
return newList ;
}
uniqeItem([{a:1,b:2},{a:1,b:2}], ['a','b']);
107.8到20位的可輸入半角符號(hào),但不含空格并且至少包含一個(gè)數(shù)字和字母
/^(?=.*[0-9])(?=.*[a-zA-Z])[\x01-\x1f|\x21-\xff]{8,20}$/
108.控制臺(tái)報(bào)錯(cuò)解決
-
1.message全局提示報(bào)錯(cuò)懂从,之前以為是DatePicker組件的校驗(yàn)問(wèn)題
定位問(wèn)題到message組件:①通過(guò)下面的created by notification授段;createed by animate;②通過(guò)保存函數(shù)番甩,應(yīng)該彈出提示信息侵贵,但是沒(méi)有彈出
-
2.Redirect to屬性報(bào)錯(cuò)
定位問(wèn)題:通過(guò) '>' expected可以想到>是html片段符號(hào),而文件后綴是ts缘薛,也就是文件類型應(yīng)該是tsx窍育。所以把文件后綴改為tsx,問(wèn)題解決
-
3.DatePicker組件總是顯示成英文
問(wèn)題解決:
109.antd中父組件怎么使用子組件的form中自帶的屬性
-
1.父組件將form傳給子組件宴胧,子組件使用父組件傳下來(lái)的form
-
2.使用官網(wǎng)API
①在父組件ExamCreation中不使用Form
②在各個(gè)子組件中使用Form漱抓,然后在父組件ExamCreation中調(diào)用的子組件上加上那個(gè)屬性,最后就可以像在子組件一樣使用form中的API了恕齐。(注意:使用typeScript時(shí)一定要先定義this.form3...)
110. antd升級(jí)到3.6.5版本后遇到問(wèn)題及解決
-
1.Pagination組件顯示成英文
解決方法:
①引入antd國(guó)際化組件LocaleProvider 和需要的語(yǔ)言包
②用國(guó)際化組件將分頁(yè)組件包裹起來(lái)
-
2.DatePicker組件顯示成英文
解決方法:除了上面使用LocaleProvider 組件解決乞娄,DatePicker組件有自帶的語(yǔ)言包
111.在git上提merge request的時(shí)候,上面檢測(cè)到的更改是显歧,自己的遠(yuǎn)程分支和master分支代碼對(duì)比的結(jié)果
112.使用Redirect的時(shí)候報(bào)錯(cuò)
Redirect是一個(gè)組件仪或,將組件嵌套在ts代碼中,文件類型要改為tsx
113.瀏覽器在傳遞url的時(shí)候士骤,會(huì)使用自己的編碼格式對(duì)地址進(jìn)行編碼范删,如果瀏覽器所使用編碼與服務(wù)器采用編碼不一致,服務(wù)器接收到的參數(shù)就會(huì)出現(xiàn)亂碼拷肌。在firefox到旦,chrome下正常旨巷,ie下會(huì)出現(xiàn)亂碼。
解決方法:使用js encodeURI 對(duì)地址進(jìn)行統(tǒng)一編碼添忘,encodeURI("article/detail?title=我是中文");
114.阻止冒泡:e.stopPropagation()采呐,IE使用e.cancelBubble = true
if (e && e.stopPropagation) {
e.stopPropagation();
} else if (window.event) {
window.event.cancelBubble = true;
}
115.日期格式轉(zhuǎn)時(shí)間戳
1.Date.parse(date) (注意瀏覽器之間的區(qū)別、兼容)
IE:
Firefox:
Chrome:
- new Date(date).getTime()
IE:
Firefox:
Chrome:
注意:兩種方法在三個(gè)瀏覽器都能起作用的日期格式是 / 分割的昔汉,所以要使用該方法的話使用 .replace()轉(zhuǎn)化,如IE下的:
116.Moment.js常用API
https://blog.csdn.net/wulex/article/details/80402036
117.修改滾動(dòng)條默認(rèn)樣式
::-webkit-scrollbar {
width: 6px;
//height: 16px;
background-color: #F5F5F5;
}
/*定義滾動(dòng)條軌道 內(nèi)陰影+圓角*/
::-webkit-scrollbar-track {
//-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
opacity: 0.5;
border-radius: 10px;
background-color: #F5F5F5;
}
/*定義滑塊 內(nèi)陰影+圓角*/
::-webkit-scrollbar-thumb {
border-radius: 10px;
//-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #dddddd;
}
118.Dva中container中的js文件
第1拴清,2個(gè)customer是在model中的命名空間靶病,第3,4個(gè)是同一個(gè)
119.Classnames
根據(jù)狀態(tài)值動(dòng)態(tài)添加或去除class.
npm install classnames
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
可以看到鍵值為true的就返回鍵名口予,可以利用這個(gè)方法來(lái)動(dòng)態(tài)控制鍵值的true/fale變化娄周,從而控制是否返回鍵。(默認(rèn)是返回的)
// ES5
let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true });
在React中使用
var Button = React.createClass({
// ...
render () {
var btnClass = 'btn';
//根據(jù)點(diǎn)擊的state來(lái)控制css
if (this.state.isPressed) btnClass += ' btn-pressed';
else if (this.state.isHovered) btnClass += ' btn-over';
return <button className={btnClass}>{this.props.label}</button>;
}
});
var classNames = require('classnames');
var Button = React.createClass({
// ...
render () {
var btnClass = classNames({
'btn': true,
'btn-pressed': this.state.isPressed,
'btn-over': !this.state.isPressed && this.state.isHovered
});
return <button className={btnClass}>{this.props.label}</button>;
}
});
如果是name和className進(jìn)行了映射,可以使用bind方法
/* components/submit-button.js */
import { Component } from 'react';
import classNames from 'classnames/bind';
import styles from './submit-button.css';
let cx = classNames.bind(styles);
export default class SubmitButton extends Component {
render () {
let text = this.props.store.submissionInProgress ? 'Processing...' : 'Submit';//text根據(jù)狀態(tài)來(lái)動(dòng)態(tài)加載
let className = cx({
base: true,
inProgress: this.props.store.submissionInProgress,//樣式的動(dòng)態(tài)加載
error: this.props.store.errorOccurred,
disabled: this.props.form.valid,
});
return <button className={className}>{text}</button>;
}
};
120.path-to-regexp
使用path-to-regexp沪停,我們可以在路徑字符串中使用正則煤辨。如/:foo*/:bar?、/icon-:foo(\d+).png等木张。
直接調(diào)用構(gòu)造函數(shù)使用众辨,一個(gè)可能含某種匹配模式的路徑字符串作為它的必選參數(shù),它返回一個(gè)正則對(duì)象舷礼。
const pathToRegexp = require('path-to-regexp')
var regexp_1 = pathToRegexp('/foo/:bar')// /^\/foo\/([^\/]+?)(?:\/)?$/i
regexp_1.exec('/foo/barrrr')//匹配成功 =>RegExpExecArray [ '/foo/barrrr', 'barrrr', index: 0, input: '/foo/barrrr' ]
regexp_1.exec('/bazzzz')//匹配失敗 => null
/foo/:bar中的/為分隔符鹃彻,把多個(gè)匹配模式分隔開,這里就分成foo和:bar妻献。像foo這種不帶:前綴的蛛株,我們請(qǐng)求的路徑需要和它完全匹配,而:bar這種育拨,叫命名參數(shù)谨履,就像個(gè)函數(shù)形參,可以傳遞任何請(qǐng)求路徑字串給它熬丧。
在命名參數(shù)上笋粟,我們可以使用參數(shù)修飾符作為其后綴,有?析蝴、+矗钟、*
- “*”:表示我這個(gè)命名參數(shù):bar可以接收隨意個(gè)匹配模式,就好像參數(shù)數(shù)組長(zhǎng)度[0,+∞)
var regexp_2 = pathToRegexp('/foo/:bar*')
regexp_2.exec('/foo/a/b/c')// => [ '/foo/a/b/c', 'a/b/c', index: 0, input: '/foo/a/b/c' ]
regexp_2.exec('/foo')// => [ '/foo', undefined, index: 0, input: '/foo' ]
- “+”: 表示命名參數(shù)可以接收至少一個(gè)匹配模式嫌变,一個(gè)都沒(méi)就匹配失敗吨艇,[1,+∞)
var regexp_3 = pathToRegexp('/foo/:bar+')
regexp_3.exec('/foo/a/b/c')// => [ '/foo/a/b/c', 'a/b/c', index: 0, input: '/foo/a/b/c' ]
regexp_3.exec('/foo')//匹配失敗 => null
- “? ”:表示命名參數(shù)可以接收0個(gè)或1個(gè)匹配模式,多個(gè)失敗腾啥,[0,1]
var regexp_4 = pathToRegexp('/foo/:bar?')
regexp_4.exec('/foo/a')// => [ '/foo/a', 'a', index: 0, input: '/foo/a' ]
regexp_4.exec('/foo/a/b/c')// => null
regexp_4.exec('/foo')// => [ '/foo', undefined, index: 0, input: '/foo' ]
我們還可以為命名參數(shù)加上自定義的正則匹配模式
// 以下設(shè)置表示:foo只能是數(shù)字东涡。
var regexp_5 = pathToRegexp('/icon-:foo(\\d+).png')
regexp_5.exec('/icon-123.png')// => [ '/icon-123.png', '123', index: 0, input: '/icon-123.png' ]
regexp_5.exec('/icon-abc.png')// null
//不需要命名參數(shù)這個(gè)占位符冯吓,通過(guò)正則就能就能匹配。
var regexp_5 = pathToRegexp('/icon-(\\d+).png')
regexp_5.exec('/icon-123.png')// => [ '/icon-123.png', '123', index: 0, input: '/icon-123.png' ]
regexp_5.exec('/icon-abc.png')// null
121. Form 提交需注意
把提交函數(shù)寫在Form上會(huì)導(dǎo)致:表單提交后在地址欄會(huì)添一個(gè)“疮跑?”组贺,界面刷新
122.轉(zhuǎn)換location.search為json格式
// js
export function getSearchJson(search) {
if(search == undefined) return
search = search.substr(1);
let arr = search.split("&"),
obj = {},
newArr = [];
arr.map((value)=>{
newArr = value.split("=");
if(newArr[0] !== undefined) {
obj[newArr[0]] = newArr[1];
}
})
return obj;
};
// 使用插件
npm i query-string
import queryString from 'query-string';
const { dispatch, location: { search } } = this.props;
const queryParams = queryString.parse(search) || {};
123.字段描述值根據(jù)值集展示
render: (text, record)=>{
if(text && this.state.code.checkStatus){
for(let i in this.state.code.checkStatus){
if(text == this.state.code.checkStatus[i].value){
return(<div>{this.state.code.checkStatus[i].meaning}</div>)
}
}
}
}
124.no-param-reassign
Object.defineProperty()
方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)已經(jīng)存在的屬性祖娘, 并返回這個(gè)對(duì)象失尖。“`
@param: obj:需要定義屬性的對(duì)象;
prop:需要定義或修改的屬性渐苏;
descriptor:將被定義或修改屬性的描述符
對(duì)象里目前存在的屬性描述符主要有兩種形式: 數(shù)據(jù)描述符和存取描述符.
125.<img />標(biāo)簽圖片文件不更新問(wèn)題
不更新的原因:更新src后掀潮,如果src與原來(lái)的相同,則瀏覽器回從緩存里獲取圖片而不會(huì)向后臺(tái)發(fā)送新的請(qǐng)求
解決辦法:在src之后加上一些沒(méi)有意義的隨機(jī)參數(shù)比如鏈接上“琼富?time=new Date().getTime()”即獲取當(dāng)前時(shí)間的時(shí)間戳仪吧,這是瀏覽器會(huì)認(rèn)為這是不同的url因此會(huì)重新發(fā)送請(qǐng)求加載新的圖片。 改成如下樣子會(huì)導(dǎo)致新的問(wèn)題:每次進(jìn)入界面都請(qǐng)求好幾次
多次請(qǐng)求原因:props中有些變量值改變導(dǎo)致重新render鞠眉,如loading由false變成true又變成false
解決方法:將url后的隨機(jī)變量的值從models中傳過(guò)來(lái)
126.Context API
- React.createContext 方法用于創(chuàng)建一個(gè) Context 對(duì)象薯鼠。該對(duì)象包含 Provider 和 Consumer兩個(gè)屬性,分別為兩個(gè) React 組件械蹋。
- Provider 組件出皇。用在組件樹中更外層的位置。它接受一個(gè)名為 value 的 prop哗戈,其值可以是任何 JavaScript 中的數(shù)據(jù)類型恶迈。
- Consumer 組件∑状迹可以在 Provider 組件內(nèi)部的任何一層使用暇仲。它接收一個(gè)名為 children 值為一個(gè)函數(shù)的 prop。這個(gè)函數(shù)的參數(shù)是 Provider 組件接收的那個(gè) value prop 的值副渴,返回值是一個(gè) React 元素(一段 JSX 代碼)奈附。
特點(diǎn):
-
Provider
和Consumer
必須來(lái)自同一次React.createContext
調(diào)用。也就是說(shuō)NameContext.Provider
和AgeContext.Consumer
是無(wú)法搭配使用的煮剧。 -
React.createContext
方法接收一個(gè)默認(rèn)值作為參數(shù)斥滤。當(dāng)Consumer
外層沒(méi)有對(duì)應(yīng)的Provider
時(shí)就會(huì)使用該默認(rèn)值。 -
Provider
組件的value
prop 值發(fā)生變更時(shí)勉盅,其內(nèi)部組件樹中對(duì)應(yīng)的Consumer
組件會(huì)接收到新值并重新執(zhí)行children
函數(shù)佑颇。此過(guò)程不受shouldComponentUpdete
方法的影響。前面的示例代碼中草娜,Hello
組件繼承自React.PureComponent
但頁(yè)面依然能正確顯示足以說(shuō)明這一點(diǎn)挑胸。 -
Provider
組件利用Object.is
檢測(cè)value
prop 的值是否有更新。注意Object.is
和===
的行為不完全相同宰闰。具體細(xì)節(jié)請(qǐng)參考Object.is
的 MDN 文檔頁(yè)茬贵。 -
Consumer
組件接收一個(gè)函數(shù)作為children
prop 并利用該函數(shù)的返回值生成組件樹的模式被稱為 Render Props 模式簿透。詳細(xì)介紹請(qǐng)參考相關(guān) React 文檔
127.在models層獲取全局狀態(tài)樹數(shù)據(jù)
- Redux下:const state =(window as GlobalDefinitions).store.getState().namespaceName
- Dva中: const state = yield select(st => st.namespaceName);
namespaceName為要獲取的那個(gè)狀態(tài)樹的命名空間
128.antd Table復(fù)選框選中控制
選中控制一定要通過(guò)selectedRowKeys,不然會(huì)出現(xiàn)選中的key是空時(shí)解藻,界面上還有勾
rowSelection={{
selectedRowKeys: selectedRows.map(i => i.docItemId),
onChange: this.handleRowSelect,
}}
129. 重新部署后頁(yè)面js文件報(bào)404
現(xiàn)象:react項(xiàng)目發(fā)布后, 需要用戶手動(dòng)刷新瀏覽器才能正常運(yùn)行老充。有md5值, js每次更改代碼后, 打包出的hash值也是不同的, 但用戶必須刷新頁(yè)面緩存才能正常使用
分析:檢查 index.html 有沒(méi)有在 Nginx 設(shè)置緩存;檢查項(xiàng)目的 vendor.js common.js 是否有hash螟左。
index.html被緩存了啡浊,被緩存的index.html引用的是舊版js、css資源胶背,這些資源也被瀏覽器緩存過(guò)巷嚣,所以加載的是上次訪問(wèn)的頁(yè)面。
解決方法:修改下nginx配置就可以了
location / {
index index.html;
if ($uri ~* "html$") {
add_header Cache-Control "no-cache, no-store, max-age=0, must-revalidate";
}
}
https://segmentfault.com/q/1010000007320935
130.查找nginx配置文件所在位置
whereis nginx --查看nginx安裝路徑
which nginx --查看nginx運(yùn)行路徑
/usr/sbin/nginx -t --在知曉了運(yùn)行路徑為/usr/sbin/nginx條件下奄妨,查看nginx配置文件的位置涂籽。nginx.conf苹祟、default.conf
131. 修改本地啟動(dòng)端口
環(huán)境變量 PORT,在 compileStartEnv 里面砸抛。 如果沒(méi)有這個(gè)文件,就在 package.json 里面
如果需要保存 就是 寫在 環(huán)境變量的 地方树枫;
如果不需要保存直焙;
直接設(shè)置 當(dāng)前環(huán)境變量就好了。
export PORT=8001 && yarn start // linux
set PORT=8001 && yarn start // windows
132. pointer-events: none;
指定在什么情況下 (如果有) 某個(gè)特定的圖形元素可以成為鼠標(biāo)事件