基于vue实现探探滑动组件功能


Posted in Javascript onMay 29, 2020

前言

嗨,说起探探想必各位程序汪都不陌生(毕竟妹子很多),能在上面丝滑的翻牌子,探探的的堆叠滑动组件起到了关键的作用,下面就来看看如何用vue写一个探探的堆叠组件 ?

一. 功能分析

简单使用下探探会发现,堆叠滑动的功能很简单,用一张图概括就是:

基于vue实现探探滑动组件功能

简单归纳下里面包含的基本功能点:

  • 图片的堆叠
  • 图片第一张的滑动
  • 条件成功后的滑出,条件失败后的回弹
  • 滑出后下一张图片堆叠到顶部

体验优化

根据触摸点的不同,滑动时首图有不同角度偏移

偏移面积判定是否成功滑出

二. 具体实现

有了归纳好的功能点,我们实现组件的思路会更清晰

1. 堆叠效果

堆叠图片效果在网上有大量的实例,实现的方法大同小异,主要通过在父层设定perspective及perspective-origin,来实现子层的透视,子层设定好translate3d Z轴数值即可模拟出堆叠效果,具体代码如下

// 图片堆叠dom
 <!--opacity: 0 隐藏我们不想看到的stack-item层级-->
 <!--z-index: -1 调整stack-item层级"-->
<ul class="stack">
 <li class="stack-item" style="transform: translate3d(0px, 0px, 0px);opacity: 1;z-index: 10;"><img src="1.png" alt="01"></li>
 <li class="stack-item" style="transform: translate3d(0px, 0px, -60px);opacity: 1;z-index: 1"><img src="2.png" alt="02"></li>
 <li class="stack-item" style="transform: translate3d(0px, 0px, -120px);opacity: 1;z-index: 1"><img src="3.png" alt="03"></li>
 <li class="stack-item" style="transform: translate3d(0px, 0px, -180px);opacity: 0;z-index: -1"><img src="4.png" alt="04"></li>
 <li class="stack-item" style="transform: translate3d(0px, 0px, -180px);opacity: 0;z-index: -1"><img src="5.png" alt="05"></li>
</ul>
<style>
.stack {
  width: 100%;
  height: 100%;
  position: relative;
  perspective: 1000px; //子元素视距
  perspective-origin: 50% 150%; //子元素透视位置
  -webkit-perspective: 1000px;
  -webkit-perspective-origin: 50% 150%;
  margin: 0;
  padding: 0;
 }
 .stack-item{
  background: #fff;
  height: 100%;
  width: 100%;
  border-radius: 4px;
  text-align: center;
  overflow: hidden;
 }
 .stack-item img {
  width: 100%;
  display: block;
  pointer-events: none;
 }
</style>

上面只是一组静态代码,我们希望得到的是vue组件,所以需要先建立一个组件模板stack.vue,在模板中我们可以使用v-for,遍历出stack节点,使用:style 来修改各个item的style,代码如下

<template>
  <ul class="stack">
   <li class="stack-item" v-for="(item, index) in pages" :style="[transform(index)]">
    <img :src="item.src">
   </li>
  </ul>
</template>
<script>
export default {
 props: {
  // pages数据包含基础的图片数据
  pages: {
   type: Array,
   default: []
  }
 },
 data () {
  return {
   // basicdata数据包含组件基本数据
   basicdata: {
    currentPage: 0 // 默认首图的序列
   },
   // temporaryData数据包含组件临时数据
   temporaryData: {
    opacity: 1, // 记录opacity
    zIndex: 10, // 记录zIndex
    visible: 3 // 记录默认显示堆叠数visible
   }
  }
 },
 methods: {
  // 遍历样式
  transform (index) {
   if (index >= this.basicdata.currentPage) {
    let style = {}
    let visible = this.temporaryData.visible
    let perIndex = index - this.basicdata.currentPage
    // visible可见数量前滑块的样式
    if (index <= this.basicdata.currentPage + visible - 1) {
     style['opacity'] = '1'
     style['transform'] = 'translate3D(0,0,' + -1 * perIndex * 60 + 'px' + ')'
     style['zIndex'] = visible - index + this.basicdata.currentPage
     style['transitionTimingFunction'] = 'ease'
     style['transitionDuration'] = 300 + 'ms'
    } else {
     style['zIndex'] = '-1'
     style['transform'] = 'translate3D(0,0,' + -1 * visible * 60 + 'px' + ')'
    }
    return style
   }
  }
 }
}
</script>

