超出部分隐藏,横向滑动的菜单栏
overflow-x: auto; //如果溢出框,则应该提供滚动机制。
white-space: nowrap; //规定段落中的文本不进行换行。
==========================================================
切换筛选菜单
筛选菜单1.png
筛选菜单2.png
<template>
<div id="sort-and-zone">
<div id="sort" @click="sortOrZone(0)"><span>{{sortSpan}}</span><div class="nav-triangle"></div></div>
<div id="zone" @click="sortOrZone(1)"><span>{{zoneSpan}}</span><div class="nav-triangle zone-triangle"></div>
</div>
<div v-show="isShadow" id="sort-and-zone-shadow" @click="hideShadow">
<div id="sort-options" v-show="isSort">
<ul class="sorts" v-for="item in sorts" :key="item.index">
<li><span>{{item.name}}</span></li>
</ul>
</div>
<div id="zone-options" v-show="!isSort">
<ul class="zones" v-for="item in zones" :key="item.index">
<li><span>{{item.name}}</span></li>
</ul>
</div>
</div>
</template>
<script>
export default {
data() {
return {
sortSpan: "最新帖子",
zoneSpan: "全部分区",
isShadow: false,
sortOrZoneFlag: -1,
isSort: true,
sorts: [
{index: 6, name: "最新帖子", param: "last"},
{index: 7, name: "最热帖子", param: "hot"},
{index: 8, name: "最热帖子", param: "hot"},
{index: 9, name: "最热帖子", param: "hot"}
],
zones: [
{index: 0, name: "全部分区", param: "all"},
{index: 1, name: "沿途风光", param: "scenery"},
{index: 2, name: "沿途风光", param: "scenery"},
{index: 3, name: "沿途风光", param: "scenery"},
{index: 4, name: "沿途风光", param: "scenery"},
{index: 5, name: "沿途风光", param: "scenery"},
{index: 15, name: "沿途风光", param: "scenery"},
{index: 25, name: "沿途风光", param: "scenery"},
{index: 35, name: "沿途风光", param: "scenery"},
{index: 45, name: "沿途风光", param: "scenery"},
{index: 55, name: "沿途风光", param: "scenery"},
{index: 65, name: "沿途风光", param: "scenery"}
]
}
},
methods: {
sortOrZone: function(flag) {
var _this = this;
if(_this.sortOrZoneFlag == -1) { //初始状态,没有展开菜单
_this.sortOrZoneFlag = flag; //记录当前菜单对应的按钮
_this.isShadow = !_this.isShadow; //展开菜单,展示相应的菜单内容
if(flag == 0) {
_this.isSort = true;
}else {
_this.isSort = false;
}
$("html").css("overflow", "hidden");//PC端这样设置可以使得页面在遮罩层出现时禁止滚动,但是移动端无效
$("body").css("overflow", "hidden");
$('#sort-and-zone-shadow').bind("touchmove",function(e){//该方法为遮罩层添加滑动时的事件
e.preventDefault();//preventDefault()取消默认事件,来达到遮罩层出现时禁止滑动的效果
});
}else if(_this.sortOrZoneFlag == flag) { //该按钮展开了菜单,现在应该收起菜单
_this.isShadow = !_this.isShadow; //收起菜单
_this.sortOrZoneFlag = -1; //回到初始状态
$("html").css("overflow", "visible");
$("body").css("overflow", "visible");
}else { //另一个按钮被点击,应保持菜单展开状态,更换相应的菜单内容
_this.sortOrZoneFlag = flag; //更改当前菜单对应的按钮
_this.isSort = !_this.isSort
$("html").css("overflow", "hidden");
$("body").css("overflow", "hidden");
$('#sort-and-zone-shadow').bind("touchmove",function(e){
e.preventDefault();
});
}
},
hideShadow: function() {
var _this = this;
_this.isShadow = false; //收起菜单
_this.sortOrZoneFlag = -1; //回到初始状态
$("html").css("overflow", "visible");
$("body").css("overflow", "visible");
}
}
}
</script>
==========================================================
类似的小标签通过给<span>添加背景颜色实现,或者给<span>添加边框样式
帖子小标签.png
==========================================================
两种盒模型的区别
1.box-sizing: content-box:
W3C标准盒模型
盒子所占空间的宽度 = content.width+padding×2+border×2+margin×2
盒子的实际宽度 = content.width+padding×2+border×2
2.box-sizing: border-box:
IE的盒模型
盒子所占空间的宽度 = content.width+margin×2
盒子的实际宽度 = content.width
3.区别:
在使用W3C标准盒模型时,定义宽度只是对content的定义,对padding、border、margin的定义是额外加上去的,它们都会改变盒子的实际大小以及所占空间。在使用IE盒模型时,定义的宽度是包含了padding和border的,对padding、border、margin的定义都不会改变盒子的实际大小,但是对margin的定义会改变盒子所占空间的大小,而对padding和border的定义不会。
==========================================================
在有遮罩层出现时,禁止对遮罩层以下的内容进行操作(PC端滚动,移动端滑动)
1.PC端
将超出的部分隐藏,设置overflow为hidden
2.移动端
阻止遮罩层的默认事件
$("遮罩层").bind("touchmove", function(e) {
e.preventDefault();
})
==========================================================
下拉刷新
jQuery插件(pulltorefresh.js)
var ptr = PullToRefresh.init({
mainElement: "选择下拉的element",
onRefresh: function() {
window.location.reload();
}
});
==========================================================
返回上一页
在index.js中使用keepAlive使组件保留状态,避免重新渲染。
在二级页面使用history.go(-1)或者history.back()来返回上一个页面。
history.go(-1)会使得要返回的页面刷新,而history.back()不会刷新。
以上为理论,下面是实际使用的结果:
我在index.js中为index.vue组件设置了
{
path: '/',
name: 'index',
component: 'index',
meta: {
keepAlive: true
}
}
之后,再使用history.back()和history.go(-1)返回index页面,index组件都没有重新渲染。而在不设
置keepAlive属性时,返回index页面,组件都重新渲染了,页面被刷新了。
==========================================================
vue组件或者元素的过渡
使用transition来实现元素或组件的过渡。
一个通用的例子,实现简单地过渡。
<transition name="fade">
<div v-show="isIsSignBoardShow" id="is-sign-board">今天已签到</div>
</transition>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 #5086A5 */ {
opacity: 0;
}
==========================================================
vue路由设置页面不刷新
在router.js中把需要缓存的页面设置为:
{
path: "/",
name: "index",
component: index,
meta: {
keepAlive: true
}
}
在App.vue中,需要缓存的页面这样写:
<keep-alive>
<router-view v-if="$route.meta.keepAlive" v-on:isMenuNeed="isMenuNeed" v-on:needReload="reload"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" v-on:isMenuNeed="isMenuNeed" v-on:needReload="reload"></router-view>
在需要返回的页面,用history.back()返回。(返回的两种方式之前写过了)
==========================================================
返回时定位到之前离开的位置
本次使用的是根据滚动条的高度来对页面进行定位。
在跳转页面的额函数中:
var scrollH = $("滚动的元素").scrollTop();//获取当前滚动条到屏幕上方的距离
sessionStorage.setItem("h", scrollH);//将当前滚动条到屏幕上方的距离存入sessionStorage
//在返回的页面中的activated函数中:(activated函数是在keep-alive 组件激活时调用的)
var h = sessionStorage.getItem("h");//从sessionStorage中取出离开时的滚动条到屏幕上方的距离
$("#test-wrap").scrollTop(h);//设置滚动条到屏幕上方的距离来定位页面位置
//在返回的页面中的created函数中:
sessionStorage.setItem("h", 0);//将sessionStorage存储的滚动条到屏幕上方的距离改为0,这样在页面刷新的时候页面就会回到最上方。
还有一种利用锚点来定位,个人感觉在本次的页面中不太好利用,因此没有使用。
==========================================================
复杂的布局和定位灵活运用position属性:
relative属性的元素初始位置是一直被占据的,而absolute属性的元素不会。
relative属性的元素定位是相对初始位置定位的,而absolute属性的元素是相对它父元素中拥有position属性的元素定位的,如果父元素中没有就相对body定位。
在复杂的布局定位中可以给父元素设置position: relative,子元素设置position: absolute,这样子元素就可以被设置到想要的想对于父元素的任意位置了。
==========================================================
下拉刷新和上滑加载更多
需要引用刷新的组件(父组件)
<template>
<v-load id="test-wrap" :on-refresh="onRefresh" :on-infinite="onInfinite" :tPage="page">//onRefresh是下拉刷新,onInfinite是上滑加载更多,可根据需求取舍。把当前的页数传到子组件。
<card v-for="card in cards" :key="card.id"></card>
</v-load>
</template>
<script>
import card from "components/card.vue";
import load from "components/load.vue";//引入组件
export default {
data() {
return {
page: 0
}
}
components: {
vLoad: load//注册组件
},
methods: {
// 下拉刷新
onRefresh(done) {
window.location.reload();
done(); //加载完成,防止重复执行
},
// 上滑加载更多
onInfinite(done) {
// window.location.reload();
var _this = this;
if(_this.page == 6) {
done();
}else {
setTimeout(function() {
_this.addMore();
_this.page += 1;
done();
}, 1000);//设置一秒钟之后是为了方便观察效果
}
}
}
}
</script>
load.vue
<template>
<div class="yo-scroll"
:class="{'down':(state===0),'up':(state==1),refresh:(state===2),touch:touching}"
@touchstart="touchStart($event)"
@touchmove="touchMove($event)"
@touchend="touchEnd($event)"
@scroll="(onInfinite || infiniteLoading) ? onScroll($event) : undefined">
<section class="inner" :style="{ transform: 'translate3d(0, ' + top + 'px, 0)' }">
<header class="pull-refresh">
<slot name="pull-refresh">
<span class="down-tip">下拉更新</span>
<span class="up-tip">松开更新</span>
<span class="refresh-tip">更新中</span>
</slot>
</header>
<slot></slot>
<footer class="load-more">
<slot name="load-more">
<span v-show="!isAll">加载中……</span>
<span v-show="isAll">加载完毕</span>
</slot>
</footer>
</section>
</div>
</template>
<script>
export default {
props: {
offset: {
type: Number,
default: 40
},
enableInfinite: {
type: Boolean,
default: true
},
enableRefresh: {
type: Boolean,
default: true
},
onRefresh: {
type: Function,
default: undefined,
required: false
},
onInfinite: {
type: Function,
default: undefined,
require: false
},
tPage: {
type: Number//接收到当前页数
}
},
data() {
return {
top: 0,
state: 0,
startY: 0,
touching: false,
infiniteLoading: false,
isAll: false
}
},
methods: {
touchStart(e) {
this.startY = e.targetTouches[0].pageY
this.startScroll = this.$el.scrollTop || 0
this.touching = true
},
touchMove(e) {
if (!this.enableRefresh || this.$el.scrollTop > 0 || !this.touching) {
return
}
let diff = e.targetTouches[0].pageY - this.startY - this.startScroll
if (diff > 0) e.preventDefault()
this.top = Math.pow(diff, 0.8) + (this.state === 2 ? this.offset : 0)
if (this.state === 2) { // in refreshing
return
}
if (this.top >= this.offset) {
this.state = 1
} else {
this.state = 0
}
},
touchEnd(e) {
if (!this.enableRefresh) return
this.touching = false
if (this.state === 2) { // in refreshing
this.state = 2
this.top = this.offset
return
}
if (this.top >= this.offset) { // do refresh
this.refresh()
} else { // cancel refresh
this.state = 0
this.top = 0
}
},
refresh() {
this.state = 2
this.top = this.offset
this.onRefresh(this.refreshDone)
},
refreshDone() {
this.state = 0
this.top = 0
},
infinite() {
this.infiniteLoading = true
this.onInfinite(this.infiniteDone)
},
infiniteDone() {
this.infiniteLoading = false
},
onScroll(e) {
if (!this.enableInfinite || this.infiniteLoading) {
return
}
let outerHeight = this.$el.clientHeight
let innerHeight = this.$el.querySelector('.inner').clientHeight
let scrollTop = this.$el.scrollTop
let ptrHeight = this.onRefresh ? this.$el.querySelector('.pull-refresh').clientHeight : 0
let infiniteHeight = this.$el.querySelector('.load-more').clientHeight
let bottom = innerHeight - outerHeight - scrollTop - ptrHeight
if (bottom < -80) this.infinite()
}
},
//当数据发生变化时执行(vue生命周期中的钩子函数updated)
updated: function() {//这里把总页数设置为6,判断是否加载完毕
if(this.tPage == 6) {
this.isAll = true;
}
}
}
</script>
<style scoped>
.yo-scroll {
position: absolute;
top: 2.5rem;
right: 0;
bottom: 0;
left: 0;
overflow: auto;
-webkit-overflow-scrolling: touch;
background-color: #f9f9f9;
}
.yo-scroll .inner {
position: absolute;
top: -2rem;
width: 100%;
margin-bottom: 55px;
margin-top: 50px;
transition-duration: 300ms;
/* background-color: rgb(228, 29, 29); */
}
.yo-scroll .pull-refresh {
position: relative;
left: 0;
top: 0;
width: 100%;
height: 2rem;
display: flex;
align-items: center;
justify-content: center;
}
.yo-scroll.touch .inner {
transition-duration: 0ms;
}
.yo-scroll.down .down-tip {
display: block;
}
.yo-scroll.up .up-tip {
display: block;
}
.yo-scroll.refresh .refresh-tip {
display: block;
}
.yo-scroll .down-tip,
.yo-scroll .refresh-tip,
.yo-scroll .up-tip {
display: none;
}
.yo-scroll .load-more {
height: 3rem;
display: flex;
align-items: center;
justify-content: center;
}
</style>
==========================================================
H5页面适配
解决div在不同尺寸屏幕上等比缩放的问题:
//将viewport的宽度设置为设备屏幕的宽度,同时不允许用户手动缩放
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
var deviceWidth = document.documentElement.clientWidth;//获取设备屏幕宽度
document.documentElement.style.fontSize = deviceWidth+"px";//设置HTML的fontSize
@function calc(\$val) {
@return $val/1080;
}
.logo {
width: calc(180rem);
}
解决1px的问题:
先将整个页面缩小dpr倍,再把跟字体大小放大dpr倍。(页面整体需要采用rem单位)
解决横屏问题:
横屏时让width=height的效果是最好的。
var deviceWidth = document.documentElement.clientWidth;
var deviceHeight = document.documentElement.clientHeight;
if(window.orientation === 90 || window.orientation == -90) {
deviceWidth = deviceHeight;
}
document.documentElement.style.fontSize = deviceWidth + 'px';
判断手机横竖屏的方法:
if (window.orientation === 180 || window.orientation === 0) {
console.log('竖屏状态!');
}
if (window.orientation === 90 || window.orientation === -90 ){
console.log('横屏状态!');
}
在同一个CSS中两套样式:
@media screen and (orientation: portrait) {
/*竖屏 css*/
}
@media screen and (orientation: landscape) {
/*横屏 css*/
}
在link中筛选样式
<!-- 竖屏 -->
<link rel="stylesheet" media="all and (orientation:portrait)" href="portrait.css">
<!-- 竖屏 -->
<link rel="stylesheet" media="all and (orientation:landscape)" href="landscape.css">
H5适配方案:
html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<!-- 正文 -->
</body>
</html>
js:
/**
* @DESCRIPTION 移动端页面适配解决方案 v1.0
* @AUTHOR Night
* @DATE 2018年08月01日
*/
(function(window, document){
var docEle = document.documentElement,
dpr = window.devicePixelRatio || 1,
scale = 1 / dpr;
var fontSizeRadio = 1, //手机字体正常比例
isLandscape = false;//是否横屏
///////////////////////// viewport start //////////////////////////////////
//设置页面缩放比例并禁止用户手动缩放
document.getElementsByName('viewport')[0].setAttribute('content','width=device-width,initial-scale='+scale+',maximum-scale='+scale+',minimum-scale='+scale+',user-scalable=no');
///////////////////////// viewport end //////////////////////////////////
//横屏状态检测
if (window.orientation === 90 || window.orientation === -90) {
isLandscape = true;
};
///////////////////// system font-size check start //////////////////////
//试探字体大小,用于检测系统字体是否正常
var setFz = '100px';
//给head增加一个隐藏元素
var headEle = document.getElementsByTagName('head')[0],
spanEle = document.createElement('span');
spanEle.style.fontSize = setFz;
spanEle.style.display = 'none';
headEle.appendChild(spanEle);
//判断元素真实的字体大小是否setFz
//如果不相等则获取真实的字体换算比例
var realFz = getComputedStyle(headEle).getPropertyValue('font-size');
if(setFz !== 'realFz'){
//去掉单位px,下面要参与计算
setFz = parseFloat(setFz);
realFz = parseFloat(realFz);
//获取字体换算比例
fontSizeRadio = setFz / realFz;
};
///////////////////// system font-size check end //////////////////////
var setBaseFontSize = function(){
var deviceWidth = docEle.clientWidth,
deviceHeight= docEle.clientHeight;
if(isLandscape){
deviceWidth = deviceHeight;
};
docEle.style.fontSize = deviceWidth * fontSizeRadio + 'px';
};
setBaseFontSize();
//页面发生变化时重置font-size
//防止多个事件重复执行,增加延迟300ms操作(防抖)
var tid;
window.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(setBaseFontSize, 300);
}, false);
window.addEventListener('pageshow', function(e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(setBaseFontSize, 300);
};
}, false);
})(window, document);
scss:
//设计稿尺寸大小,假如设计稿宽度750
$baseDesignWidth = 750;
@function calc($val){
@return $val / $baseDesignWidth;
}
//适配元素采用rem,假如设计稿中元素宽度180
.logo{
width : calc(180rem);
}
//边框采用px,假如设计稿边框宽度1px
.box{
border : 1px solid #ddd;
}
作者:vivo丨sunmaobin
链接:https://juejin.im/post/5b6503dee51d45191e0d30d2
来源:掘金
关于字体大小问题:
PC端文字的最小尺寸为12px
移动端文字最小尺寸为8px
如果文字的尺寸小于最小尺寸则显示为最小尺寸
文字大小用最好以px为单位
网友评论