前端經驗 取值,改值或者渲染 js使用經驗--取值,改值,渲染

js使用經驗--取值,改值,渲染

有時間了,就寫一寫前端的項目遇到的幾個常見的問題,爲了記錄工作,總結下,對自己有或多或少的幫助。也許,十幾年後回過頭來,能看到自己的影子,走過的路跡。

因爲深度拷貝項目中用的多,所以啊,也在裏面提及。

取值

前端是什麼,前端就是把後臺的數據或者自定義的數據渲染到頁面上,或者自定義數據或者從頁面拿數據作爲參數給後臺接口。渲染數據主要用的是後臺的數據,而給後臺接口的數據主要來自頁面或者後臺上一次的接口。

所以從頁面(html)拿數據給後臺就變得很重要或者頻繁,做好這一步,對工作效率的提高是很大的幫助。

方式一、原生js支持dataSet,只要在標籤內data-就能嵌入值,在js裏面dom.dataset就能拿到對應的值。

方式二、vue有雙向數據綁定,v-model把data的值插入到標籤。這個data的值就是需要的值。

啥時候取值

在項目中有時不會這個簡單。記得有一次我做xx所有人信息時,那一塊需要一個數組,數組的每一項對應着姓名(輸入框),類型(單項),電話,證件,地址(下拉框)等等。我要採集這一塊數據有兩個方案:給每一個輸入項綁定事件,比如輸入框onblur,onchang,等等,可以穩穩實現,但是代碼量多,以後改動起來不好改;利用監聽vuex裏面的某個狀態變化便採集開始數據,但是需要寫兩個state狀態值,對原來保存功能的代碼改動大,不是個好方法。

後來在我思考選哪一種方式時,坐地鐵時,突然想起onmouseleave事件可以完美解決這個問題。xx所有人信息塊是一個區域,技術上來說是個標籤div,每次點擊保存時鼠標一定要移出這個區域,我只要添加mouseleave,讓那會生成後臺需要數組,等真正點擊保存按鈕時,數據肯定是就緒的。一行代碼的事。如果我選擇上面的方式之一,10到50行不同地方的代碼,維護起來就不容易。你看,onmouseleave這個了不起眼的事件,在這個時候就起到很大的作用。所以有時間需要了解一些原生js,vue的事件,說不定那天就大派用場。

這件事給我的啓發是,用一種方式做一件事(不限寫代碼)的時候,如果感覺有困難,很可能是這個方式有問題,那就要多想其他的2種方式,在這幾種方式挑最有好的。這樣子,事半工倍。寫代碼時,如果項目任務不是特別急,時間充裕下,停下來想好再編碼,對公司,對自己都是好事。否則很可能在項目裏挖一些坑。

代碼寫的簡潔,對自己和項目是好事。但是給領導那邊不好交代。代碼寫簡潔就是用行數少的代碼去做多的時間,代碼行數少,領導知道這個以爲你做事情不多或者工作不飽和,這樣不太好。有一次代碼評審時,別人一看我的代碼少,就問你叫什麼名字,是不是工作不飽和。其實我只是代碼寫簡潔了,用這種方式之前我還用過其他一種複雜的方式,後來纔想到後來這種優化的方式,說白了就是取巧。我的工作量並沒有像代碼行數那樣少,應該說不多不少,因爲除了寫代碼,還要走測試流程呢。沒地方吐槽,便來這裏吐槽唄。

到源頭取值

vue ui選擇框,選擇框下數組通常是前端定義好或者後來返回來的。當選擇了其中一項時,我們使用onchange,很容易拿到當前選擇的一個值,去做點什麼。如果是後臺需要該數組下的當前選擇的2個以上或者幾個字段的值時,那怎麼辦?onchange只能拿到綁定在下面標籤的一個字段。我的同事包括我吧,曾經感覺這個很難,用dataSet不方便,onchange在v-for的外面。因爲我們都犯了一個錯:把注意力留在html層面。其實,回到數據源頭,事情變得很簡單。你看下面代碼,v-for需要的dataList,我們需要的東西就在dataList,其實到DataList去要就行,它纔是源頭。html它是個中間人,可以不管它,因爲html的數據值也是由dataList提供的啊。

具體是dataList的哪一項呢?拿到目標數據項的某個屬性值(不限於index),藉助array.filter這個函數(我在公衆號文章《js使用經驗--遍歷》體驗過),輕鬆拿到。實現如下:

//vue
<pax-select defaultValue="lucy" style="width: 120px" @change="handleChange">
      <pax-select-option :value="item.value" v-for="(item,index ) in dataList">{{item.name}}</pax-select-option>
</pax-select>


//js
data(){
    return {
        dataList: [{
            value: 'value'
            ... //省略很多行代碼
        }]
    }  
},
methods: {
    handleChange(value) {
        let targetItem = this.dataList.filter((item) => {
            //因爲value是唯一的,所以拿它做標記
            return item.value === value;
        })[0];
        //之後就乾點什麼
    }
}

改值

深度拷貝

取值後,我們通常需要對數據處理,達到某個目的。在調用一些工具類處理對象或者數組時,會把原來的對象或數組改變,我們並不需要這樣的改變。這時候,就需要深度拷貝。