关键点

style可以绑定对象的同时,也可以绑定数组和函数,这在遍历的时候很有用

最基本的dom结构已经构建完毕,下一步是让首张图片“动”起来

2. 图片滑动

图片滑动效果,在很多场景中都有出现,其原理无非是监听touchs事件,得到位移,再通过translate3D改变目标位移,因此我们要实现的步骤如下

  • 对stack进行touchs事件的绑定
  • 监听并储存手势位置变化的数值
  • 改变首图css属性中translate3D的x,y值

具体实现

在vue框架中,不建议直接操作节点,而是通过指令v-on对元素进行绑定,因此我们将绑定都写在v-for遍历里,通过index进行判断其是否是首图,再使用:style修改首页的样式,具体代码如下:

<template>
  <ul class="stack">
   <li class="stack-item" v-for="(item, index) in pages"
   :style="[transformIndex(index),transform(index)]"
   @touchstart.stop.capture="touchstart"
   @touchmove.stop.capture="touchmove"
   @touchend.stop.capture="touchend"
   @mousedown.stop.capture="touchstart"
   @mouseup.stop.capture="touchend"
   @mousemove.stop.capture="touchmove">
    <img :src="item.src">
   </li>
  </ul>
</template>
<script>
export default {
 props: {
  // pages数据包含基础的图片数据
  pages: {
   type: Array,
   default: []
  }
 },
 data () {
  return {
   // basicdata数据包含组件基本数据
   basicdata: {
    start: {}, // 记录起始位置
    end: {}, // 记录终点位置
    currentPage: 0 // 默认首图的序列
   },
   // temporaryData数据包含组件临时数据
   temporaryData: {
    poswidth: '', // 记录位移
    posheight: '', // 记录位移
    tracking: false // 是否在滑动,防止多次操作,影响体验
   }
  }
 },
 methods: {
  touchstart (e) {
   if (this.temporaryData.tracking) {
    return
   }
   // 是否为touch
   if (e.type === 'touchstart') {
    if (e.touches.length > 1) {
     this.temporaryData.tracking = false
     return
    } else {
     // 记录起始位置
     this.basicdata.start.t = new Date().getTime()
     this.basicdata.start.x = e.targetTouches[0].clientX
     this.basicdata.start.y = e.targetTouches[0].clientY
     this.basicdata.end.x = e.targetTouches[0].clientX
     this.basicdata.end.y = e.targetTouches[0].clientY
    }
   // pc操作
   } else {
    this.basicdata.start.t = new Date().getTime()
    this.basicdata.start.x = e.clientX
    this.basicdata.start.y = e.clientY
    this.basicdata.end.x = e.clientX
    this.basicdata.end.y = e.clientY
   }
   this.temporaryData.tracking = true
  },
  touchmove (e) {
   // 记录滑动位置
   if (this.temporaryData.tracking && !this.temporaryData.animation) {
    if (e.type === 'touchmove') {
     this.basicdata.end.x = e.targetTouches[0].clientX
     this.basicdata.end.y = e.targetTouches[0].clientY
    } else {
     this.basicdata.end.x = e.clientX
     this.basicdata.end.y = e.clientY
    }
    // 计算滑动值
    this.temporaryData.poswidth = this.basicdata.end.x - this.basicdata.start.x
    this.temporaryData.posheight = this.basicdata.end.y - this.basicdata.start.y
   }
  },
  touchend (e) {
   this.temporaryData.tracking = false
   // 滑动结束,触发判断
  },
  // 非首页样式切换
  transform (index) {
   if (index > this.basicdata.currentPage) {
    let style = {}
    let visible = 3
    let perIndex = index - this.basicdata.currentPage
    // visible可见数量前滑块的样式
    if (index <= this.basicdata.currentPage + visible - 1) {
     style['opacity'] = '1'
     style['transform'] = 'translate3D(0,0,' + -1 * perIndex * 60 + 'px' + ')'
     style['zIndex'] = visible - index + this.basicdata.currentPage
     style['transitionTimingFunction'] = 'ease'
     style['transitionDuration'] = 300 + 'ms'
    } else {
     style['zIndex'] = '-1'
     style['transform'] = 'translate3D(0,0,' + -1 * visible * 60 + 'px' + ')'
    }
    return style
   }
  },
  // 首页样式切换
  transformIndex (index) {
   // 处理3D效果
   if (index === this.basicdata.currentPage) {
    let style = {}
    style['transform'] = 'translate3D(' + this.temporaryData.poswidth + 'px' + ',' + this.temporaryData.posheight + 'px' + ',0px)'
    style['opacity'] = 1
    style['zIndex'] = 10
    return style
   }
  }
 }
}
</script>

