React開發(fā)問(wèn)題總結(jié)(持續(xù)更新...)

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、有和不同谴垫?

    encodeURIdecodeURI 函數(shù)操作的是完整的 URI章母;這倆函數(shù)假定 URI 中的任何保留字符都有特殊意義,所有不會(huì)編碼它們翩剪。

    encodeURIComponentdecodeURIComponent 函數(shù)操作的是組成 URI 的個(gè)別組件乳怎;這倆函數(shù)假定任何保留字符都代表普通文本,所以必須編碼它們前弯,所以它們(保留字符)出現(xiàn)在一個(gè)完整 URI 的組件里面時(shí)不會(huì)被解釋成保留字符了蚪缀。

    以上說(shuō)明摘自ECMAScript標(biāo)準(zhǔn),為了容易讀懂做了點(diǎn)編輯加工恕出。
    4询枚、圖解四個(gè)函數(shù)的不同:

    image.png

    當(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)


outline實(shí)現(xiàn)

outline-offset實(shí)現(xiàn)

不足之處:
不能貼合圓角
   2舀武、 box-shadow實(shí)現(xiàn)
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]+)(?![a-zA-Z]+)[0-9A-Za-z]{6,20}/' 數(shù)字 + 字母 長(zhǎng)度在6-20位 分開來(lái)注釋一下: ^ 匹配一行的開頭位置 (?![0-9]+) 預(yù)測(cè)該位置后面不全是數(shù)字
(?![a-zA-Z]+) 預(yù)測(cè)該位置后面不全是字母 [0-9A-Za-z] {6,10} 由6-10位數(shù)字或這字母組成 匹配行結(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é)果如下:


image.png

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

image.png

* 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)址”勾選杨赤。
image.png
  • 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)等信息焰枢。


    image.png

    (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
image.png

(5)修改某一處為錯(cuò)誤,然后觀察結(jié)果


image.png

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 讀取沾谓。


image.png

這里需要注意, 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ù):

image.png

  • 布爾值定罢、null、undefined在渲染時(shí)會(huì)被自動(dòng)忽略
    false搁廓,null引颈,undefined和true是有效的子元素,不過(guò)他們從根本上講是不參與渲染的境蜕。 這些JSX表達(dá)式將渲染處相同的東西:


    image.png

    如果你想要一個(gè)值如false蝙场,true,null或undefined出現(xiàn)在輸出中粱年,你必須先將它轉(zhuǎn)換為字符串:


    image.png

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的寫法:


image.png

audio對(duì)象的方法和屬性:

我們可以動(dòng)態(tài)把一個(gè)audio元素插入到頁(yè)面中森缠,從而通過(guò) JS 來(lái)獲取這個(gè)對(duì)象,簡(jiǎn)單的方法如下:


image.png

image.png

事件:


image.png

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

Andyudd
addEventListener 用法

addEventListener 用于注冊(cè)事件處理程序蒋腮,IE 中為 attachEvent,我們?yōu)槭裁粗v addEventListener 而不講 attachEvent 呢藕各?一來(lái) attachEvent 比較簡(jiǎn)單池摧,二來(lái) addEventListener 才是 DOM 中的標(biāo)準(zhǔn)內(nèi)容。

  1. 簡(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

image.png

image.png

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

image.png

怎么找到下面的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選擇器

image.png


image.png

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


image.png

88.onsenui實(shí)現(xiàn)下拉列表展開樣式仿淘寶

image.png

![image.png](https://upload-images.jianshu.io/upload_images/8527411-e8c59f7eb3446996.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

img

89.充分利用before和after屬性

image.png

90.js的delete屬性

delete 操作符用于刪除對(duì)象的某個(gè)屬性;如果沒(méi)有指向這個(gè)屬性的引用携悯,那它最終會(huì)被釋放


image.png

image.png

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ù)組操作)

image.png

.rest(array) 移除數(shù)組首元素 和initial相反
85.js原生的indexOf和lodash中的indexOf
js:
①語(yǔ)法: stringObject.indexOf(searchvalue,fromindex)
image.png

