原生JS結合cookie實現商品評分元件
阿新 • • 發佈:2020-11-01
元件樣式效果:
再次訪問記錄使用者上次操作:
開發思路如下:
1.利用JS直接操作DOM的方式開發商品評分元件,主要實現功能有:顯示評價評分的樣式以及將使用者操作後對應的資料返回到主頁面
2.主頁面引入商品評分元件的js檔案並根據規定格式的資料,生成對應的元件元素並插入頁面
3.主頁面利用偵聽事件接收元件拋發的資料並儲存,每次有元件拋發事件都會覆蓋上次拋發的資料,直到頁面關閉,將最後一次拋發的資料儲存到cookie中。
4.當再次開啟主頁面時,先判斷cookie中是否有對應的資料,如果有提取cookie其中的資料,先根據頁面資料生成對應的元件元素,再將cookie中資料傳入對應元件元素中重新渲染,最後將元素插入主頁面
注意點:
因為當再次開啟頁面,使用者可能不一定會修改所有的元件元素,這樣元件丟擲的資料就不完整,不會是所有元素的資料,當我們在儲存資料的時候需要和上一次儲存的資料進行比對,只覆蓋和上一次儲存資料不同的屬性,保證資料的完整性。
主頁面JS部分程式碼如下:
import Star from "./js/Star.js"; var data=["商品符合度","店家服務態度","快遞配送速度","快遞員服務","快遞包裝"]; var cookieStorage={}; // 初始化載入先拿到cookie,切割好資料之後,在初始化建立渲染完評分資料物件之後,再通過setData的方法修改資料 var hository=JSON.parse(document.cookie.split("=")[1]); data.forEach((item)=>{ var star=new Star(item); star.addEventListener("change",changeHandler); if(JSON.stringify(hository)!=="{}"){//判斷cookie中是否有對應的資料 star.setData(hository[item]) } star.appendTo(".ShowStarList"); }) cookieStorage=hository; function changeHandler(e){ for(var prop in e.StarList){//因為當再次開啟頁面,使用者可能不一定會修改所有的元件元素,這樣丟擲的資料就不完整不會是所有元素的資料 cookieStorage[prop]=e.StarList[prop]; } } //頁面點選操作之後,將資料存放到cookieStorage中,當下一次再點選時將cookieStorage中的資料覆蓋 // 直到頁面被關閉時,觸發下述事件,將cookieStorage+時間段的方式儲存到cookie中 window.onbeforeunload=closeHandler; function closeHandler(){ var date=new Date(); date.setFullYear(2021); document.cookie="cookieStorage="+JSON.stringify(cookieStorage)+";expires="+date.toUTCString(); }
商品評分元件JS部分程式碼如下:
import Base from "./Base.js"; export default class Star extends Base{ static StarList = {};//用來儲存資料選中的評分資料到時候返回頁面 label; starCon = []; pos=-1 labelWrap; starWrap; face; scoreWrap; constructor(_label) { // 第一次建立是用label生成的物件,後面都是用StarList去渲染物件 super(); this.label = _label; this.elem.setAttribute("class", "StarCon"); this.createStarCon(); this.setStyle(); } //建立評分元件的HTML結構 createStarCon() { this.labelWrap = document.createElement("span"); this.labelWrap.textContent = this.label; this.starWrap = document.createElement("div"); for (let i = 0; i < 5; i++){ let singleStar = document.createElement("div"); singleStar.setAttribute("class", "singleStar"); this.starWrap.appendChild(singleStar); this.starCon.push(singleStar); } this.face = document.createElement("div"); this.starWrap.appendChild(this.face); this.scoreWrap = document.createElement("span"); this.scoreWrap.textContent = "0分"; this.labelWrap.setAttribute("class", "label"); this.starWrap.setAttribute("class", "star"); this.face.setAttribute("class", "face"); this.scoreWrap.setAttribute("class", "score"); this.elem.appendChild(this.labelWrap); this.elem.appendChild(this.starWrap); this.elem.appendChild(this.scoreWrap); this.starWrap.addEventListener("mouseover",e=>this.mouseHandler(e)); this.starWrap.addEventListener("click",e=>this.mouseHandler(e)); this.starWrap.addEventListener("mouseleave",e=>this.mouseHandler(e)); } mouseHandler(e) { // click和mouseover都要不停渲染星星樣式,所以都要通過遍歷識別滑鼠當前指向的是哪個e.target,從而通過for迴圈渲染星星 // 其中點選事件和滑鼠移動事件不同的地方在於 // 點選事件會記錄下一個全域性變數pos表示選中該資料,且會丟擲事件傳遞包括同頁面其他例項物件的資料給頁面 // 滑鼠移動事件則是利用相同原理除了渲染星星外,還要渲染分數和笑臉 switch (e.type) { case "mouseover": let index = this.starCon.indexOf(e.target); if (index < 0) return; this.changeScore(index + 1); this.changeFace(index); this.changeStar(index); break; case "click": let index1 = this.starCon.indexOf(e.target); if (index1 < 0) return; this.pos = index1; this.dispatch(); this.changeStar(index1); break; case "mouseleave": this.changeStar(this.pos); this.changeScore(this.pos + 1); this.changeFace(-1); break; } } //根據分數改變星星樣式 changeStar(n){ for(var i=0;i<this.starCon.length;i++){ if(i<=n || i<=this.pos){ this.starCon[i].style.backgroundPositionY="-16px"; }else{ this.starCon[i].style.backgroundPositionY="0px"; } } } //根據分數改變分數樣式 changeScore(n){ this.scoreWrap.textContent=n+"分"; if(n===0){ this.scoreWrap.style.color="#999"; }else{ this.scoreWrap.style.color="#e4393c"; } } //根據分數改變笑臉樣式 changeFace(n){ if(n<0){ this.face.style.display="none"; return } var index=5-n-1 // 滑鼠移動時,笑臉的div位置和其背景圖的位置都要同時移動 // 滑鼠離開或者點選之後,笑臉消失 this.face.style.display="block"; this.face.style.backgroundPositionX=-index*20+"px"; this.face.style.left=this.starCon[n].offsetLeft+"px"; } //每次點選後拋發改變後的例項化元件元素群組的資料 dispatch() { Star.StarList[this.label]=this.pos+1; var evt=new Event("change"); evt.score=this.pos+1; evt.label=this.label; evt.StarList=Star.StarList; this.dispatchEvent(evt); } //根據cookie傳入的資料重新渲染元件元素 setData(historyScore) { if (historyScore < 1) return; this.pos = historyScore-1; this.changeStar(historyScore-1); this.changeScore(historyScore); } //設定例項化元件的樣式 setStyle() { Utils.addCSS(".label",{ float: "left", height: "16px", font: '12px / 150% tahoma, arial, "Microsoft YaHei", "Hiragino Sans GB", 宋體, sans-serif', marginRight: "10px", overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis", color: "rgb(102, 102, 102)", }); Utils.addCSS(".star",{ float: "left", height: "16px", position: "relative", marginTop: "1px", }); Utils.addCSS(".singleStar",{ float: "left", height: "16px", width: "16px", backgroundImage: "url(../img/commstar.png)", backgroundPositionY: "0px", }); Utils.addCSS(".face",{ height: "16px", width: "16px", backgroundImage: "url(../img/face-red.png)", position:"absolute", top:"-16px", display: "none", backgroundPositionX:"0px", left:"0px", }); Utils.addCSS(".score",{ position:"relative", width:"30px", height:"16px", top:"-2px", marginLeft: "10px", font: '12px / 150% tahoma, arial, "Microsoft YaHei", "Hiragino Sans GB", 宋體, sans-serif', textAlign:"right", color:"#999", }); } }