3. 条件成功后的滑出,条件失败后的回弹

条件的触发判断是在touchend/mouseup后进行,在这里我们先用简单的条件进行判定,同时给予首图弹出及回弹的效果,代码如下

<template>
  <ul class="stack">
   <li class="stack-item" v-for="(item, index) in pages"
   :style="[transformIndex(index),transform(index)]"
   @touchmove.stop.capture="touchmove"
   @touchstart.stop.capture="touchstart"
   @touchend.stop.capture="touchend"
   @mousedown.stop.capture="touchstart"
   @mouseup.stop.capture="touchend"
   @mousemove.stop.capture="touchmove">
    <img :src="item.src">
   </li>
  </ul>
</template>
<script>
export default {
 props: {
   // pages数据包含基础的图片数据
  pages: {
   type: Array,
   default: []
  }
 },
 data () {
  return {
   // basicdata数据包含组件基本数据
   basicdata: {
    start: {}, // 记录起始位置
    end: {}, // 记录终点位置
    currentPage: 0 // 默认首图的序列
   },
   // temporaryData数据包含组件临时数据
   temporaryData: {
    poswidth: '', // 记录位移
    posheight: '', // 记录位移
    tracking: false, // 是否在滑动,防止多次操作,影响体验
    animation: false, // 首图是否启用动画效果,默认为否
    opacity: 1 // 记录首图透明度
   }
  }
 },
 methods: {
  touchstart (e) {
   if (this.temporaryData.tracking) {
    return
   }
   // 是否为touch
   if (e.type === 'touchstart') {
    if (e.touches.length > 1) {
     this.temporaryData.tracking = false
     return
    } else {
     // 记录起始位置
     this.basicdata.start.t = new Date().getTime()
     this.basicdata.start.x = e.targetTouches[0].clientX
     this.basicdata.start.y = e.targetTouches[0].clientY
     this.basicdata.end.x = e.targetTouches[0].clientX
     this.basicdata.end.y = e.targetTouches[0].clientY
    }
   // pc操作
   } else {
    this.basicdata.start.t = new Date().getTime()
    this.basicdata.start.x = e.clientX
    this.basicdata.start.y = e.clientY
    this.basicdata.end.x = e.clientX
    this.basicdata.end.y = e.clientY
   }
   this.temporaryData.tracking = true
   this.temporaryData.animation = false
  },
  touchmove (e) {
   // 记录滑动位置
   if (this.temporaryData.tracking && !this.temporaryData.animation) {
    if (e.type === 'touchmove') {
     this.basicdata.end.x = e.targetTouches[0].clientX
     this.basicdata.end.y = e.targetTouches[0].clientY
    } else {
     this.basicdata.end.x = e.clientX
     this.basicdata.end.y = e.clientY
    }
    // 计算滑动值
    this.temporaryData.poswidth = this.basicdata.end.x - this.basicdata.start.x
    this.temporaryData.posheight = this.basicdata.end.y - this.basicdata.start.y
   }
  },
  touchend (e) {
   this.temporaryData.tracking = false
   this.temporaryData.animation = true
   // 滑动结束,触发判断
   // 简单判断滑动宽度超出100像素时触发滑出
   if (Math.abs(this.temporaryData.poswidth) >= 100) {
    // 最终位移简单设定为x轴200像素的偏移
    let ratio = Math.abs(this.temporaryData.posheight / this.temporaryData.poswidth)
    this.temporaryData.poswidth = this.temporaryData.poswidth >= 0 ? this.temporaryData.poswidth + 200 : this.temporaryData.poswidth - 200
    this.temporaryData.posheight = this.temporaryData.posheight >= 0 ? Math.abs(this.temporaryData.poswidth * ratio) : -Math.abs(this.temporaryData.poswidth * ratio)
    this.temporaryData.opacity = 0
   // 不满足条件则滑入
   } else {
    this.temporaryData.poswidth = 0
    this.temporaryData.posheight = 0
   }
  },
  // 非首页样式切换
  transform (index) {
   if (index > this.basicdata.currentPage) {
    let style = {}
    let visible = 3
    let perIndex = index - this.basicdata.currentPage
    // visible可见数量前滑块的样式
    if (index <= this.basicdata.currentPage + visible - 1) {
     style['opacity'] = '1'
     style['transform'] = 'translate3D(0,0,' + -1 * perIndex * 60 + 'px' + ')'
     style['zIndex'] = visible - index + this.basicdata.currentPage
     style['transitionTimingFunction'] = 'ease'
     style['transitionDuration'] = 300 + 'ms'
    } else {
     style['zIndex'] = '-1'
     style['transform'] = 'translate3D(0,0,' + -1 * visible * 60 + 'px' + ')'
    }
    return style
   }
  },
  // 首页样式切换
  transformIndex (index) {
   // 处理3D效果
   if (index === this.basicdata.currentPage) {
    let style = {}
    style['transform'] = 'translate3D(' + this.temporaryData.poswidth + 'px' + ',' + this.temporaryData.posheight + 'px' + ',0px)'
    style['opacity'] = this.temporaryData.opacity
    style['zIndex'] = 10
    if (this.temporaryData.animation) {
     style['transitionTimingFunction'] = 'ease'
     style['transitionDuration'] = 300 + 'ms'
    }
    return style
   }
  }
 }
}
</script>