②注意: 對(duì)大小寫敏感仰禀! 如果要檢索的字符串值沒(méi)有出現(xiàn),則該方法返回 -1蚕愤。
③例子:

lodash:
①語(yǔ)法: _.indexOf(array, value, [fromIndex=0])
②注意:第一個(gè)參數(shù)必須是數(shù)組
③例子:
image.png

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ù)組去重


image.png

簡(jiǎn)單來(lái)說(shuō)悬嗓,Set于Array的區(qū)別在于:Array中允許出現(xiàn)重復(fù)的元素,例如[1,2,2,3]裕坊;而Set中的所有元素都是唯一的包竹,只能是{1,2,3}。利用這一特性籍凝,我們就可以迅速地去掉數(shù)組中重復(fù)的元素周瞎。


image.png
let sessionListAll = Array.from(new Set(sessionData));
classchollArrayId= [...new Set(classchollArrayId)]//數(shù)組去重

②lodash uniq/unique 數(shù)組去重


image.png

③lodash union數(shù)組合并去重


image.png

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()搭配使用


image.png

image.png

image.png

image.png

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 命令
    1. 安裝模塊到項(xiàng)目node_modules目錄下。
    2. 不會(huì)將模塊依賴寫入devDependencies或dependencies 節(jié)點(diǎn)牡肉。
    3. 運(yùn)行 npm install 初始化項(xiàng)目時(shí)不會(huì)下載模塊捧灰。
  • npm install -g moduleName 命令
    1. 安裝模塊到全局侠坎,不會(huì)在項(xiàng)目node_modules目錄中保存模塊包耸峭。
    2. 不會(huì)將模塊依賴寫入devDependencies或dependencies 節(jié)點(diǎn)志笼。
    3. 運(yùn)行 npm install 初始化項(xiàng)目時(shí)不會(huì)下載模塊徘郭。
  • npm install -save * * moduleName 命令
    1. 安裝模塊到項(xiàng)目node_modules目錄下亦镶。
    2. 會(huì)將模塊依賴寫入dependencies 節(jié)點(diǎn)洁段。
    3. 運(yùn)行 npm install 初始化項(xiàng)目時(shí)秃殉,會(huì)將模塊下載到項(xiàng)目目錄下识埋。
    4. 運(yùn)行npm install --production或者注明NODE_ENV變量值為production時(shí)免绿,會(huì)自動(dòng)下載模塊到node_modules目錄中唧席。
  • npm install -save-dev moduleName 命令
    1. 安裝模塊到項(xiàng)目node_modules目錄下。
    2. 會(huì)將模塊依賴寫入devDependencies 節(jié)點(diǎn)嘲驾。
    3. 運(yùn)行 npm install 初始化項(xiàng)目時(shí)淌哟,會(huì)將模塊下載到項(xiàng)目目錄下。
    4. 運(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ì)象

image.png

image.png

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è)面的

image.png

image.png

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

image.png
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

image.png

image.png

image.png

put 就是我們所說(shuō)的一個(gè)調(diào)用 Effect 的例子
call 就像 put懂昂, 返回一個(gè)指示 middleware 以給定參數(shù)調(diào)用給定的函數(shù)的 Effect介时。

image.png

image.png

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)被取消徒蟆。
image.png

image.png

在 Generator 函數(shù)中,yield 右邊的任何表達(dá)式都會(huì)被求值型型,結(jié)果會(huì)被 yield 給調(diào)用者
image.png

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 姥闪。

image.png

race
image.png

image.png

yield* 操作符來(lái)組合多個(gè) Sagas,使得它們保持順序砌烁。 這讓你可以一種簡(jiǎn)單的程序風(fēng)格來(lái)排列你的 宏觀任務(wù)(macro-tasks)筐喳。


image.png

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])

image.png

.xorBy([arrays], [iteratee=.identity])
image.png

