原生JS分析

这里主要是作为自己学习用的

这里纯JS原生,实现的动态效果有:放大镜 ,缩略图,选中商品属性 ,点击切换高亮的功能.点击叉号删除 

//封装一个函数 处理路径导航的效果
function createBreadcrumb() {
  //获取路径导航的数据
  var path = goodsData.path;
  //获取路径导航的容器元素
  var breadcrumb = document.querySelector('#root #content .container .breadcrumb');
  //遍历数组
  for (var i = 0; i < path.length; i++) {
    //创建 a 元素
    var a = document.createElement('a');
    //设置标签文本
    a.innerHTML = path[i].title;
    //设置 a 元素的 href 属性
    a.href = path[i].url;
    //将 a 元素插入到容器中
    breadcrumb.appendChild(a);

    //检测是否为数组的最后一个元素
    if (i !== path.length - 1) {
      //创建 span 元素
      var span = document.createElement('span');
      //设置 span 的文本
      span.innerHTML = '/';
      //将 span 插入到容器中
      breadcrumb.appendChild(span);
    }

  }

}
createBreadcrumb();

//遍历渲染缩略图元素
function renderThumbnails() {
  //获取所有的图片
  var images = goodsData.imagessrc;
  //获取 ul 元素
  var ul = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .thumbnails ul')
  //获取小图
  var smallImg = document.querySelector('#root #content .container .goods-intro-section .left .small-img > img');
  var bigImg = document.querySelector('#root #content .container .goods-intro-section .left .small-img .big-img img');
  //遍历图片数组
  images.forEach(function (item, index) {
    //创建 li 元素
    var li = document.createElement('li');
    //为当前元素添加数字下标
    li.index = index;
    // li.setAttribute('index', index); // 可以为标签设置属性, 方便事件中获取
    // li.dataset.index = index;// dataset //也可以通过 dataset 特性设置标签属性
    // li.dataset.abc = 'iloveyou';
    //创建 img 元素
    var img = document.createElement('img');
    //设置图片的 src 属性
    img.setAttribute('src', item.s);
    //将 img 元素插入到 li 中
    li.append(img);
    //将 li 插入到 ul 中
    ul.append(li);
    //判断是否为第一个元素
    if (index === 0) {
      //将小图和大图的 src 设置为当前的值
      //设置小图的 src
      smallImg.src = item['s'];
      //设置大图的 src
      bigImg.src = item.b;
      //设置当前 li 的类名为 active
      li.className = 'active';
    }
    //为 li 元素绑定单击事件
    li.onclick = function () {
      //同辈元素移除 active 类名
      this.parentNode.querySelectorAll('li').forEach(function (item) {
        item.className = '';
      })
      //为当前元素添加 active 类
      this.className = 'active';
      //获取当前元素在同辈元素中的下标
      var i = this.index;
      // console.log(this.index);
      // console.log(this.getAttribute('index'));
      // console.log(this.dataset.index);
      //获取当前下标对应的图片
      var images = goodsData.imagessrc[i];
      //修改小图和大图的路径
      smallImg.src = images.s;
      bigImg.src = images.b;
    }
  });
}
renderThumbnails();

//实现放大镜效果
function magnifier() {
  //获取 small-img 元素
  var smallImgDiv = document.querySelector('#root #content .container .goods-intro-section .left .small-img');
  //获取 mask 元素
  var mask = document.querySelector('#root #content .container .goods-intro-section .left .small-img .mask')
  //获取大图
  var bigImg = document.querySelector('#root #content .container .goods-intro-section .left .small-img .big-img img')
  //绑定鼠标移动事件
  smallImgDiv.onmousemove = function (e) {
    //获取鼠标距离左侧的偏移量
    var x = e.clientX;
    var y = e.clientY;
    //获取遮罩层元素宽度的一半
    var w = mask.offsetWidth / 2;
    var h = mask.offsetHeight / 2;
    //获取 small-img 距离窗口左侧的距离
    var l = smallImgDiv.getBoundingClientRect().left;
    var t = smallImgDiv.getBoundingClientRect().top;

    //计算 mask 元素的 left 值
    var newLeft = x - w - l;
    var newTop = y - h - t;
    //左侧边界判断
    if (newLeft < 0) {
      newLeft = 0;
    }
    //计算最大的 left 值
    var maxLeft = smallImgDiv.clientWidth - mask.offsetWidth;
    //右侧边界判断
    if (newLeft > maxLeft) {
      newLeft = maxLeft;
    }
    //上方边界检测
    if (newTop < 0) {
      newTop = 0;
    }
    //计算最大的 top 值
    var maxTop = smallImgDiv.clientHeight - mask.offsetHeight;
    //下方边界检测
    if (newTop > maxTop) {
      newTop = maxTop;
    }

    //设置 mask 元素的 left
    mask.style.left = newLeft + 'px';
    //设置 mask 元素的 top
    mask.style.top = newTop + 'px';

    //控制右侧大图的位移
    // 获取小图 div 的宽度
    var sw = smallImgDiv.clientWidth;
    var sh = smallImgDiv.clientHeight;
    // var s
    //获取大图的宽度
    var bigImgWidth = bigImg.offsetWidth;
    var bigNewLeft = newLeft / sw * bigImgWidth;

    var bigImgHeight = bigImg.offsetHeight;
    var bigNewTop = newTop / sh * bigImgHeight;
    //设置大图的 left 值
    bigImg.style.left = -bigNewLeft + 'px';
    bigImg.style.top = -bigNewTop + 'px';

  }

}
magnifier();

