1. 程式人生 > 實用技巧 >原生JS結合cookie實現商品評分元件

原生JS結合cookie實現商品評分元件

元件樣式效果:

再次訪問記錄使用者上次操作:

開發思路如下:

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",
    });

  }
}