3)_.xorWith([arrays], [comparator])
image.png

  • 106.對(duì)象中數(shù)組對(duì)象去重


    image.png

    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)有彈出


    報(bào)錯(cuò)信息

    保存函數(shù)代碼

    antd官網(wǎng)API

    解決后代碼
  • 2.Redirect to屬性報(bào)錯(cuò)
    定位問(wèn)題:通過(guò) '>' expected可以想到>是html片段符號(hào),而文件后綴是ts缘薛,也就是文件類型應(yīng)該是tsx窍育。所以把文件后綴改為tsx,問(wèn)題解決


    路由重定位代碼

    報(bào)錯(cuò)信息
  • 3.DatePicker組件總是顯示成英文


    原國(guó)際化配置代碼

    相應(yīng)組件

    問(wèn)題解決:


    官網(wǎng)API

    image.png

109.antd中父組件怎么使用子組件的form中自帶的屬性

  • 1.父組件將form傳給子組件宴胧,子組件使用父組件傳下來(lái)的form


    image.png

    父組件使用Form.create()

    子組件不再使用Form.create()
  • 2.使用官網(wǎng)API


    image.png

    ①在父組件ExamCreation中不使用Form


    image.png

    ②在各個(gè)子組件中使用Form漱抓,然后在父組件ExamCreation中調(diào)用的子組件上加上那個(gè)屬性,最后就可以像在子組件一樣使用form中的API了恕齐。(注意:使用typeScript時(shí)一定要先定義this.form3...)
    子組件通過(guò)Form創(chuàng)建
wrappedComponentRef

使用子組件Form中的方法

先定義實(shí)例form3

110. antd升級(jí)到3.6.5版本后遇到問(wèn)題及解決

  • 1.Pagination組件顯示成英文


    Pagination

    解決方法:
    ①引入antd國(guó)際化組件LocaleProvider 和需要的語(yǔ)言包


    引入組件和語(yǔ)言包

②用國(guó)際化組件將分頁(yè)組件包裹起來(lái)


image.png
  • 2.DatePicker組件顯示成英文


    image.png

    解決方法:除了上面使用LocaleProvider 組件解決乞娄,DatePicker組件有自帶的語(yǔ)言包


    image.png

    image.png

111.在git上提merge request的時(shí)候,上面檢測(cè)到的更改是显歧,自己的遠(yuǎn)程分支和master分支代碼對(duì)比的結(jié)果

112.使用Redirect的時(shí)候報(bào)錯(cuò)

image.png

image.png

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:

ie

Firefox:
Firefox

Chrome:
chrome

  1. new Date(date).getTime()
    IE:
    ie

    Firefox:
    Firefox

    Chrome:
    chrome

注意:兩種方法在三個(gè)瀏覽器都能起作用的日期格式是 / 分割的昔汉,所以要使用該方法的話使用 .replace()轉(zhuǎn)化,如IE下的:

image.png

image.png

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文件

image.png

第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 提交需注意

image.png
image.png

把提交函數(shù)寫在Form上會(huì)導(dǎo)致:表單提交后在地址欄會(huì)添一個(gè)“疮跑?”组贺,界面刷新

image.png

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)題

錯(cuò)誤做法

不更新的原因:更新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)求好幾次

這樣會(huì)出現(xiàn)新問(wèn)題
多次請(qǐng)求

多次請(qǐng)求原因:props中有些變量值改變導(dǎo)致重新render鞠眉,如loading由false變成true又變成false
解決方法:將url后的隨機(jī)變量的值從models中傳過(guò)來(lái)