爲啥會改變呢,因爲引用,原數據和新數據用的是同一個內存地址,他們是同一個東西。深度拷貝就是不管數據有多複雜,原封不動的拷貝一樣的過來。無論怎麼改後者,前者都不變。

這玩意有啥用呢。有一次,我做一個4個SY人信息的錄入,保存,再次第二次保存時,發現上一次信息數據殘留,回填着呢。沒辦法啊,只有改,排查keepAlive找一會找不到,肯定不是那個問題,因爲其他信息錄入沒有問題。後來纔想到應該是data裏面的數據數組和初始值數組(後者賦值給前者),它們的聯繫沒有切斷。使用深度拷貝這個概念切斷它們的聯繫,讓它們在內存中獨立存在,這個數據殘留的問題就解決了哈。

//todo 寫一寫頁面數據和後臺數據。

一、一維數組,對象的拷貝

數組:concat() 拓展運算符... Array.from
對象:Object.assign() 擴展運算符...

注意使用 assign() 有如下特點:不會拷貝對象繼承的屬性、不可枚舉的屬性、屬性的數據屬性/訪問器屬性;可以拷貝 Symbol 類型。

以上他們只能對一維的數據深度拷貝,對二維和多維無效,因爲還是引用那個問題。

二、 二維以上的深度拷貝

(1)最常用的 JSON 序列化與反序列化
JSON.parse(JSON.stringify(obj))

簡單粗爆,但是有缺陷:

拷貝的對象的值中如果有函數、undefined、symbol,則經過 JSON.stringify() 序列化後的 JSON 字符串中這個鍵值對會消失;
拷貝 Date 引用類型會變成字符串;
拷貝 RegExp 引用類型會變成空對象;
等等。

(2)lodash 的深拷貝 cloneDeep(推薦,最靠譜的)
使用 lodash 插件的深拷貝方法

(3) 自己擼一個輪子,玩下

其實實現思路很簡單,就是遍歷一個對象,查看它內部的屬性值的類型,如果是對象和數組等等,再次進去遍歷;如果是簡單的數據類型,就做賦值操作。因爲對象和數組的賦值是給引用,普通的數組類型是真給值,當然存在這非對象數組非普通數據的第三種情況(工作中很少遇到而已)。

需要用到遞歸,arguments.callee可以簡化寫法。

function deepClone(Obj){
    let result;
    let topType = Object.prototype.toString.call(Obj);     // "[object Array]"
    let callee =  arguments.callee;
    result = ['[object Object]'].includes(topType) ? {} : [];


    if(['[object Object]'].includes(topType)){
        Object.keys(Obj).forEach((item, index)=>{
            result[item] = callee(Obj[item])
        })
    }else if(['[object Array]'].includes(topType)){
        Obj.reduce((pre, cur) => {
            result.push(callee(cur))
            return [];
        },[])
    }else{
        //省略 
        //這裏可以擴展其他條件
        result = Obj
    }


    return result;
}


//測試
let obj = {
    name: 'admin',
    arr: [2,3,{name: 'name',value: 'value'}],
    obj: {
        name: 'admin2'
    },
    deepClone: function(){
        console.log('hello word')
    }
}
let obj2 = deepClone(obj);
obj2.arr[2].name = [1,2,88]
obj2.obj.name = '周星馳'
obj2.deepClone = function(){
    console.log('fuck pinan')
}


console.log(obj)     
console.log(obj2)
obj.deepClone();
obj2.deepClone();


(4) 30second of code 有名的代碼片段

人家的代碼簡潔,整理代碼應該往這種方向走,讓我寫,我肯定寫不出來。

const deepClone = obj => {
  if (obj === null) return null;
  let clone = Object.assign({}, obj);
  Object.keys(clone).forEach(
    key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
  );
  return Array.isArray(obj) && obj.length
    ? (clone.length = obj.length) && Array.from(clone)
    : Array.isArray(obj)
    ? Array.from(obj)
    : clone;
};

vue頁面渲染,$set

最近遇到一個vue項目的問題,感覺算經典的,挺有意思的。就是在頁面上渲染一個數組,採集SY人的基本信息,這個數組的每一項採集名稱,年齡,日期等字段,可刪可增。在做項目的過程中,發現刪除第一項,怎麼也刪除不了;當時試了2種方法,比如set等等,

最後發現是:key='index'的問題。只要讓:key=id就可以了。ID是獨一無二的,index不是。vue的v-for每一項的是否重新渲染是看key是否變化,給id值確保了頁面做刪除操作了,頁面重新渲染,因爲id肯定變化了。

其實這類的問題最快捷的解決方法就是去vue的官網上找文檔觀看,瞭解v-for的運行機制,就可以解決答案。我很幸運,是朋友告訴我的。哈哈。

如果是數據複雜時,比如,數組的每一項是對象,對象下某個屬性是對象。改變最底層的某個屬性值,而頁面上不更新。這時候需要要set方法。實現很簡單,代碼如下:

this.$set(this.obj,'e',02)

最後,歡迎關注我的公衆號。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章