官方链接(github):
GitHub - xyxiao001/vue-cropper: A simple picture clipping plugin for vue
相关知识:
1.输出图片太模糊?可以通过enlarge属性修改图片裁剪的质量,默认值1(生成的大小25.k),值2(生成的大小900k),建议使用1.5(生成大小400k左右)。
一、安装。
npm install vue-cropper -S
以下测试代码推荐使用指定版本:
npm install vue-cropper@0.5.5 -S
如果生成的图片出现偏移多半是版本的问题。不过也有可能是样式问题,如:
img?{max-width:?100%;}
如上代码就会出现图片拉伸的情况。
二、项目使用。
针对头像裁剪:
代码:(弹窗组件时view的)
待抽离。
完全代码:
<template>
<div>
<div class="" style="display:flex;align-items:center;">
<span>
地址:<Input v-model="pageData.address" placeholder="请输入" style="width:150px;" />
</span>
<span class="ml10">
邮箱:<Input v-model="pageData.mail" placeholder="请输入" style="width:150px;" />
</span>
<!-- <span class="ml10">
角色:
<Select v-model="pageData.priority" placeholder="请选择" style="width:100px;" clearable >
<Option :value="1">用户1</Option>
<Option :value="0">用户2</Option>
</Select>
</span> -->
<Button type="primary" class="ml10" @click="seach()">查询</Button>
<Button type="success" style="margin-left:10px;" @click="clear()" ghost>重置</Button>
</div>
<div class="mt10">
<Table :columns="th" :data="td">
<template slot="address" slot-scope="{ row }">
<span v-if="!row.address" class="cloc">未绑定</span>
<span v-else>{{row.address}}</span>
</template>
<template slot="status" slot-scope="{ row }">
<span v-if="row.status===0" class="green">正常</span>
<span v-else class="red">禁用</span>
</template>
<template slot="control" slot-scope="{ row }">
<span class="active_t blue" @click="edit(row)">编辑</span>
</template>
</Table>
</div>
<div class="mt10">
<Page :total="pageData.total" :current="pageData.page" @on-change="handlePage" />
</div>
<!--添加弹窗-->
<Modal v-model="isBoxPop" :title="box.id?'编辑':'添加'" :maskClosable="false" width="600px" >
<Form :model="box" :label-width="80">
<FormItem label="头像" prop="imgUrl" :rules="[{ required: true, message: '请输入封面',trigger:'none'}]">
<div v-if="box.imgUrl" class="onlineImg">
<viewer :images="[box.imgUrl]">
<img :src="box.imgUrl" style="width:80px;height:80px;" />
</viewer>
<span class="removeImg" @click="removeImg()">×</span>
</div>
<div v-else class="addImg">
<span><Icon type="md-camera" /></span>
<input type="file" accept="image/*" onblur="this.value=''" @change="uploadPhoto" class="uploadImg"/>
</div>
<span class="ml10 cloc">200×200px</span>
</FormItem>
<FormItem label="地址">
<span v-if="!box.address" class="cloc">未绑定</span>
<span v-else>{{box.address}}</span>
</FormItem>
<FormItem label="邮箱">
<Input v-model="box.mail" style="width:50%;" maxlength="48"></Input>
</FormItem>
<!-- <FormItem label="性别">
<Select v-model="box.priority" placeholder="请选择" style="width:100px;" clearable >
<Option :value="1">男</Option>
<Option :value="0">女</Option>
</Select>
</FormItem> -->
<FormItem label="出生年月">
<DatePicker v-model="box.birth" :options="options3" type="date" placeholder="请选择时间" style="width: 200px"></DatePicker>
</FormItem>
<FormItem label="介绍">
<Input v-model="box.remark" type="textarea" maxlength="150" :autosize="{minRows: 2,maxRows: 5}" placeholder=""></Input>
</FormItem>
<FormItem label="角色">
<Select v-model="box.memberLevel" placeholder="请选择" style="width:100px;" clearable disabled>
<Option :value="1">普通用户</Option>
</Select>
</FormItem>
<FormItem label="状态" prop="status" :rules="[{ required: true, message: '',trigger:'none'}]">
<Select v-model="box.status" placeholder="请选择" style="width:100px;" clearable >
<Option :value="0">正常</Option>
<Option :value="1">禁用</Option>
</Select>
</FormItem>
</Form>
<div slot="footer">
<Button type="text" size="large" @click="isBoxPop=false;">取消</Button>
<Button type="success" size="large" @click="saveBox()">确定</Button>
</div>
</Modal>
<Modal v-model="cropperModel" :title="'图片裁剪'" :maskClosable="false" width="950px" @on-ok="uploadAvatar">
<cropper-image
:Name="cropperName"
@uploadImgSuccess = "handleUploadSuccess"
@getImageData="uploadAvatar"
ref="cropper">
</cropper-image>
</Modal>
<Modal
v-model="modal1"
title="图片裁剪"
:loading="loading"
@on-ok="uploadAvatar"
:mask-closable="false"
width="460px">
<div class="cropper">
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.size"
:outputType="option.outputType"
:info="true"
:full="option.full"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:autoCrop="option.autoCrop"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber"
:centerBox="option.centerBox"
:infoTrue="option.infoTrue"
:fixedBox="option.fixedBox"
@realTime="realTime"
:enlarge="1.5"
></vueCropper>
</div>
<!--预览效果图-->
<!-- <div class="show-preview">
<div :style="previews.div" class="preview" style="overflow:hidden;">
<img :src="previews.url" :style="previews.img">
</div>
</div> -->
<!-- <div :style="previewStyle1">
<div :style="previews.div">
<img :src="previews.url" :style="previews.img">
</div>
</div> -->
</Modal>
</div>
</template>
<script>
import axios from 'axios'
import { getToken } from '@/libs/token.js'
import config from '@/config'
import {regex} from '@/utils/base.js'
import {memberPage,updateMember} from '@/api/http.js'
import CropperImage from '@/components/CropperImage/CropperImage'
import { VueCropper } from "vue-cropper";
export default {
name: '',
props: {
},
components: {
CropperImage,VueCropper
},
data () {
return {
th: [
{ title: "ID", key: "id" },
{ title: "地址", slot: "address" },
{ title: "邮箱", key: "mail" },
{ title: "昵称", key: "username" },
{ title: "状态", slot: "status" },
{ title: "最后登录时间", key: "lastLoginTime" },
{ title: "操作", align: "center", slot: "control" },
],
td: [],
pageData:{
page:1,
size:10,
total:0,
address:'',
mail:''
},
isBoxPop:false,
box:{
id:"",
imgUrl:'',
mail:''
},
cropperModel:false,//裁剪弹窗组件
//头像裁剪
cropperName:'',
modal1: false,
option: {
img: '', // 裁剪图片的地址
info: true, // 裁剪框的大小信息
outputSize: 1, // 裁剪生成图片的质量
outputType: 'png', // 裁剪生成图片的格式
canScale: true, // 图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框
// autoCropWidth: 200, // 默认生成截图框宽度
// autoCropHeight: 200, // 默认生成截图框高度
fixedBox: true, // 固定截图框大小 不允许改变
fixed: true, // 是否开启截图框宽高固定比例
fixedNumber: [1, 1], // 截图框的宽高比例
full: false, // 是否输出原图比例的截图
canMoveBox: false, // 截图框能否拖动。裁剪框不能拖动的时候,那么拖动时就是控制的图片
original: false, // 上传图片按照原始比例渲染。true,裁剪框始终保持80%,false:由图片决定。
centerBox: true, // 截图框是否被限制在图片里面
infoTrue: true, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
},
fileinfo:'',
// 防止重复提交
loading: false,
previews: {},
previewStyle1:{},
options3: {
disabledDate (date) {
// return date && date.valueOf() < Date.now() - 86400000;//不能选今天之前的日期
// return date && date.valueOf() > Date.now() - 86400000;//不能选今天和今天之后的日期
return date && date.valueOf() > Date.now();//不能选今天之前的日期
}
},//时间选择框
}
},
mounted() {
this.getList();
},
methods: {
realTime (data) {
// 固定为 100 高度
// var previews = data
// var h = 1
// var w = 0.2
// this.previewStyle1 = {
// width: previews.w + "px",
// height: previews.h + "px",
// overflow: "hidden",
// margin: "0",
// zoom: h
// }
this.previews = data;
},
uploadAvatar() {
// console.log(data)
// return;
// this.$refs.cropper.getCropBlob((data) => {
// console.log(data,88)
// // this.downImg = window.URL.createObjectURL(data);
// // aLink.href = window.URL.createObjectURL(data);
// // aLink.click();
// });
// return;
let that = this;
this.$refs.cropper.getCropData((data) => {
that.loading = true
// that.$refs.upload.clearFiles()
console.log(convertBase64UrlToBlob(data),88);
// that.$refs.cropper.clearFiles()
// let formData=new FormData();
// formData.append('avatar',data)
// that.$axios.post('/api/manage/avatar/update',formData,{
// 'Content-Type':'multipart/form-data'
// }).then(res=>{
// that.loading = false
// if(res.data.err_code == 0){
// that.$router.push('/login')
// }else if(res.data.err_code == 1){
// that.$Message.success('修改成功!')
// that.changeAvatar({Avatar:res.data.data.slice(1)})
// }else{
// that.$Message.error('服务器出错!')
// }
// })
//base64转Blob
function convertBase64UrlToBlob(urlData){
//去掉url的头,并转换为byte
var split = urlData.split(',');
var bytes=window.atob(split[1]);
//处理异常,将ascii码小于0的转换为大于0
var ab = new ArrayBuffer(bytes.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob( [ab] , {type : split[0]});
}
let formData = new FormData();
let configs = {
headers:{
"Content-Type":'multipart/form-data',
"apiKey": getToken(),
'lang':'zh-CN',
}
}
formData.append('file', convertBase64UrlToBlob(data), new Date().getTime() + '.jpg');
formData.append('lang','1');//1中文,2英文
formData.append('type','1');//1图片,2视频
axios.post(config.baseUrl+'/file/upload',formData,configs).then(data=>{
that.loading = false
let res=data.data;
if(res.code=='000000'){
this.$Message.success(res.msg);
this.box.imgUrl=res.data.url;
this.$forceUpdate();
}else{
this.$Message.error(res.msg);
}
})
})
},
//图片上传成功后
handleUploadSuccess (data){
console.log(data)
switch(data.name){
case 'flagImg':
this.formValidate.mainImage = 'http://ydfblog.cn/dfs/'+data.url;
console.log('最终输出'+data.name)
break;
}
this.cropperModel = false;
},
//删除图片
removeImg(){
this.$Modal.confirm({
title:'您确认删除吗?',
onOk:()=>{
this.box.imgUrl='';
this.$forceUpdate();
},
onCancel:()=>{
}
})
},
//上传图片
uploadPhoto(e){
console.log('选择图片:',e)
let file = e.target.files[0];
if(!file)return;
this.fileinfo =file
let data = window.URL.createObjectURL(new Blob([file]));
this.option.img = data
this.modal1 = true;
// this.cropperModel=true;
return false;//取消自动上传
// let file = e.target.files[0];
// let formData = new FormData();
// let configs = {
// headers:{
// "Content-Type":'multipart/form-data',
// "apiKey": getToken(),
// 'lang':'zh-CN',
// }
// }
// formData.append('file',file);
// formData.append('lang','1');//1中文,2英文
// formData.append('type','1');//1图片,2视频
// axios.post(config.baseUrl+'/file/upload',formData,configs).then(data=>{
// let res=data.data;
// if(res.code=='000000'){
// this.$Message.success(res.msg);
// this.box.imgUrl=res.data.url;
// this.$forceUpdate();
// }else{
// this.$Message.error(res.msg);
// }
// })
},
//编辑
edit(item){
this.isBoxPop=true;
this.box=JSON.parse(JSON.stringify(item));
this.box.id=item.id;
},
//保存
saveBox(){
let d={
id:this.box.id,
imgUrl:this.box.imgUrl,
mail:this.box.mail,
remark:this.box.remark,
birth:this.box.birth && this.$dayjs(this.box.birth).format("YYYY-MM-DD"),//后推一天
// birth:this.box.birth==''?null:this.$dayjs(this.box.birth).valueOf(),//后推一天
status:this.box.status,
}
if(!d.imgUrl){
this.$Message.warning('请上传头像!');
return;
}
if(d.mail && !regex(d.mail,'email')){
this.$Message.warning('邮箱格式不正确!');
return;
}
if(!d.status && d.status!==0){
this.$Message.warning('请选择状态!');
return;
}
//临时
// let configs = {
// headers:{
// "Content-Type": "application/json",
// "apiKey": getToken(),
// 'lang':'zh-CN',
// }
// }
// axios.post(config.userBaseUrl+'/member/updateMember',d,configs).then((response) => {
// let res=response.data;
// if(res.code=='000000'){
// this.$Message.success(res.msg);
// this.getList();
// this.isBoxPop=false;
// }else{
// this.$Message.error(res.msg);
// }
// })
updateMember(d).then((res) => {
if(res.code=='000000'){
this.$Message.success(res.msg);
this.getList();
this.isBoxPop=false;
}else{
this.$Message.error(res.msg);
}
});
},
//清空
clear(){
this.pageData={
page:1,
address:'',
mail:''
}
this.getList();
},
//搜索
seach(){
this.pageData.page=1;
this.getList();
},
handlePage(page) {
this.pageData.page = page;
this.getList();
},
//获取用户列表
getList() {
let d={
current:this.pageData.page,
size:this.pageData.size,
address:this.pageData.address && this.pageData.address.trim(),
mail:this.pageData.mail && this.pageData.mail.trim(),
}
//临时
// let configs = {
// headers:{
// "Content-Type": "application/json",
// "apiKey": getToken(),
// 'lang':'zh-CN',
// }
// }
// axios.post(config.userBaseUrl+'/member/memberPage',d,configs).then((response) => {
// let res=response.data;
// if(res.code=='000000'){
// this.td=res.data.list || [];
// this.td.forEach(item=>{
// item.lastLoginTime=item.lastLoginTime && this.$dayjs(item.lastLoginTime).format('YYYY-MM-DD HH:mm:ss');
// item.birth=item.birth && this.$dayjs(item.birth).format('YYYY-MM-DD');
// });
// this.pageData.total=res.data.totalCount || 0;
// }else{
// this.$Message.error(res.msg);
// }
// })
memberPage(d).then((res) => {
if(res.code=='000000'){
this.td=res.data.list || [];
this.td.forEach(item=>{
item.lastLoginTime=item.lastLoginTime && this.$dayjs(item.lastLoginTime).format('YYYY-MM-DD HH:mm:ss');
item.birth=item.birth && this.$dayjs(item.birth).format('YYYY-MM-DD');
});
this.pageData.total=res.data.totalCount || 0;
}else{
this.$Message.error(res.msg);
}
});
},
},
}
</script>
<style scoped lang='less'>
.cropper {
width: 400px;
height: 400px;
}
</style>
针对常规图片的处理(添加部分功能):
代码:
待处理。
完整代码:
三.官方测试所有用例:
?预览地址:https://codepen.io/xyxiao001/pen/wxwKGz
效果图:
代码:
<template>
<div>
<div id="app">
<div class="model" v-show="model" @click="model = false">
<div class="model-show">
<img :src="modelSrc" alt="">
</div>
</div>
<p>例子</p>
<div class="cut">
<vue-cropper ref="cropper" :img="option.img" :output-size="option.size" :output-type="option.outputType" :info="true" :full="option.full" :fixed="fixed" :fixed-number="fixedNumber" :can-move="option.canMove" :can-move-box="option.canMoveBox" :fixed-box="option.fixedBox" :original="option.original" :auto-crop="option.autoCrop" :auto-crop-width="option.autoCropWidth" :auto-crop-height="option.autoCropHeight" :center-box="option.centerBox" @real-time="realTime" :high="option.high" @img-load="imgLoad" mode="cover" :max-img-size="option.max" @crop-moving="cropMoving"></vue-cropper>
</div>
<div class="show-preview" :style="{'width': previews.w + 'px', 'height': previews.h + 'px', 'overflow': 'hidden', 'margin': '5px'}">
<div :style="previews.div">
<img :src="previews.url" :style="previews.img">
</div>
</div>
<div class="test-button">
<button @click="changeImg" class="btn">changeImg</button>
<label class="btn" for="uploads">upload</label>
<input type="file" id="uploads" style="position:absolute; clip:rect(0 0 0 0);" accept="image/png, image/jpeg, image/gif, image/jpg" @change="uploadImg($event, 1)">
<button @click="startCrop" v-if="!crap" class="btn">start</button>
<button @click="stopCrop" v-else class="btn">stop</button>
<button @click="clearCrop" class="btn">clear</button>
<button @click="refreshCrop" class="btn">refresh</button>
<button @click="changeScale(1)" class="btn">+</button>
<button @click="changeScale(-1)" class="btn">-</button>
<button @click="rotateLeft" class="btn">rotateLeft</button>
<button @click="rotateRight" class="btn">rotateRight</button>
<button @click="finish('base64')" class="btn">preview(base64)</button>
<button @click="finish('blob')" class="btn">preview(blob)</button>
<a @click="down('base64')" class="btn">download(base64)</a>
<a @click="down('blob')" class="btn">download(blob)</a>
<a @click="() => option.img = ''" class="btn">清除图片</a>
<div style="display:block; width: 100%;">
<label class="c-item">
<span>上传图片是否显示原始宽高 (针对大图 可以铺满)</span>
<input type="checkbox" v-model="option.original">
<span>original: {{ option.original}}</span>
</label>
<label class="c-item">
<span>能否拖动图片</span>
<input type="checkbox" v-model="option.canMove">
</label>
<label class="c-item">
<span>能否拖动截图框</span>
<input type="checkbox" v-model="option.canMoveBox">
<span>canMoveBox: {{ option.canMoveBox}}</span>
</label>
<label class="c-item">
<span>截图框固定大小</span>
<input type="checkbox" v-model="option.fixedBox">
<span>fixedBox: {{ option.fixedBox}}</span>
</label>
<label class="c-item">
<span>是否输出原图比例的截图</span>
<input type="checkbox" v-model="option.full">
<span>full: {{ option.full}}</span>
</label>
<label class="c-item">
<span>是否自动生成截图框</span>
<input type="checkbox" v-model="option.autoCrop">
<span>autoCrop: {{ option.autoCrop}}</span>
</label>
<label class="c-item">
<span>是否根据dpr生成适合屏幕的高清图片</span>
<input type="checkbox" v-model="option.high">
<span>high: {{ option.high}}</span>
</label>
<label class="c-item">
<span>截图框是否限制在图片里(只有在自动生成截图框时才能生效)</span>
<input type="checkbox" v-model="option.centerBox">
<span>centerBox: {{ option.centerBox}}</span>
</label>
<label class="c-item">
<p>输出图片格式</p>
<label>jpg
<input type="radio" name="type" value="jpeg" v-model="option.outputType">
</label>
<label>png
<input type="radio" name="type" value="png" v-model="option.outputType">
</label>
<label>webp
<input type="radio" name="type" value="webp" v-model="option.outputType">
</label>
</label>
</div>
</div>
</div>
</div>
</template>
<script>
import { VueCropper } from "vue-cropper";
export default {
name: "",
props: {},
components: {
VueCropper,
},
data() {
return {
model: false,
modelSrc: "",
crap: false,
previews: {},
lists: [
{
img:
"https://avatars2.githubusercontent.com/u/15681693?s=460&v=4",
},
],
option: {
img:
"https://avatars2.githubusercontent.com/u/15681693?s=460&v=4",
size: 1,
full: false,
outputType: "png",
canMove: true,
fixedBox: false,
original: false,
canMoveBox: true,
autoCrop: true,
// 只有自动截图开启 宽度高度才生效
autoCropWidth: 160,
autoCropHeight: 150,
centerBox: false,
high: true,
max: 99999,
},
show: true,
fixed: true,
fixedNumber: [16, 9],
};
},
mounted() {},
methods: {
changeImg() {
this.option.img = this.lists[
~~(Math.random() * this.lists.length)
].img;
},
startCrop() {
// start
this.crap = true;
this.$refs.cropper.startCrop();
},
stopCrop() {
// stop
this.crap = false;
this.$refs.cropper.stopCrop();
},
clearCrop() {
// clear
this.$refs.cropper.clearCrop();
},
refreshCrop() {
// clear
this.$refs.cropper.refresh();
},
changeScale(num) {
num = num || 1;
this.$refs.cropper.changeScale(num);
},
rotateLeft() {
this.$refs.cropper.rotateLeft();
},
rotateRight() {
this.$refs.cropper.rotateRight();
},
finish(type) {
// 输出
// var test = window.open('about:blank')
// test.document.body.innerHTML = '图片生成中..'
if (type === "blob") {
this.$refs.cropper.getCropBlob((data) => {
console.log(data);
var img = window.URL.createObjectURL(data);
this.model = true;
this.modelSrc = img;
});
} else {
this.$refs.cropper.getCropData((data) => {
this.model = true;
this.modelSrc = data;
});
}
},
// 实时预览函数
realTime(data) {
this.previews = data;
console.log(data);
},
finish2(type) {
this.$refs.cropper2.getCropData((data) => {
this.model = true;
this.modelSrc = data;
});
},
finish3(type) {
this.$refs.cropper3.getCropData((data) => {
this.model = true;
this.modelSrc = data;
});
},
down(type) {
// event.preventDefault()
var aLink = document.createElement("a");
aLink.download = "demo";
// 输出
if (type === "blob") {
this.$refs.cropper.getCropBlob((data) => {
this.downImg = window.URL.createObjectURL(data);
aLink.href = window.URL.createObjectURL(data);
aLink.click();
});
} else {
this.$refs.cropper.getCropData((data) => {
this.downImg = data;
aLink.href = data;
aLink.click();
});
}
},
uploadImg(e, num) {
//上传图片
// this.option.img
var file = e.target.files[0];
if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
alert("图片类型必须是.gif,jpeg,jpg,png,bmp中的一种");
return false;
}
var reader = new FileReader();
reader.onload = (e) => {
let data;
if (typeof e.target.result === "object") {
// 把Array Buffer转化为blob 如果是base64不需要
data = window.URL.createObjectURL(
new Blob([e.target.result])
);
} else {
data = e.target.result;
}
if (num === 1) {
this.option.img = data;
} else if (num === 2) {
this.example2.img = data;
}
};
// 转化为base64
// reader.readAsDataURL(file)
// 转化为blob
reader.readAsArrayBuffer(file);
},
imgLoad(msg) {
console.log(msg);
},
cropMoving(data) {
console.log(data, "截图框当前坐标");
},
},
};
</script>
<style scoped lang='scss'>
* {
margin: 0;
padding: 0;
}
.cut {
width: 500px;
height: 500px;
margin: 30px auto;
}
.c-item {
max-width: 800px;
margin: 10px auto;
margin-top: 20px;
}
.content {
margin: auto;
max-width: 1200px;
margin-bottom: 100px;
}
.test-button {
display: flex;
flex-wrap: wrap;
align-content: center;
justify-content: center;
}
.btn {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
border: 1px solid #c0ccda;
color: #1f2d3d;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 20px 10px 0px 0px;
padding: 9px 15px;
font-size: 14px;
border-radius: 4px;
color: #fff;
background-color: #50bfff;
border-color: #50bfff;
transition: all 0.2s ease;
text-decoration: none;
user-select: none;
}
.des {
line-height: 30px;
}
code.language-html {
padding: 10px 20px;
margin: 10px 0px;
display: block;
background-color: #333;
color: #fff;
overflow-x: auto;
font-family: Consolas, Monaco, Droid, Sans, Mono, Source, Code, Pro, Menlo,
Lucida, Sans, Type, Writer, Ubuntu, Mono;
border-radius: 5px;
white-space: pre;
}
.show-info {
margin-bottom: 50px;
}
.show-info h2 {
line-height: 50px;
}
/*.title, .title:hover, .title-focus, .title:visited {
color: black;
}*/
.title {
display: block;
text-decoration: none;
text-align: center;
line-height: 1.5;
margin: 20px 0px;
background-image: -webkit-linear-gradient(
left,
#3498db,
#f47920 10%,
#d71345 20%,
#f7acbc 30%,
#ffd400 40%,
#3498db 50%,
#f47920 60%,
#d71345 70%,
#f7acbc 80%,
#ffd400 90%,
#3498db
);
color: transparent;
-webkit-background-clip: text;
background-size: 200% 100%;
animation: slide 5s infinite linear;
font-size: 40px;
}
.test {
height: 500px;
}
.model {
position: fixed;
z-index: 10;
width: 100vw;
height: 100vh;
overflow: auto;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.8);
}
.model-show {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
}
.model img {
display: block;
margin: auto;
max-width: 80%;
user-select: none;
background-position: 0px 0px, 10px 10px;
background-size: 20px 20px;
background-image: linear-gradient(
45deg,
#eee 25%,
transparent 25%,
transparent 75%,
#eee 75%,
#eee 100%
),
linear-gradient(
45deg,
#eee 25%,
white 25%,
white 75%,
#eee 75%,
#eee 100%
);
}
.c-item {
display: block;
user-select: none;
}
@keyframes slide {
0% {
background-position: 0 0;
}
100% {
background-position: -100% 0;
}
}
</style>
|