4. 滑出后下一张图片堆叠到顶部

重新堆叠是组件最后一个功能,同时也是最重要和复杂的功能。在我们的代码里,stack-item的排序依赖绑定:style的transformIndex和transform函数,函数里判定的条件是currentPage,那是不是改变currentPage,让其+1,即可完成重新堆叠呢?

答案没有那么简单,因为我们滑出是动画效果,会进行300ms的时间,而currentPage变化引起的重排,会立即变化,打断动画的进行。因此我们需要先修改transform函数的排序条件,后改变currentPage。

具体实现

  • 修改transform函数排序条件
  • 让currentPage+1
  • 添加onTransitionEnd事件,在滑出结束后,重新放置stack列表中

代码如下:

<template>
  <ul class="stack">
   <li class="stack-item" v-for="(item, index) in pages"
   :style="[transformIndex(index),transform(index)]"
   @touchmove.stop.capture="touchmove"
   @touchstart.stop.capture="touchstart"
   @touchend.stop.capture="touchend"
   @mousedown.stop.capture="touchstart"
   @mouseup.stop.capture="touchend"
   @mousemove.stop.capture="touchmove"
   @webkit-transition-end="onTransitionEnd"
   @transitionend="onTransitionEnd"
   >
    <img :src="item.src">
   </li>
  </ul>
