一些封装的组件,基于element-ui
Dialog(弹窗)
在保留当前页面状态的情况下,告知用户并承载相关操作。
亮点功能:
- 支持自定义Dialog标题
- 支持自定义Dialog宽度
- 支持全屏显示(需打开Dialog后点击)
- Dialog高度自适应,超出屏幕高度的80%可滚动。
- 兼容各种设备。
核心代码:
<template>
<div id="popup">
<div class="warp"></div>
<div :class="{container: true, fullscreen:fullscreen}" ref="popup" :style="{width:width, 'margin-left':marginLeft}">
<div class="title">
<h3>{{title}}</h3>
<div class="titleAction">
<el-button @click="fullscreen=!fullscreen" class="fullscreenBtn" :icon="fullscreen? 'el-icon-aim' : 'el-icon-full-screen'" :title="fullscreen?'取消全屏':'全屏'"></el-button>
<el-button @click="closePopup" class="closePopup" icon="el-icon-close" title="关闭"></el-button>
</div>
</div>
<div class="content">
<slot></slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: "popup",
props: {
title: {type: String, required: true},
width: {type: String, required: false},
marginLeft: {type: String, required: false},
}
data(){
return{
currentScrollTop:'',
fullscreen: false
}
},
methods:{
closePopup(){
this.$emit("closePopup")
},
useScroll(){
setTimeout(()=>{
let popHeight = this.$refs.popup.clientHeight;
let bodyHeight = document.body.clientHeight
if(bodyHeight- popHeight < 180){
this.$refs.popup.style["overflow-y"] = "scroll";
this.$refs.popup.style.height = "80vh"
}
}, 10)
}
},
watch:{
popHeight(n, o){
console.log(n, o)
}
},
mounted() {
this.useScroll()
},
created() {
this.currentScrollTop = document.documentElement.scrollTop || document.body.scrollTop;
document.body.style.overflow='hidden';
document.body.style.position='fixed';
document.body.style.top= this.currentScrollTop+"px";
},
beforeDestroy() {
document.body.style.removeProperty('overflow');
document.body.style.removeProperty('position');
document.body.style.removeProperty('top');
document.body.scrollTop = this.currentScrollTop;
document.documentElement.scrollTop = this.currentScrollTop;
},
}
</script>
<style scoped>
#popup, .warp{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#popup{
z-index: 1000;
}
.warp{
z-index: 1001;
background-color: #000;
opacity: .6;
transition: .1s ease-out all;
}
.container{
width: 1100px;
min-height: 30vh;
background-color: #fff;
position: absolute;
left: 50%;
top: 10vh;
z-index: 1002;
margin-left: -550px;
transition: .5s ease-out all;
border-radius: 3px;
max-height: 80%;
overflow: auto;
}
.fullscreen{
width: 100%!important;
min-height: 100vh!important;
top:0!important;
height: 100%!important;
margin-left: -50% !important;
}
.container .title{
display: flex;
align-items: center;
justify-content: space-between;
height: 50px;
border-bottom: 1px solid #999;
padding: 0 15px;
position: sticky;
background: #fff;
}
.container .title h3{
color: #303133;
letter-spacing: 2px;
font-size: 19px;
}
.container .title .titleAction button{
color: #666;
font-weight: bold;
padding: 0;
font-size: 22px;
border: none;
background: none;
margin-right: 10px;
}
.container .title .titleAction button:first-child{
font-size: 20px;
}
.container .title .closePopup:hover{
color: #f00;
}
@media (max-width: 1000px) {
.container{
width: 100%;
/*top: 6vh;*/
margin-left: 0;
left: 0;
}
}
@media (max-width: 800px) {
.container{
width: 100%;
left: 10px;
overflow: auto;
}
.container .title{
width: 800px;
}
}
/*修改滚动条样式*/
.container::-webkit-scrollbar{
width:9px;
height:9px;
}
.container::-webkit-scrollbar-track{
background: rgb(239, 239, 239);
border-radius:2px;
}
.container::-webkit-scrollbar-thumb{
background: #bfbfbf;
border-radius:10px;
}
.container::-webkit-scrollbar-thumb:hover{
background: #333;
}
.container::-webkit-scrollbar-corner{
background: #179a16;
}
</style>
Attributes
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
title | Dialog的标题 | String | - | - |
width | Dialog宽度 | String | - | 1100px |
marginLeft | Dialog左侧便宜量,居中显示的时候需要是 width/2 | String | - | 550px |
Events
事件名称 | 说明 | 回调参数 |
---|---|---|
closePopup | 关闭Dialog弹窗 | - |
Slot
name | 说明 |
---|---|
匿名插槽 | Dialog核心内容插槽 |
上传文件
通过点击或拖拽上传文件,不需要重复写获取文件及验证规则
亮点功能
- 样式支持各种自定义
- 支持是否拖拽上传
- 支持多选
- 自定义提示语
- 符合实际需求的已上传文件列表显示
- 不用重复写文件验证
核心代码
<template>
<div id="uploadDoc">
<el-upload class="upload-demo" :drag="drag" action="/" :multiple="multiple" :http-request="uploadFile" :show-file-list="false">
<div v-if="uploadStyle=='default'">
<i class="el-icon-upload"></i>
<div class="el-upload__text" v-html="footnote"></div>
<div class="el-upload__text">只能上传{{backString(allowFileType)}}文件</div>
</div>
<div v-else>
<slot></slot>
</div>
</el-upload>
<div v-if="multiple">
<p class="fileList" v-for="(item,index) in fileList">
<span :title="item.name">
<i class="el-icon-document"></i>
<a href="javascript:void(0)" class="fileName">{{item.name}}</a>
</span>
<i class="close el-icon-circle-close" @click="removeFile(index)" title="删除"></i>
</p>
</div>
<div v-else>
<p class="fileList" v-if="fileList">
<span :title="fileList.name">
<i class="el-icon-document"></i>
<a href="javascript:void(0)" class="fileName">{{fileList.name}}</a>
</span>
<i class="close el-icon-circle-close" @click="removeFile(-1)" title="删除"></i>
</p>
</div>
</div>
</template>
<script>
export default {
name: "uploadFile",
props:{
uploadStyle:{
default: "default", type:String,
},
drag:{default:true, type:Boolean},
multiple:Boolean,
allowFileType:{
default: ()=>{
return ["doc", "docx", "xlsx", "zip", "rar"]
}
},
allowFileSize:{
default:5242880
},
footnote:{
default: `将审核通过文件拖到此处,或<em>点击上传</em>`
},
},
data(){
return{
fileList:[]
}
},
methods:{
backString(item){
let str = ""
item.forEach(i=>{
str = str + i + "、"
})
return str.substring(0, str.length-1)
},
uploadFile(fileObj){
let file = fileObj.file;
// 文件格式
let allowFleType = this.allowFileType;
let uploadFileType = file.name.substring(file.name.lastIndexOf('.')+1, file.name.length);
if(allowFleType.indexOf(uploadFileType) <= -1){
this.$message.error(`${uploadFileType}格式的文件不受支持,请上传:${this.allowFileType}文件`);
return false
}
// 文件大小
const fileSize = file.size;
if(fileSize > this.allowFileSize){
this.$message.error(`仅支持${this.allowFileSize/1024/1024}MB以内的文件,请重新上传`);
return false
}
if(this.multiple){
this.fileList.push({file:file, name:file.name});
}else{
this.fileList = {file:file, name:file.name};
}
// 与父组件同步上传文件信息
this.$emit("changeUploadEvent", this.fileList)
},
// 删除文件
removeFile(index){
if(index>=0){
this.fileList.splice(index, 1);
}else {
this.fileList = ''
}
// 与父组件同步上传文件信息
this.$emit("changeUploadEvent", this.fileList)
}
},
mounted() {
this.fileList = this.multiple ? [] : '';
}
}
</script>
<style scoped>
#uploadDoc{
width: 360px;
}
.fileList{
width: 96%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 3px 5px;
font-size: 14px;
}
.fileList > span {
display: flex;
align-items: center;
}
.fileList> i{
color: #999;
}
.fileName{
margin-left: 5px;
color: #606266;
letter-spacing: .5px;
overflow: hidden;
text-wrap: none;
white-space: nowrap;
text-overflow: ellipsis;
width: 320px;
display: inline-block;
}
.close{
display: none;
cursor: pointer;
font-size: 15px;
}
.close:hover{
color: #67c23a;
}
.fileList:hover {
background-color: #f6f6f6;
border-radius: 2px;
}
.close{
display: inline-block;
}
.close > span .fileName{
color: #0755a2;
}
.uploadBlock .upload-demo >>> .el-upload{
width: 100%;
height: 36px;
border: 1px solid #DCDFE6;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
border-radius: 3px;
}
.uploadBlock .upload-demo >>> .el-upload:focus{
color: #000;
}
</style>
Attributes
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
uploadStyle | 上传文件样式 | String | 任意 | default |
drag | 是否支持拖拽上传文件 | Boolean | true/false | true |
multiple | 是否支持上传多个文件(多选) | Boolean | true/false | fasle |
allowFileType | 允许上传的文件类型 | Array | - | [“doc”, “docx”, “xlsx”, “zip”, “rar”] |
allowFileSize | 允许上传的文件大小(b) | Number | - | 5242880(5Mb) |
Events
事件名称 | 说明 | 回调参数 |
---|---|---|
changeUploadEvent | 与父组件同步上传文件列表 | fileList |
Slot
name | 说明 |
---|---|
匿名插槽 | 自定义上传文件内容及样式 |
2021.1.13
回到顶部
亮点功能
自动根据终端屏幕高度及滚动高度显示隐藏回到顶部
核心代码
<template>
<button v-if="display" class="backTop" title="回到顶部" @click="back()">
<svg t="1604475304961" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2661" width="23" height="23"><path d="M533.204945 247.840277c-11.435995-13.314876-30.184888-13.314876-41.620883 0l-342.378861 399.573165c-11.435995 13.319992-6.434858 24.25659 11.19346 24.25659l128.001279 0c17.621155 0 31.995203 14.379165 31.995203 32.007483l0 256.048609c0 17.626271 14.378142 32.00339 32.001343 32.00339l320.002175 0c17.628318 0 31.996226-14.378142 31.996226-32.00339L704.394887 703.678539c0-17.629342 14.376095-32.007483 32.005437-32.007483l127.999232 0c17.621155 0 22.624339-10.937621 11.185273-24.25659L533.204945 247.840277z" p-id="2662"></path><path d="M192.395911 159.573836l640.002303 0c35.375346 0 64.00064-28.633481 64.00064-64.011897 0-35.382509-28.625294-64.011897-64.00064-64.011897l-640.002303 0c-35.371252 0-63.99757 28.629387-63.99757 64.011897C128.398341 130.940356 157.023635 159.573836 192.395911 159.573836z" p-id="2663"></path></svg>
</button>
</template>
<script>
export default {
name: "back_top",
data(){
return{
backTimer: '',
scrollHeight: 0, // 滚轮高度
clientHeight: 0, // 当前屏幕可视高度
scroll: 0, // 滚轮实时高度
display: false, // 默认不显示回到顶部
}
},
methods:{
back(){
var self = this;
this.backTimer = setInterval(function () {
this.scrollHeight = document.body.scrollTop || document.documentElement.scrollTop;
var speed = this.scrollHeight / 3;
if (document.body.scrollTop!=0) {
document.body.scrollTop -= speed;
}else {
document.documentElement.scrollTop -= speed;
}
if(this.scrollHeight === 0){
clearInterval(self.backTimer)
}
}, 30);
},
handleScroll(){
this.scroll = document.body.scrollTop || document.documentElement.scrollTop;
this.display = this.scroll >= this.clientHeight*1.2 ? true : false;
},
// 节流
throttle (fn, delay = 200) {
// 设置变量默认为true
let flag = true;
// 为了保证this指向,返回一个箭头函数
return (...args) => {
// 判断如果已经在执行就直接return
if (!flag) return;
// 否则就是没有执行,将状态赋值为false
flag = false;
// 设置定时器,设置时间
setTimeout(() => {
// 调用apply方法确保this指向问题
fn.apply(this, args);
// 最后将状态重新更改为true,以便程序下次执行
flag = true;
}, delay)
};
},
},
mounted() {
this.clientHeight = document.documentElement.clientHeight;
window.addEventListener('scroll',this.throttle(this.handleScroll))
}
}
</script>
<style scoped>
button.backTop{
display: block;
background: #fff;
border-radius: 4px;
width: 40px;
height: 40px;
box-shadow: 0 1px 3px rgba(20,20,20,.2);
position: fixed;
right: 50px;
bottom: 30px;
cursor: pointer;
border: none;
animation: buttonAnimation .3s;
transition: all linear .2s;
z-index: 99;
}
button.backTop > i{
font-size: 24px;
color: #333333;
}
@keyframes buttonAnimation
{
from {bottom: 0;}
to {bottom: 30px;}
}
</style>
无需传值;无触发其它组件事件
骨架屏
在此标签还未有内容时,先占位;即骨架屏
核心代码:
在全局配置:
// main.js
import Vue from 'vue';
Vue.directive('placeholder', {
inserted(el, binding){
let {data, config} = binding.value;
console.log(data, config)
if(data){
el.innerText = data;
return
}
// TODO:根据传的配置来显示样式,没有传则如下使用默认样式
let placeholder = "<span style='display: inline-block;width: 100%;height: 24px;background-color: #ddd;'></span>";
el.innerHTML = placeholder;
},
update(el, binding){
let {data, config} = binding.value;
if(data){
console.log(el.children[0].style)
el.children[0].style.opacity = "0";
el.children[0].style.width = "0";
el.children[0].style.height = "0";
el.children[0].style.transition = ".2s all";
setTimeout(()=>{
el.removeChild(el.children[0])
el.innerHTML = data;
}, 200)
}
}
})
在组件内配置和使用:
<template>
<div id="power">
<span v-placeholder="{data: title, config: {}}" style="color:red"></span>
</div>
</template>
<script>
export default {
name: "power",
data(){
return{
title: ""
}
},
mounted() {
setTimeout(()=>{
this.title = "123456"
}, 1000)
},
directives:{
placeholder: {
inserted(el, binding){
let {data, config} = binding.value;
console.log(data, config)
if(data){
el.innerText = data;
return
}
// TODO:根据传的配置来显示样式,没有传则如下使用默认样式
let placeholder = "<span style='display: inline-block;width: 100%;height: 24px;background-color: #ddd;'></span>";
el.innerHTML = placeholder;
},
update(el, binding){
let {data, config} = binding.value;
if(data){
console.log(el.children[0].style)
el.children[0].style.opacity = "0";
el.children[0].style.width = "0";
el.children[0].style.height = "0";
el.children[0].style.transition = ".2s all";
setTimeout(()=>{
el.removeChild(el.children[0])
el.innerHTML = data;
}, 200)
}
}
}
}
}
</script>
wait update!!