简单的大屏适配
无需特定编写rem单位,也不需要考虑单位使用失误导致适配不完全,只需导入一个js文件,即可实现大屏适配,效果如下
如何使用
使用 mixins: [ drawMixin ]实现
index.vue
<div id="index" ref="appRef"></div>
<script>
import drawMixin from "@/utils/drawMixin";
export default {
mixins: [ drawMixin ],
data(){return {}}
}
<style>
#app {
width: 100vw;
height: 100vh;
background-color: #091520;
overflow: hidden;
}
#index {
color: #d3d6dd;
width: 1920px;
height: 1080px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform-origin: left top;
}
</style>
drawMixin.js
// 屏幕适配 mixin 函数
// * 默认缩放值
const scale = {
width: '1',
height: '1',
}
// * 设计稿尺寸(px)
const baseWidth = 1920
const baseHeight = 1080
// * 需保持的比例(默认1.77778)
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
export default {
data() {
return {
// * 定时函数
drawTiming: null
}
},
mounted () {
this.calcRate()
window.addEventListener('resize', this.resize)
},
beforeDestroy () {
window.removeEventListener('resize', this.resize)
},
methods: {
calcRate () {
const appRef = this.$refs["appRef"]
if (!appRef) return
// 当前宽高比
const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))
if (appRef) {
if (currentRate > baseProportion) {
// 表示更宽
scale.width = ((window.innerHeight * baseProportion) / baseWidth).toFixed(5)
scale.height = (window.innerHeight / baseHeight).toFixed(5)
appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
} else {
// 表示更高
scale.height = ((window.innerWidth / baseProportion) / baseHeight).toFixed(5)
scale.width = (window.innerWidth / baseWidth).toFixed(5)
appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
}
}
},
resize () {
clearTimeout(this.drawTiming)
this.drawTiming = setTimeout(() => {
this.calcRate()
}, 200)
}
},
}
关键在scale的使用
scale就是拿出 当前的电脑屏幕宽度像素除以当前屏幕高度像素 去和我们的设计稿宽度像素除以设计稿高度做一个比较。
当前屏幕比例<设计稿比例。那么我们需要缩放的比例就是屏幕宽度除以设计稿宽度
当前屏幕比例>设计稿比例。那么我们需要缩放的比例就是屏幕高度除以设计稿高度
排名滚动
安装
npm install vue-seamless-scroll --save
main.js
import scroll from 'vue-seamless-scroll'
Vue.use(scroll)
index.vue
<TableCarousel :rollTitle="sdTitle" :rollList="sdList" />
import TableCarousel from "@/components/starMap/TableCarousel.vue";
export default {
data(){
sdTitle: ["头像", "姓名", "性别", "年龄", "执法证号", "学历", "是否在编"],
sdList: [],
}
}
TableCarousel.vue
<template>
<div class="tableCarousel">
<div class="rollTitle">
<span v-for="item in rollTitle" :key="item.id">
{{ item }}
</span>
</div>
<div class="rollContent">
<vue-seamless-scroll
:data="rollList"
class="seamless-warp"
:class-option="classOption"
>
<div class="row" v-for="(item, index) in rollList" :key="item.ssbmid">
<span :class="[index < 3 ? 'orange' : 'blue', 'orderNum']">{{
index + 1
}}</span>
<span>{{item.name}}</span>
<span>{{item.field2}}</span>
<span>{{item.field3}}</span>
<span>{{item.field4}}</span>
<span>{{item.field5}}</span>
</div>
</vue-seamless-scroll>
</div>
</div>
</template>
<script>
export default {
props: ["rollTitle","rollList"],
data() {
return {
};
},
computed: {
classOption() {
return {
step: 1, // 数值越大速度滚动越快
limitMoveNum: 4, // 开始无缝滚动的数据量 this.dataList.length
hoverStop: true, // 是否开启鼠标悬停stop
direction: 1, // 0向下 1向上 2向左 3向右
openWatch: true, // 开启数据实时监控刷新dom
singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
waitTime: 1000, // 单步运动停止的时间(默认值1000ms)
autoPlay: true,
};
},
},
watch: {},
created() {},
mounted() {},
methods: {},
};
</script>
<style lang='scss' scoped>
.tableCarousel {
margin-bottom: 30px;
.orange {
color: #eda44e;
}
.blue {
color: #65b8f8;
}
.orderNum {
font-weight: 600;
}
.rollTitle {
background: #1f5384;
font-weight: 600;
position: relative;
width: 100%;
display: flex;
text-align: center;
height: 40px;
line-height: 40px;
span {
flex: 2;
}
span:nth-of-type(1) {
width: 40px;
}
span:nth-of-type(2) {
flex: 6;
}
}
.rollContent {
height: 200px;
overflow: hidden;
.row {
display: flex;
text-align: center;
height: 40px;
line-height: 40px;
span {
flex: 2;
}
span:nth-of-type(1) {
width: 40px;
}
span:nth-of-type(2) {
flex: 6;
}
}
.row:nth-child(odd) {
background: #294358;
}
}
.risk {
display: flex;
margin-top: 20px;
.circleBox {
text-align: center;
flex: 1;
.circle {
width: 88px;
height: 88px;
border: 2px solid #65b8f8;
border-radius: 50%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin: 0 auto;
margin-bottom: 20px;
span:nth-of-type(1) {
font-size: 28px;
}
span:nth-of-type(2) {
color: #838d91;
}
}
}
}
}
</style>
动态数字
使用
index.vue
<NumsRoll
:countEnterNum="totalCase"
unitVal="件"
:numberProp="{
width: '26px',
height: '30px',
'font-size': '22px',
'margin-right': '4px',
}"
/>
NumsRoll.vue
<template>
<div class="centerContent">
<!-- 数字滚动 -->
<div class="chartNum">
<div class="box-item">
<li
:class="{ 'number-item': !isNaN(item), 'mark-item': isNaN(item)}"
:style="!isNaN(item)?numberProp:''"
v-for="(item, index) in orderNum"
:key="index"
>
<span v-if="formatNumber(item)">
<i ref="numberItem">0123456789</i>
</span>
<span class="comma" v-else>{{ item }}</span>
</li>
</div>
<span class="totalUnit">{{ unitVal }}</span>
</div>
</div>
</template>
<script>
export default {
props: {
countEnterNum: {
type: [String, Number],
default: "000000",
},
unitVal: {
type: String,
default: "1",
},
numberProp: {
type: Object,
default:()=>{
return {}
},
},
},
data() {
return {
orderNum: ["0", "0", "0", ",", "0", "0", "0"], // 默认
};
},
components: {},
created() {},
mounted() {
this.getCountEnterNum();
},
watch: {
/* eslint-disable */
countEnterNum: {
deep: true,
handler: function (newV, oldV) {
let list = [];
const NumberList = this.formatMoney(newV).split("");
for (let i = 0; i < NumberList.length; i++) {
if (NumberList[i] == ",") {
list.push(NumberList[i]);
} else {
list.push("0");
}
}
this.orderNum = list;
this.getCountEnterNum();
},
},
/* eslint-enable */
},
methods: {
formatMoney(num) {
/* eslint-disable */
var res = num.toString().replace(/\d+/, function (n) {
// 先提取整数部分
return n.replace(/(\d)(?=(\d{3})+$)/g, function ($1) {
return $1 + ",";
});
});
return res;
/* eslint-enable */
},
// 判断是否是数值
formatNumber(val) {
/* eslint-disable */
var numReg = /^[0-9]*$/;
var numRe = new RegExp(numReg);
if (!numRe.test(val)) {
return false;
} else {
return true;
}
/* eslint-enable */
},
getCountEnterNum() {
setTimeout(() => {
this.$nextTick(() => {
this.toOrderNum(this.countEnterNum); // 这里输入数字即可调用
this.setNumberTransform();
});
}, 1000);
},
// 设置文字滚动
setNumberTransform() {
const numberItems = this.$refs.numberItem; // 拿到数字的ref,计算元素数量
const numberArr = this.orderNum.filter((item) => {
// console.log(this.formatNumber(item));
return this.formatNumber(item);
});
// 结合CSS 对数字字符进行滚动,显示总数量
/* eslint-disable */
for (let index = 0; index < numberItems.length; index++) {
const elem = numberItems[index];
elem.style.transform = `translate(-50%, -${numberArr[index] * 10}%)`;
}
/* eslint-enable */
},
// 处理总数字
toOrderNum(num) {
num = num.toString();
//总数中加入逗号
/* eslint-disable */
// num = num.slice(0, 2) + ',' + num.slice(2, 5) + ',' + num.slice(5, 8);
num = this.formatMoney(num);
/* eslint-enable */
this.orderNum = num.split(""); // 将其便变成数据,渲染至滚动数组
// }
},
},
};
</script>
<style lang="scss" scoped>
.centerContent {
// width: 100%;
display: flex;
flex-wrap: wrap;
.gmv-title {
width: 100%;
text-align: center;
margin-top: 5vh;
font-weight: bolder;
font-size: 32px;
margin-bottom: 1.8vh;
}
.chartNum {
display: flex;
align-items: center;
}
.cont {
margin: 0 0;
}
}
.box-item {
position: relative;
height: 40px;
font-size: 54px;
line-height: 41px;
text-align: center;
list-style: none;
writing-mode: vertical-lr;
text-orientation: upright;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
}
.mark-item {
width: 10px;
height: 50px;
margin-right: 8px;
line-height: 10px;
font-size: 48px;
position: relative;
& > span {
position: absolute;
width: 100%;
bottom: 10px;
writing-mode: vertical-rl;
text-orientation: upright;
}
}
.number-item {
width: 30px;
height: 43px;
font-size: 50px;
list-style: none;
margin-right: 9px;
border-radius: 4px;
color: #ffffff;
font-size: 30px;
background: #072847;
font-weight: 700;
border: 1px solid rgba(7, 91, 118, 0.96);
color: #f2dc13;
box-shadow: 1px 1px 12px 2px rgba(7, 91, 118, 0.96);
-webkit-box-shadow: 1px 1px 12px 2px rgba(7, 91, 118, 0.96);
-moz-box-shadow: 1px 1px 12px 2px rgba(7, 91, 118, 0.96);
& > span {
position: relative;
display: inline-block;
margin-right: 10px;
width: 100%;
height: 100%;
writing-mode: vertical-rl;
text-orientation: upright;
overflow: hidden;
left: -2px;
& > i {
font-style: normal;
position: absolute;
top: 0px;
left: 50%;
transform: translate(-50%, 0);
transition: transform 1s ease-in-out;
letter-spacing: 10px;
}
}
}
.number-item:last-child {
margin-right: 0;
}
.comma {
color: #ffffff;
font-size: 50px;
font-weight: 600;
}
.totalUnit {
font-size: 16px;
font-weight: normal;
// color: #2390fe;
margin-left: 10px;
margin-top: 20px;
}
</style>
粒子动画
安装
npm install vue-particles --save-dev
main.js
import VueParticles from 'vue-particles'
Vue.use(VueParticles)
index.vue
<vue-particles
color="#fff"
:particle-opacity="0.7"
:particles-number="100"
shape-type="circle"
:particle-size="4"
lines-color="#fff"
:lines-width="1"
:line-linked="true"
:line-opacity="0.5"
:lines-distance="150"
:move-speed="2"
:hover-effect="true"
hover-mode="grab"
:click-effect="true"
click-mode="push"
>
</vue-particles>
属性说明
- color: String类型。默认’#dedede’。粒子颜色。
- particleOpacity: Number类型。默认0.7。粒子透明度。
- particlesNumber: Number类型。默认80。粒子数量。
- shapeType: String类型。默认’circle’。可用的粒子外观类型有:“circle”,“edge”,“triangle”, “polygon”,“star”。
- particleSize: Number类型。默认80。单个粒子大小。
- linesColor: String类型。默认’#dedede’。线条颜色。
- linesWidth: Number类型。默认1。线条宽度。
- lineLinked: 布尔类型。默认true。连接线是否可用。
- lineOpacity: Number类型。默认0.4。线条透明度。
- linesDistance: Number类型。默认150。线条距离。
- moveSpeed: Number类型。默认3。粒子运动速度。
- hoverEffect: 布尔类型。默认true。是否有hover特效。
- hoverMode: String类型。默认true。可用的hover模式有: “grab”, “repulse”, “bubble”。
- clickEffect: 布尔类型。默认true。是否有click特效。
- clickMode: String类型。默认true。可用的click模式有: “push”, “remove”, “repulse”, “bubble”