南通网站建设_营销型企业网站制作_专业网页定制开发-网络推广公司
南通,简称“通”,别称静海、崇州、崇川、紫琅,古称通州,江苏省地级市,长江三角洲中心区27城之一 [1] ,国务院批复确定的中国长三角北翼经济中心、现代化港口城市 [2] 。地处中国华东地区、江苏东南部,东抵黄海、南濒长江 [5] ,是扬子江城市群的重要组成部分、上海大都市圈北翼门户城市、中国首批对外开放的14个沿海城市之一 [6] ,集“黄金海岸”与“黄金水道”优势于一身,拥有长江岸线226千米,“据江海之会、扼南北之喉 [7] ”,被誉为“北上海”。截至2020年12月,南通市辖3个区、1个县、代管3个县级市,总面积8001平方千米。 [4] 2020年,南通市实现地区生产总值10036.3亿元。 [243]
南通是国家历史文化名城,自后周显德三年(956年)建城至今已有一千多年历史。在中国近代文化科教史上,南通创办第一所师范学校、第一座民间博物苑、第一所纺织学校、第一所刺绣学校、第一所戏剧学校、第一所中国人办的盲哑学校和第一所气象站等“七个第一”,被称为“中国近代第一城”。 [8]
南通是“精神文明南通现象”的发源地 [9-10] ,是中国、江苏省重大精神文明先进典型最多的地区之一 [9] ,连续五次被评为全国文明城市 [242] ,并先后入选国家智慧城市试点 [11] 、宽带中国示范城市 [12] 。
截至2014年,南通人口平均预期寿命达80.71岁,百岁寿星多达1031位。 [13] 2014年5月,南通被国际自然医学会、世界长寿乡认证委员会授予全球首个“世界长寿之都”。 [14-15] 2018年10月,获评首届健康中国年度标志城市。 [16] 2018年中国百强城市排行榜中,位列22位。 [17]
其实写这个组件之前是因为在使用某UI组件库的loadmore时踩了不少坑,到最后还是会出现各种问题,至此就放弃了踩坑,决定自己封装一个类似组件。不敢说自己写的没问题,但是目前运用到项目中,各手机设备上都能正常操作,所以今天把自己封装的这个组件分享出来,如果大家在使用时遇到问题可以随时向我反馈,我这边也会第一时间去修复。废话就不多说了,这里我先贴出组件代码
<style lang="scss" scoped>.loadmore {
overflow-y: auto;
position: fixed;
height: 100%;
width: 100%;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 10;
user-select: none;
.loadmore-content {
backface-visibility: hidden;
transform-style: preserve-3d;
background: #f5f5f5;
position: relative;
}
.loading, .pull, .drop {
position: fixed;
width: 100%;
left: 0;
right: 0;
text-align: center;
line-height: 40px;
z-index: -1;
font-size: 14px;
}
.top-loading-text {
top: -40px;
}
.bottom-loading-text {
bottom: 0px;
}
}</style><template>
<section class="loadmore" ref="loadmore">
<section class="loadmore-content" ref="list" :style="style">
<section class="loading top-loading-text" v-if="topLoading" v-html="topLoadingText"></section>
<section class="pull" :style="{top: `-40px`}" v-if="topPull" v-html="topPullText"></section>
<section class="drop" :style="{top: `-40px`}" v-if="topDrop" v-html="topDropText"></section>
<slot></slot>
</section>
<section v-if="bottomDrop" class="drop" :style="{bottom: `${0}px`}" v-html="bottomDropText"></section>
<section v-if="bottomPull" class="pull" :style="{bottom: `${0}px`}" v-html="bottomPullText"></section>
<section v-if="bottomLoading" class="loading bottom-loading-text" v-html="bottomLoadingText"></section>
</section></template><script>export default { name: 'loadmore',
data () { return { style: {}, direction: '', touchstart: 'touchstart', touchmove: 'touchmove', touchend: 'touchend', loadmore: null, list: null, dY: 0, mY: 0, bottomLoading: false, bottomPull: false, bottomDrop: false, topLoading: false, topPull: false, topDrop: false, topOn: false, bottomOn: false, scrollOn: true
}
}, computed: {
isMobile () { return /Mobile/ig.test(window.navigator.userAgent)
}
}, props: { //提前触发到底事件的高度,默认到底触发(手机端建议默认此参数)
earlyTrigger: { type: Number,
validater (v) { return v >= 0
}, default () { return 0
}
}, //手指移动距离和组件滚动之间的比率
distanceIndex: { type: Number, default () { return 3
}
}, //更新完,设置此参数不再触发 topMethod 方法
topAllLoaded: { type: Boolean, default () { return true
}
}, //下拉刷新的高度
topDistance: { type: Number,
validater (v) { return v > 40
}, default () { return 60
}
}, //上拉加载的高度
bottomDistance: { type: Number,
validater (v) { return v > 40
}, default () { return 60
}
}, //加载完,设置此参数不再触发 bottomMethod 方法
bottomAllLoaded: { type: Boolean, default () { return false
}
}, //是否自动填充内容
autoFill: { type: Boolean, default () { return true
}
}, //下拉刷新提示内容,可传入HTML
topPullText: { type: String, default () { return '↓ 下拉刷新'
}
}, //下拉刷新到达指定高度提示内容,可传入HTML
topDropText: { type: String, default () { return '释放更新'
}
}, //下拉更新中提示内容,可传入HTML
topLoadingText: { tye: String, default () { return '更新中...'
}
}, //上拉加载提示内容,可传入HTML
bottomPullText: { type: String, default () { return '↑ 上拉加载'
}
}, //上拉加载到达指定高度提示内容,可传入HTML
bottomDropText: { type: String, default () { return '释放更新'
}
}, //上拉加载中提示内容,可传入HTML
bottomLoadingText: { type: String, default () { return '加载中...'
}
}, //下拉刷新,触发方法
topMethod: { type: Function, default: () => {}
}, //上拉加载,触发方法
bottomMethod: { type: Function, default: () => {}
}
}, methods: { //偏移元素
deviationElement (distance, isAnimation) { this.style = isAnimation && { transform: `translate3d(0, ${ distance }px, 0)`, transition: 'transform .3s ease'
} || { transform: `translate3d(0, ${ distance }px, 0)`
}
}, //底部加载完成后调用,关闭加载状态
onBottomLoadedSuccess () { this.bottomLoading = this.bottomDrop = this.bottomPull = false
this.deviationElement(0, true)
}, //顶部加载完成后调用,关闭加载状态
onTopLoadedSuccess () { this.topLoading = this.topDrop = this.topPull = false
this.deviationElement(0, true)
}, //手指(鼠标按键)抬起
removeEv () { //上拉释放
if (this.direction == 'up') { if (this.bottomDrop) { this.deviationElement(-40, true)
setTimeout(() => { this.bottomDrop = this.bottomPull = false
this.bottomLoading = true
this.bottomMethod()
}, 300)
} else { this.deviationElement(0, true)
setTimeout(() => { this.bottomLoading = this.bottomDrop = this.bottomPull = false
}, 300)
}
} else if (this.direction == 'down') {//下拉释放
if (this.topDrop) { this.deviationElement(40, true)
setTimeout(() => { this.topDrop = this.topPull = false
this.topLoading = true
this.topMethod()
}, 300)
} else { this.deviationElement(0, true)
setTimeout(() => { this.topLoading = this.topDrop = this.topPull = false
}, 300)
}
} this.loadmore.removeEventListener(this.touchmove, this.moveEv) this.loadmore.removeEventListener(this.touchend, this.removeEv)
}, //手指(鼠标)按下事件
startEv (e) {
e = e || window.event this.dY = this.isMobile && e.touches[0].pageY || e.pageY this.topOn = this.bottomOn = true
this.loadmore.addEventListener(this.touchmove, this.moveEv) this.loadmore.addEventListener(this.touchend, this.removeEv)
}, //手指(鼠标按住拖动)滑动事件
moveEv (ev) {
ev = ev || window.event this.mY = this.isMobile && ev.touches[0].pageY || ev.pageY let sT = this.loadmore.scrollTop,
prevent = false,
h = this.loadmore.clientHeight - this.list.scrollHeight //下拉更新
if ((this.mY - this.dY) > 0) { this.direction = 'down'
if (sT <= 0) {
prevent = true
if (this.topOn) { this.topOn = false
this.dY = this.mY
} let top = (this.mY - this.dY) / this.distanceIndex this.deviationElement(top) if ((top > 0) && (top < this.topDistance) && !this.topAllLoaded) { this.topLoading = this.topDrop = false
this.topPull = true
} else if ((top > this.topDistance) && !this.topAllLoaded) { this.topLoading = this.topPull = false
this.topDrop = true
}
}
} else {//上拉加载
this.direction = 'up'
if (Math.abs(Math.abs(h) - sT) < 10) {
prevent = true
if (this.bottomOn) { this.bottomOn = false
this.dY = this.mY this.$emit('bottomStatusChange', '到底啦')
} let bottom = (this.mY - this.dY) / this.distanceIndex,
absBottom = Math.abs(bottom) this.deviationElement(bottom) if ((absBottom > 0) && (absBottom < this.bottomDistance) && !this.bottomAllLoaded) { this.bottomLoading = this.bottomDrop = false
this.bottomPull = true
} else if ((absBottom > this.bottomDistance) && !this.bottomAllLoaded) { this.bottomLoading = this.bottomPull = false
this.bottomDrop = true
}
}
}
prevent && ev.preventDefault()
}, //scorll 监听事件
scrollEv () { let sH = this.list.scrollHeight,
cH = this.loadmore.clientHeight,
top = this.loadmore.scrollTop if ((sH - cH - this.earlyTrigger) <= top && this.scrollOn) { this.scrollOn = false
this.$emit('bottomStatusChange', '到底啦')
}
}
},
mounted () { this.$nextTick(() => { if (!this.isMobile) { this.touchstart = 'mousedown'
this.touchmove = 'mousemove'
this.touchend = 'mouseup'
} this.loadmore = this.$refs.loadmore this.list = this.$refs.list //自动填充
if ((this.loadmore.clientHeight > this.list.scrollHeight) && this.autoFill) { this.bottomMethod(!0)
}
!this.earlyTrigger && this.loadmore.addEventListener(this.touchstart, this.startEv) this.earlyTrigger && this.loadmore.addEventListener('scroll', this.scrollEv)
})
},
deactivated () {
!this.earlyTrigger && this.loadmore.removeEventListener(this.touchstart, this.startEv) this.earlyTrigger && this.loadmore.removeEventListener('scroll', this.scrollEv)
}
}</script>
上面是这个组件的全部代码,这里不解读代码,我大概说一下实现思路:
首先我利用了addEventListener做了主要三个事件的绑定,按下事件,滑动事件,抬起事件,通过滑动事件内首先判断了用户的滑动方向,往上还是往下。往上拉的逻辑,要获取可视区高度,整个页面内容的高度,当前滚动条的位置,这样就能计算出当前用户是否滑动到了底部,计算公式:
scorllHeight-clientHeight == scrollTop
当以上条件成立,既滑动到了底部,这时就可以做相关上拉效果的逻辑。同理,向下拉逻辑,计算公式:
scrollTop <= 0
当以上条件成立,既滑动到了顶部,同样可做相关下拉效果逻辑,组件整个拉动效果都是运用的css3的动画,js计算了滑动位置,这里说一下拉动的效果逻辑,例如:当拉动到了底部,如果再往上拉,效果会给人一种好像越拉越难拉的感觉,其实这里也是运用了一个公式:
//(手指移动的ev.pageY - 手指按下的ev.pageY) / 系数(movePageY - downPageY) / coefficient
根据上方公式就能实现拉动效果,最后当抬起事件触发时即归位元素位置,触发更新事件实现加载数据的回调。上面简单的说了下实现思路,当然也可以不利用滚动条去写,全部滑动效果都可自己用计算方式实现,这里也就提一下这个,因为个人只是觉得没有这个必要去整个滑动都自己计算写,当然如果你如果非要自己做处理,可以屏蔽掉滚动条,获取滚动条位置改写成获取元素顶部距离,然后在滑动事件内加一个没有到底部或者顶部的滑动处理。
南通网站建设_营销型企业网站制作_专业网页定制开发-网络推广公司