天天看點

開發過程中遇到的問題

  1. try catch 在接口中使用注意

使用 try catch 的使用無論是在 try 中的代碼還是在 catch 中的代碼性能消耗都是一樣的。需要注意的性能消耗在于 try catch 中不要直接塞進去太多的代碼(聲明太多的變量),最好是吧所有要執行的代碼放在另一個 function 中,通過調用這個 function 來執行。針對第二點,可以檢視 ECMA 中關于 try catch 的解釋,在代碼進入 try catch 的時候 js引擎會拷貝目前的詞法環境,拷貝的其實就是目前 scope 下的所有的變量。建議在使用 try catch 的時候盡量把 try catch 放在一個相對幹淨的 scope 中,同時在 try catch 語句中也盡量保證足夠少的變量,最好通過函數調用方式來 try catch。

try {
        yield call(services.deleteComment, i, commentid);
        Toast.success('删除成功',1.5);
        yield put(routerRedux.push('/notebooks/comment'));
      } catch (e) {
        Toast.fail('删除失敗',1.5);
      }
           

2.在開發過程中程式會在不同手機的浏覽器進行使用,偶爾會在操作中出現以下現象:

image.png

點着點着會引發浏覽器自帶選中文字狀态。

解決方案(不可複制,不可選擇)

body {
    -webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
  }
           
  1. 在react+antd+dva的項目中內建html2canvas截圖功能

首先在已經建立好得項目的檔案夾下找到 index.ejs 這個檔案

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>111</title>
</head>
<body>
  <div id="root" style="background: #efefef"></div>
</body>
<script src="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.js"></script>
</html>

           

導入線上的/html2canvas.js檔案,然後在寫一個頁面,正文如下:

screenshot(event){// 截圖并儲存到本地
         html2canvas(document.body).then(function(canvas) {    
            canvas.id = "mycanvas";         
            let newImg = document.createElement("img");  
            let newSrc = document.createElement("a");  
            let type = 'png';
            let imgData = canvas.toDataURL(type);
            let saveFile = function(data, filename){
            let save_link = document.createElementNS('http://www.x3.org/1999/xtml', 'a');
                save_link.href = data;
                save_link.download = filename;
                let event = document.createEvent('MouseEvents');
                event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                save_link.dispatchEvent(event);
            };
            let filename = '圖檔名' + (new Date()).getTime() + '.' + 'png';
            let ua = navigator.userAgent.toLowerCase();   
                  saveFile(imgData,filename);
                  newImg.src =  imgData;   
          })    
    }

return(
<div>
        <div id="textArea"> 11111111111</div>
        <button onclick={(event) => this.screenshot(event)}>截圖</button>
</div>
)
           

4.實時通訊(該demo隻是前端的部分)

css:

.labText {
             min-height: 230px;
             border: solid 1px #eee;
             width: 1000px;
             margin: 10px auto;
             height: 300px;
             overflow-y: scroll;
         }
           

html:

<input type="text" id="txtSendText" /><input id="btnSend" type="button" value="send" />
<div id="labText">消息:</div> 
<script src="jquery-1.8.3.min.js"></script>
<script src="jquery.signalR-2.1.2.min.js"></script>
<script src="http://192.168.118.100:8080/signalr/hubs"></script>
 // 此檔案是在c#中下載下傳signalR自動生成的,最好後端放在伺服器上,你直接寫路徑。
           

js:

function showMessage(msg) {
            $("#labText").append("<div>" + msg + "</div>");
        }
     $(function () {
        // Declare a proxy to reference the hub.
        var hub = $.connection.Hub;
        console.log(hub)
        $.connection.hub.qs = {patientName:"jack",id:9000};
        $.connection.hub.url = "http://192.168.118.100:8080/signalr"; // 是伺服器上的檔案

        // Create a function that the hub can call to broadcast messages.
        hub.client.sendMessage = function (msg) {
            $("#labText").append("<div>" + msg+"</div>");

        };
        hub.client.BroadcastMessage = (msg) => {
            showMessage(msg);
        };
        // Start the connection.
        $.connection.hub.start({jsonp:true}).done(() => {
            alert("啟動成功!");
            $("#btnSend").click(function() {
                var msg = $("#txtSendText").val();
                console.log(msg)
                hub.server.sendToAll(msg);
                $("#txtSendText").val("").focus();
            });
            // hub.server.hello();
        });
        $.connection.hub.error((error) => {
            // showMessage("啟動成功!");
            console.log(error)
            alert("啟動失敗!")
        });

    });
           

5.this.setState的寫法表示不同的含義

驅動元件渲染的過程中除了prop, 還有state,state代表的是元件内部的狀态。由于React元件不能修改傳入的prop,是以需要記錄自身資料變化,就要使用state。

示例:

this.setState({...owner, name: ‘Jason'}) 
//   相當于把name鍵值對添加到owner對象裡(把owner對象裡面的name的值替換成Jason)     
 this.setState(...owner, {name: ‘Jason’}) 
//   把整個owner對象替換為 name: Jason
           

舉例:

let aWithOverrides = { …a, x: 1, y: 2 };
    //  等同于
     let aWithOverrides =  { …a, …{ x: 1; y: 2} };
    //  等同于
     let x = 1, y = 2, aWithOverrides = { ...a, x, y };
    //  等同于
     let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 });
           
  1. react中元件被重新渲染(閃屏現象)

簡介:ShouldCompleteUpdate,下文簡稱SCU,就是指明什麼時候component(元件)需要進行更新。

constructor(props) {
        super(props);
        this.onClickButton = this.onClickButton.bind(this);
        this.state = { count: 0};
  }
 shouldComponentUpdate(nextProps, nextState) {
      if (this.state.count !== nextState.count) {
        return true;
      }
      return false;
  }