</template>
<script>
export default {
 props: {
  // pages数据包含基础的图片数据
  pages: {
   type: Array,
   default: []
  }
 },
 data () {
  return {
   // basicdata数据包含组件基本数据
   basicdata: {
    start: {}, // 记录起始位置
    end: {}, // 记录终点位置
    currentPage: 0 // 默认首图的序列
   },
   // temporaryData数据包含组件临时数据
   temporaryData: {
    poswidth: '', // 记录位移
    posheight: '', // 记录位移
    lastPosWidth: '', // 记录上次最终位移
    lastPosHeight: '', // 记录上次最终位移
    tracking: false, // 是否在滑动,防止多次操作,影响体验
    animation: false, // 首图是否启用动画效果,默认为否
    opacity: 1, // 记录首图透明度
    swipe: false // onTransition判定条件
   }
  }
 },
 methods: {
  touchstart (e) {
   if (this.temporaryData.tracking) {
    return
   }
   // 是否为touch
   if (e.type === 'touchstart') {
    if (e.touches.length > 1) {
     this.temporaryData.tracking = false
     return
    } else {
     // 记录起始位置
     this.basicdata.start.t = new Date().getTime()
     this.basicdata.start.x = e.targetTouches[0].clientX
     this.basicdata.start.y = e.targetTouches[0].clientY
     this.basicdata.end.x = e.targetTouches[0].clientX
     this.basicdata.end.y = e.targetTouches[0].clientY
    }
   // pc操作
   } else {
    this.basicdata.start.t = new Date().getTime()
    this.basicdata.start.x = e.clientX
    this.basicdata.start.y = e.clientY
    this.basicdata.end.x = e.clientX
    this.basicdata.end.y = e.clientY
   }
   this.temporaryData.tracking = true
   this.temporaryData.animation = false
  },
  touchmove (e) {
   // 记录滑动位置
   if (this.temporaryData.tracking && !this.temporaryData.animation) {
    if (e.type === 'touchmove') {
     this.basicdata.end.x = e.targetTouches[0].clientX
     this.basicdata.end.y = e.targetTouches[0].clientY
    } else {
     this.basicdata.end.x = e.clientX
     this.basicdata.end.y = e.clientY
    }
    // 计算滑动值
    this.temporaryData.poswidth = this.basicdata.end.x - this.basicdata.start.x
    this.temporaryData.posheight = this.basicdata.end.y - this.basicdata.start.y
   }
  },
  touchend (e) {
   this.temporaryData.tracking = false
   this.temporaryData.animation = true
   // 滑动结束,触发判断
   // 简单判断滑动宽度超出100像素时触发滑出
   if (Math.abs(this.temporaryData.poswidth) >= 100) {
    // 最终位移简单设定为x轴200像素的偏移
    let ratio = Math.abs(this.temporaryData.posheight / this.temporaryData.poswidth)
    this.temporaryData.poswidth = this.temporaryData.poswidth >= 0 ? this.temporaryData.poswidth + 200 : this.temporaryData.poswidth - 200
    this.temporaryData.posheight = this.temporaryData.posheight >= 0 ? Math.abs(this.temporaryData.poswidth * ratio) : -Math.abs(this.temporaryData.poswidth * ratio)
    this.temporaryData.opacity = 0
    this.temporaryData.swipe = true
    // 记录最终滑动距离
    this.temporaryData.lastPosWidth = this.temporaryData.poswidth
    this.temporaryData.lastPosHeight = this.temporaryData.posheight
    // currentPage+1 引发排序变化
    this.basicdata.currentPage += 1
    // currentPage切换,整体dom进行变化,把第一层滑动置零
    this.$nextTick(() => {
     this.temporaryData.poswidth = 0
     this.temporaryData.posheight = 0
     this.temporaryData.opacity = 1
    })
   // 不满足条件则滑入
   } else {
    this.temporaryData.poswidth = 0
    this.temporaryData.posheight = 0
    this.temporaryData.swipe = false
   }
  },
  onTransitionEnd (index) {
   // dom发生变化后,正在执行的动画滑动序列已经变为上一层
   if (this.temporaryData.swipe && index === this.basicdata.currentPage - 1) {
    this.temporaryData.animation = true
    this.temporaryData.lastPosWidth = 0
    this.temporaryData.lastPosHeight = 0
    this.temporaryData.swipe = false
   }
  },
  // 非首页样式切换
  transform (index) {
   if (index > this.basicdata.currentPage) {
    let style = {}
    let visible = 3
    let perIndex = index - this.basicdata.currentPage
    // visible可见数量前滑块的样式
    if (index <= this.basicdata.currentPage + visible - 1) {
     style['opacity'] = '1'
     style['transform'] = 'translate3D(0,0,' + -1 * perIndex * 60 + 'px' + ')'
     style['zIndex'] = visible - index + this.basicdata.currentPage
     style['transitionTimingFunction'] = 'ease'
     style['transitionDuration'] = 300 + 'ms'
    } else {
     style['zIndex'] = '-1'
     style['transform'] = 'translate3D(0,0,' + -1 * visible * 60 + 'px' + ')'
    }
    return style
   // 已滑动模块释放后
   } else if (index === this.basicdata.currentPage - 1) {
    let style = {}
    // 继续执行动画
    style['transform'] = 'translate3D(' + this.temporaryData.lastPosWidth + 'px' + ',' + this.temporaryData.lastPosHeight + 'px' + ',0px)'
    style['opacity'] = '0'
    style['zIndex'] = '-1'
    style['transitionTimingFunction'] = 'ease'
    style['transitionDuration'] = 300 + 'ms'
    return style
   }
  },
  // 首页样式切换
  transformIndex (index) {
   // 处理3D效果
   if (index === this.basicdata.currentPage) {
    let style = {}
    style['transform'] = 'translate3D(' + this.temporaryData.poswidth + 'px' + ',' + this.temporaryData.posheight + 'px' + ',0px)'
    style['opacity'] = this.temporaryData.opacity
    style['zIndex'] = 10
    if (this.temporaryData.animation) {
     style['transitionTimingFunction'] = 'ease'
     style['transitionDuration'] = 300 + 'ms'
    }
    return style
   }
  }
 }
}
</script>