//缩略图中上一个和下一个的效果实现
function nextAndPrev() {
  //获取下一个的按钮
  var nextBtn = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .next')
  var prevBtn = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .prev')
  //缩略图的容器
  var thumbnail = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .thumbnails')
  //获取 ul
  var thumbUL = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .thumbnails ul')
  //获取缩略图中单个 li 的宽度
  var thumbLi = document.querySelector('#root #content .container .goods-intro-section .left .thumbnails-section .thumbnails ul li');
  var w = thumbLi.offsetWidth + 20;
  //绑定事件
  // //过addEventListener(添加点击事件监听器)形式的绑定事件不会互相抵消,从而实现一个按钮控制多个事件
  nextBtn.addEventListener('click', function () {
    //获取 ul 的左侧的偏移量
    var left = thumbUL.offsetLeft;
    //减少 ul 的 left 值
    var newLeft = left - w * 2;
    //计算最大的 left 绝对值
    var maxLeft = thumbUL.offsetWidth - thumbnail.offsetWidth - 12;
    //边界检测
    if (newLeft < -maxLeft) {
      newLeft = -maxLeft;
    }
    //设置 ul 新的 left 值
    // element.style   //行内样式操作   适用于要修改的不多
    thumbUL.style.left = newLeft + 'px';
  });
  //点击上一个
  // 给 prevBtn添加函数监听事件
  prevBtn.addEventListener('click', function () {
    //获取 ul 的左侧的偏移量
    //offsetLeft获取的是相对于父对象的左边距
    var left = thumbUL.offsetLeft;
    //减少 ul 的 left 值
    var newLeft = left + w * 2;
    //边界检测
    //if(条件表达式){console.log("a")};//如果条件为真,执行该处代码
    if (newLeft > 0) {
      newLeft = 0
    }
    //设置 ul 新的 left 值
    //left获取或设置相对于具有定位属性(position定义为relative)的父对象的左边距
    thumbUL.style.left = newLeft + 'px';
  })


}
// 结尾要写调用 函数才会生效
nextAndPrev();

//设置商品的基本信息
function setGoodsBasicInfo() {
  //获取商品的详细信息
  //var 定义的变量的作用域是函数作用域(补充: var 声明的变量具有声明提升。)
  var goodsDetail = goodsData.goodsDetail;
  //获取商品基本信息的容器元素
  //  声明一个变量,变量的作用域范围=获取文本翁电脑中 root下面basic-info-section类名的元素.
  //document.querySelector 获取文档中的元素
  var goodsDetailContainer = document.querySelector('#root #content .container .goods-intro-section .right .basic-info-section')
  //商品字符串
  // JavaScript 中,使用字符串连接有 几 种方式:连接符(+)、反引号(`)、join()、concat()。
  var goodsStr = `<!-- 商品标题 -->
                  <h3>` + goodsDetail.title + `</h3>
                  <!-- 优惠提示 -->
                  <p>` + goodsDetail.recommend + `</p>
                  <!-- 价格与促销 -->
                  <div class="price-sale-section">
                    <!-- 价格 -->
                    <div class="price-section">
                      <!-- 属性 -->
                      <div class="attr">价&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;格</div>
                      <!-- 价格 -->
                      <div class="value">
                        <span>¥</span>
                        <span>${goodsDetail.price}</span>
                        <span>降价通知</span>
                      </div>
                      <!-- 评价数量 -->
                      <div class="eval-total">
                        累计评价 ${goodsDetail.evaluateNum}
                      </div>
                    </div>
                    <!-- 促销 -->
                    <div class="sale-section">
                      <div class="attr">
                        促&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;销
                      </div>
                      <div class="value">
                        <span>${goodsDetail.promoteSales.type}</span> ${goodsDetail.promoteSales.content}
                      </div>
                    </div>
                  </div>
                  <!-- 支持 -->
                  <div class="support">
                    <div class="attr">
                      支&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;持
                    </div>
                    <div class="value">
                      ${goodsDetail.support}
                    </div>
                  </div>
                  <!-- 地址 -->
                  <div class="address">
                    <div class="attr">
                      配 送 至
                    </div>
                    <div class="value">
                      ${goodsDetail.address}
                    </div>
                  </div>`; // 声明字符串的另外一种语法  `djslfajlewaof`
  //设置容器的 HTML 内容
  goodsDetailContainer.innerHTML = goodsStr;
}
setGoodsBasicInfo();