onClickButton() {
        this.setState({ count: this.state.count + 1 });
  }
// 其中的state.count的值要被改變的,我們可以直接用SCU
// 元件僅僅會校驗state.count,如果這些值都不會改變,那麼元件就不會有更新。
           
constructor(props) {
      super(props);
       // console.log(this.props);
      this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
      this.onClickDecrementButton = this.onClickDecrementButton.bind(this);
      // this.foo = ::this.foo 其他教程中可以這樣去編寫它
      // this.foo = this.foo.bind(this)

      this.state = {
        count: props.initValue // initValue 是一個可選的props 
      }
    }

  /*
  getInitialState() {
    getInitialState的傳回值用來初始化元件的this.state,隻有用React.createClass方法創造的元件類才會起作用,
    在這裡這個函數是根本不起作用的
    console.log('enter getInitialState');
  }

  getDefaultProps() {

    console.log('enter getDefaultProps');
  }
  */
  componentWillReceiveProps(nextProps) {}

  componentWillMount() {}

  componentDidMount() {}

  onClickIncrementButton() {
    this.setState({count: this.state.count + 1}); 
  }

  onClickDecrementButton() {
    this.setState({count: this.state.count - 1});
  }

  shouldComponentUpdate(nextProps, nextState) {
    return (nextProps.caption !== this.props.caption) ||
           (nextState.count !== this.state.count);
  }
// 
當頁面重新被渲染之前,把一些不必要的和沒有渲染的節點進行處理。
因為頁面的兩部分分别渲染5000個節點,從1-5000。
當點選按鈕之後,第二部分的節點會更新,重新渲染從2-5001的數字,但是第一部分保持不變。
是以說SCU是在元件沒被二次渲染之前删掉一些浪費的渲染。
shouldComponentUpdate這個函數是必須是在react的生命周期函數中去調用。
//
           

7.在react中導入iconfont圖示字型遇到的狀況

首先:

(1)去阿裡矢量圖官網

http://www.iconfont.cn/

添加你所喜歡的

iconfont

,然後你的購物車裡面就是你添加的

one.png

(2)把購物車中

添加已有的項目

qqq

中去,如果沒有的可以在右上腳建立新的項目

two.png

(3)把項目的代碼複制下來,跟本地添加

一樣。

three.jpg

示例如下:

(3)index.css中内容

// 本地和導入項目 這個是固定的
.iconfont{
    font-family:"iconfont";
    font-size:40px;
    font-style:normal;
}

//這個就是你複制在iconfont上的代碼連結(你添加在項目中的iconfont)
@font-face {
  font-family: 'iconfont';  /* project id 499958 */
  src: url('//at.alicdn.com/t/font_499958_759xzvyfw16k1emi.eot');
  src: url('//at.alicdn.com/t/font_499958_759xzvyfw16k1emi.eot?#iefix') format('embedded-opentype'),
  url('//at.alicdn.com/t/font_499958_759xzvyfw16k1emi.woff') format('woff'),
  url('//at.alicdn.com/t/font_499958_759xzvyfw16k1emi.ttf') format('truetype'),
  url('//at.alicdn.com/t/font_499958_759xzvyfw16k1emi.svg#iconfont') format('svg');
}
           

(4)在頁面上的使用:

import styles from './index.css';// 引入CSS

render() {
    return (
      <div>
              <i className="iconfont">&#xe617;</i>// 老版本的寫法
              <i className={styles.iconfont}>&#xe617;</i>// 目前的寫法
      </div>
     )
 }
           

8.react(dva)+antd建立項目之後的路由問題

(1)之前低版本的路由是可以有嵌套關系的

return (
      <Router history={history}>
          <Route path="/" component={Layout}>
              <IndexRoute component={HealthyPage} />
              <Route path="department" component={DepartPage} />
              <Route path="signin" component={SigninPage} />
              <Route path="signup">
                    <IndexRoute component={SignupMobilePage} />
                    <Route path="2" component={SignupPasswordPage} />
                    <Route path="3" component={SignupUserInfoPage} />
              </Route>
              <Route path="forgot">
                    <IndexRoute component={ForgotPasswordPage} />
                    <Route path="reset" component={ResetPasswordPage} />
              </Route>
              <Route path="signauth" component={SignAuthPage} />
              <Route path="doctor" onEnter={() => requireAuth(app._store)}>
                    <IndexRoute component={DoctorPage} />
                    <Route path=":id" component={ConversationPage} />
              </Route>
              <Route path="healthy" onEnter={() => requireAuth(app._store)}>
              </Route>
      </Router>
  )
           

使用IndexRoute有利于代碼分離,也有利于使用React Router提供的各種API。

IndexRoute元件沒有路徑參數path

(2) 目前版本的路由是不可以嵌套的

<Router history={history}>
      <Switch>
          <Route path="/" exact component={SinAuthPage} />
          <Route path="/IndexPage" exact component={IndexPage} />
          <Route path="/Clickmobile" exact component={Clickmobile} />
          <Route path="/IndexPage/chd" exact component={chd} />
          <Route path="/IndexPage/pre" exact component={pre} />
          <Route path="/IndexPage/dia" exact component={dia} />
          <Route path="/IndexPage/phy" exact component={phy} />
          <Route path="/IndexPage/partum" exact component={partum} />
      </Switch>
    </Router>
           

現在是變的是單個頁面要單個單個的去寫,不能像之前的嵌套關系比較複雜啦。如果像之前那樣去寫的話會報以下的錯誤:

Syntax error: Expected corresponding JSX closing tag for <Switch>

什麼意思呢?意思就是說:相關的jsx文法有問題 直接報的是代碼有問題。

目前還有找到相對應的解決方案。