ok~ 完成了上面的四步,堆叠组件的基本功能就已经实现,快来看看效果吧

基于vue实现探探滑动组件功能

堆叠滑动效果已经出来了,但是探探在体验上,还增加了触碰角度偏移,以及判定滑出面积比例

角度偏移的原理,是在用户每次进行touch时,记录用户触碰位置,计算出最大的偏移角度,在滑动出现位移时,线性增加角度以至最大的偏移角度。

使用在stack中具体要做的是:

touchmove中计算出所需角度和方向

touchend及onTransitionEnd中将角度至零

判定滑出面积比例,主要通过偏移量计算出偏移面积,从而得到面积比例,完成判断

完整的代码和demo可以在github上查看源码,这里就不贴出来了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
用javascript实现分割提取页面所需内容
May 09 Javascript
jQuery支持动态参数将函数绑定到事件上的方法
Mar 17 Javascript
js实现模拟计算器退格键删除文字效果的方法
May 07 Javascript
JS实现的自定义水平滚动字体插件完整实例
Jun 17 Javascript
jquery 正整数数字校验正则表达式
Jan 10 Javascript
动态加载css方法实现和深入解析
Jan 18 Javascript
JS中使用 after 伪类清除浮动实例
Mar 01 Javascript
Angular2.js实现表单验证详解
Jun 23 Javascript
快速将Vue项目升级到webpack3的方法步骤
Sep 14 Javascript
解决修复npm安装全局模块权限的问题
May 17 Javascript
React 组件间的通信示例
Jun 14 Javascript
Vue.js点击切换按钮改变内容的实例讲解
Aug 22 Javascript
JS实现前端路由功能示例【原生路由】
May 29 #Javascript
JavaScript如何实现图片处理与合成
May 29 #Javascript
jQuery+css实现的点击图片放大缩小预览功能示例【图片预览 查看大图】
May 29 #jQuery
JavaScript基于用户照片姓名生成海报
May 29 #Javascript
微信小程序实现上拉加载功能示例【加载更多数据/触底加载/点击加载更多数据】
May 29 #Javascript
JavaScript设计模式之策略模式实现原理详解
May 29 #Javascript
JavaScript隐式类型转换代码实例
May 29 #Javascript
You might like
PHP技术开发技巧分享
2010/03/23 PHP
php5 apache 2.2 webservice 创建与配置(java)
2011/01/27 PHP
把1316这个数表示成两个数的和,其中一个为13的倍数,另一个是11的倍数,求这两个数。
2011/06/24 PHP
PHP制作3D扇形统计图以及对图片进行缩放操作实例
2014/10/23 PHP
php判断文件上传类型及过滤不安全数据的方法
2014/12/17 PHP
PHP 获取 ping 时间的实现方法
2017/09/29 PHP
微信公众平台开发教程⑤ 微信扫码支付模式介绍
2019/04/10 PHP
Thinkphp5框架简单实现钩子(Hook)行为的方法示例
2019/09/03 PHP
PHP var关键字相关原理及使用实例解析
2020/07/11 PHP
js的写法基础分析
2011/01/17 Javascript
Javascript面向对象编程(二) 构造函数的继承
2011/08/28 Javascript
基于jquery点击自以外任意处,关闭自身的代码
2012/02/10 Javascript
Javascript模块化编程(三)require.js的用法及功能介绍
2013/01/17 Javascript
使用jQuery不判断浏览器高度解决iframe自适应高度问题
2014/12/16 Javascript
js实现类似MSN提示的页面效果代码分享
2015/08/24 Javascript
js当前页面登录注册框,固定div,底层阴影的实例代码
2016/10/04 Javascript
headjs实现网站并行加载但顺序执行JS
2016/11/29 Javascript
ES6学习教程之对象字面量详解
2017/10/09 Javascript
浅谈es6 javascript的map数据结构
2017/12/14 Javascript
微信小程序地图导航功能实现完整源代码附效果图(推荐)
2019/04/28 Javascript
vue不操作dom实现图片轮播的示例代码
2019/12/18 Javascript
浅谈vue项目,访问路径#号的问题
2020/08/14 Javascript
[01:51]2014DOTA2西雅图邀请赛 MVP 外卡赛black场间采访
2014/07/09 DOTA
[02:51]DOTA2 Supermajor小组分组对阵抽签仪式
2018/06/01 DOTA
Python最基本的数据类型以及对元组的介绍
2015/04/14 Python
Python实现螺旋矩阵的填充算法示例
2017/12/28 Python
python查看列的唯一值方法
2018/07/17 Python
jupyter notebook 添加kernel permission denied的操作
2020/04/21 Python
Python+PyQt5实现灭霸响指功能
2020/05/25 Python
解决pytorch 数据类型报错的问题
2021/03/03 Python
eDreams葡萄牙:全球最大的在线旅行社之一
2019/04/15 全球购物
第二批党的群众路线教育实践活动总结报告
2014/10/30 职场文书
感恩母亲节活动总结
2015/02/10 职场文书
新闻稿件写作技巧
2015/07/18 职场文书
小学校本教研总结
2015/08/13 职场文书
如何利用map实现Nginx允许多个域名跨域
2021/03/31 Servers