//渲染商品属性相关的结构
function renderGoodsAttrs() {
  //获取商品属性的数据
  var data = goodsData.goodsDetail.crumbData;
  //商品属性容器
  var goodsAttrContainer = document.querySelector('#root #content .container .goods-intro-section .right .choose-section');
  //遍历 data 数组
  data.forEach(function (item, index) {
    //创建 dl 元素
    var dl = document.createElement('dl');
    //为 dl 设置下标
    dl.index = index;
    //创建 dt 元素
    var dt = document.createElement('dt');
    //设置 dt 的文本内容
    //“innerHTML”:获取的是该标签的所有内容,包括其子标签,
    //“innerText”和“textContent”是无法把html标签转化成标签的,而是当做纯文本内容显示出来,而“innerHTML”则可把内容中的标签转化成html标签.
    dt.innerHTML = item.title;
    //组装
    //ppendChild() 方法可向节点的子节点列表的末尾添加新的子节点。dl的子节点添加dt节点
    dl.appendChild(dt);
    //循环创建 dd
    //forEach内联回调函数 forEach(function(value) { /* … */ })
    item.data.forEach(function (value, index) {
      //创建 dd 元素
      var dd = document.createElement('dd');
      //判断是否为第一个元素
      if (index === 0) {
        dd.classList.add('active');
      }
      //设置 dd 元素的文本
      dd.innerHTML = value.type;
      //将属性存储到标签身上
      dd.setAttribute('change', value.changePrice);
      //将 dd 插入到 dl 中
      dl.appendChild(dd);
      //为 dd 元素绑定单击事件
      dd.onclick = function () {
        //同辈元素移除 active 类 
        this.parentNode.querySelectorAll('dd').forEach(function (v) {
          v.classList.remove('active');
        });
        //自身添加 active
        this.classList.add('active');
      }
    });
    //将 dl 插入到容器中
    goodsAttrContainer.appendChild(dl);
  })
}
renderGoodsAttrs();

//点击创建属性标签
function handleGoodsAttrTag() {
  //获取 choosed-section 元素
  var choosedSection = document.querySelector('#root #content .container .goods-intro-section .right .choosed-section');
  //获取所有的 dd
  var dds = document.querySelectorAll('dd');
  //获取商品属性
  var data = goodsData.goodsDetail.crumbData;
  //[undefined, undefined, undefined, undefined];
  //声明一个数组
  var arr = new Array(data.length);
  //绑定单击事件
  dds.forEach(function (item) {
    item.addEventListener('click', function () {
      //获取当前行在同辈中的下标
      var index = this.parentNode.index;
      //为数组中添加元素
      arr[index] = this.innerHTML;

      //清空原来的 mark 元素
      choosedSection.innerHTML = '';
      //遍历 arr
      arr.forEach(function (item, i) {
        //判断是否为 undefined
        if (item === undefined) return;
        //创建 mark 元素
        var mark = document.createElement('div');
        //为 mark 创建下标属性
        mark.dataset.index = i;
        mark.classList.add('mark');
        //创建
        var span1 = document.createElement('span');
        //设置第一个 span 的文本
        span1.innerHTML = item;
        var span2 = document.createElement('span');
        //设置第二个 span 的文本 X
        span2.innerHTML = 'X';
        //为 span2 元素绑定单击事件
        span2.onclick = function () {
          //删除当前的 mark 元素
          // this.parentNode.removeChild(this);
          this.parentNode.remove();
          //
          //获取当前标签对应的下标
          var i = this.parentNode.dataset.index;
          //删除数组中的元素的值
          arr[i] = undefined;
          //获取 dl 
          var dls = document.querySelectorAll('#root #content .container .goods-intro-section .right .choose-section dl');
          //清除同辈元素的 active
          dls[i].querySelectorAll('dd').forEach(function (item) {
            item.classList.remove('active');
          })
          //删除完成之后 要将对应行的选中状态
          //querySelectorAll返回一个静态的NodeList(深克隆),静态:是指选出的所有元素的数组,不会随着文档操作而改变
          dls[i].querySelectorAll('dd')[0].classList.add('active');
        }
        //组装
        mark.appendChild(span1);
        mark.appendChild(span2);
        //将 mark 元素插入到 choosed-section
        //appendChild插入节点
        choosedSection.appendChild(mark);
      });
    });
  });


}
handleGoodsAttrTag();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值