image.png
image.png

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):

  1. ProviderConsumer 必須來(lái)自同一次 React.createContext 調(diào)用。也就是說(shuō) NameContext.ProviderAgeContext.Consumer 是無(wú)法搭配使用的煮剧。
  2. React.createContext 方法接收一個(gè)默認(rèn)值作為參數(shù)斥滤。當(dāng) Consumer 外層沒(méi)有對(duì)應(yīng)的 Provider 時(shí)就會(huì)使用該默認(rèn)值。
  3. Provider 組件的 value prop 值發(fā)生變更時(shí)勉盅,其內(nèi)部組件樹中對(duì)應(yīng)的 Consumer 組件會(huì)接收到新值并重新執(zhí)行 children 函數(shù)佑颇。此過(guò)程不受 shouldComponentUpdete 方法的影響。前面的示例代碼中草娜,Hello 組件繼承自 React.PureComponent 但頁(yè)面依然能正確顯示足以說(shuō)明這一點(diǎn)挑胸。
  4. Provider 組件利用 Object.is 檢測(cè) value prop 的值是否有更新。注意 Object.is=== 的行為不完全相同宰闰。具體細(xì)節(jié)請(qǐng)參考 Object.is 的 MDN 文檔頁(yè)茬贵。
  5. Consumer 組件接收一個(gè)函數(shù)作為 children prop 并利用該函數(shù)的返回值生成組件樹的模式被稱為 Render Props 模式簿透。詳細(xì)介紹請(qǐng)參考相關(guān) React 文檔

127.在models層獲取全局狀態(tài)樹數(shù)據(jù)

  1. Redux下:const state =(window as GlobalDefinitions).store.getState().namespaceName
  2. 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)事件

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末砂轻,一起剝皮案震驚了整個(gè)濱河市奔誓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搔涝,老刑警劉巖厨喂,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異庄呈,居然都是意外死亡蜕煌,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門诬留,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)斜纪,“玉大人,你說(shuō)我怎么就攤上這事文兑『懈眨” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵绿贞,是天一觀的道長(zhǎng)因块。 經(jīng)常有香客問(wèn)我,道長(zhǎng)籍铁,這世上最難降的妖魔是什么贮聂? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任靠柑,我火速辦了婚禮,結(jié)果婚禮上吓懈,老公的妹妹穿的比我還像新娘歼冰。我一直安慰自己,他們只是感情好耻警,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布隔嫡。 她就那樣靜靜地躺著板驳,像睡著了一般寥枝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上儒旬,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天温兼,我揣著相機(jī)與錄音秸滴,去河邊找鬼。 笑死募判,一個(gè)胖子當(dāng)著我的面吹牛荡含,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播届垫,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼释液,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了装处?” 一聲冷哼從身側(cè)響起误债,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妄迁,沒(méi)想到半個(gè)月后寝蹈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡登淘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年箫老,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片形帮。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡槽惫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出辩撑,到底是詐尸還是另有隱情界斜,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布合冀,位于F島的核電站各薇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜峭判,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一开缎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧林螃,春花似錦奕删、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至横漏,卻和暖如春谨设,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缎浇。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工扎拣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人素跺。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓二蓝,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親亡笑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子侣夷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 深入JSX date:20170412筆記原文其實(shí)JSX是React.createElement(componen...
    gaoer1938閱讀 8,061評(píng)論 2 35
  • 一直欽佩仗劍走天涯的俠客。興許是現(xiàn)實(shí)的平淡地回,或是生活的壓抑扁远,也可能是天性如此,我們對(duì)自由都有著強(qiáng)烈的渴望刻像。 靈魂與...
    素懷閱讀 1,940評(píng)論 51 51
  • 山不在高畅买,有仙則名;水不在深细睡,有龍則靈谷羞。 茶棚老先生捋了捋長(zhǎng)胡子,開口悠悠道來(lái): “西南方有座山溜徙,場(chǎng)面云縈霧繞湃缎,不...
    淮音閱讀 569評(píng)論 0 0
  • 此時(shí)犀填,此刻,此地
    神秘嘉賓方閱讀 220評(píng)論 0 0
  • 真正的旅行不在乎是否到達(dá)終點(diǎn)嗓违,而是旅行后能夠回憶起沿途的人和美好的事九巡,這就是幸福。 2016年4月2日早晨蹂季,我和兩...
    小時(shí)公子閱讀 1,262評(píng)論 76 44