添加vue-canvas-poster

This commit is contained in:
熊丽君
2021-09-03 10:49:11 +08:00
parent 34c33fc2a4
commit 7cdaf34735
39 changed files with 4047 additions and 175 deletions

View File

@ -1,91 +1,100 @@
<template> 
<div>
<template>
<div style="width:100%">
<el-upload
:action="useOss?ossUploadUrl:minioUploadUrl"
:data="useOss?dataObj:null"
:action="useOss ? ossUploadUrl : minioUploadUrl"
:data="useOss ? dataObj : null"
list-type="picture"
:multiple="false" :show-file-list="showFileList"
:multiple="false"
:show-file-list="showFileList"
:file-list="fileList"
:before-upload="beforeUpload"
:on-remove="handleRemove"
:on-success="handleUploadSuccess"
:on-preview="handlePreview">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件且不超过10MB</div>
:on-preview="handlePreview"
>
<el-button size="mini" style="width:100%">添加图片</el-button>
<!-- <div slot="tip" class="el-upload__tip">
只能上传jpg/png文件且不超过10MB
</div> -->
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="fileList[0].url" alt="">
</el-dialog>
<!-- <el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="fileList[0].url" alt="" />
</el-dialog> -->
</div>
</template>
<script>
import {policy} from '@/api/oss'
import { policy } from '@/api/oss';
export default {
name: 'singleUpload',
props: {
value: String
export default {
name: 'singleUpload',
props: {
value: String
},
computed: {
imageUrl() {
return this.value;
},
computed: {
imageUrl() {
return this.value;
},
imageName() {
if (this.value != null && this.value !== '') {
return this.value.substr(this.value.lastIndexOf("/") + 1);
} else {
return null;
}
},
fileList() {
return [{
name: this.imageName,
url: this.imageUrl
}]
},
showFileList: {
get: function () {
return this.value !== null && this.value !== ''&& this.value!==undefined;
},
set: function (newValue) {
}
imageName() {
if (this.value != null && this.value !== '') {
return this.value.substr(this.value.lastIndexOf('/') + 1);
} else {
return null;
}
},
data() {
return {
dataObj: {
policy: '',
signature: '',
key: '',
ossaccessKeyId: '',
dir: '',
host: '',
// callback:'',
},
dialogVisible: false,
useOss:false, //使用oss->true;使用MinIO->false
ossUploadUrl:'http://macro-oss.oss-cn-shenzhen.aliyuncs.com',
minioUploadUrl:'http://192.168.99.239:1818/minio/upload',
};
},
methods: {
emitInput(val) {
this.$emit('input', val)
},
handleRemove(file, fileList) {
this.emitInput('');
},
handlePreview(file) {
this.dialogVisible = true;
},
beforeUpload(file) {
let _self = this;
if(!this.useOss){
//不使用oss不需要获取策略
return true;
fileList() {
return [
{
name: this.imageName,
url: this.imageUrl
}
return new Promise((resolve, reject) => {
policy().then(response => {
];
},
showFileList: {
get: function() {
return (
this.value !== null && this.value !== '' && this.value !== undefined
);
},
set: function(newValue) {}
}
},
data() {
return {
dataObj: {
policy: '',
signature: '',
key: '',
ossaccessKeyId: '',
dir: '',
host: ''
// callback:'',
},
dialogVisible: false,
useOss: false, //使用oss->true;使用MinIO->false
ossUploadUrl: 'http://macro-oss.oss-cn-shenzhen.aliyuncs.com',
// minioUploadUrl:'http://192.168.99.239:1818/minio/upload',
minioUploadUrl: process.env.VUE_APP_BASE_API + '/minio/upload'
};
},
methods: {
emitInput(val) {
this.$emit('input', val);
},
handleRemove(file, fileList) {
this.emitInput('');
},
handlePreview(file) {
this.dialogVisible = true;
},
beforeUpload(file) {
let _self = this;
if (!this.useOss) {
//不使用oss不需要获取策略
return true;
}
return new Promise((resolve, reject) => {
policy()
.then(response => {
_self.dataObj.policy = response.data.policy;
_self.dataObj.signature = response.data.signature;
_self.dataObj.ossaccessKeyId = response.data.accessKeyId;
@ -93,29 +102,26 @@
_self.dataObj.dir = response.data.dir;
_self.dataObj.host = response.data.host;
// _self.dataObj.callback = response.data.callback;
resolve(true)
}).catch(err => {
console.log(err)
reject(false)
resolve(true);
})
})
},
handleUploadSuccess(res, file) {
this.showFileList = true;
this.fileList.pop();
let url = this.dataObj.host + '/' + this.dataObj.dir + '/' + file.name;
if(!this.useOss){
//不使用oss直接获取图片路径
url = res.data.url;
}
this.fileList.push({name: file.name, url: url});
this.emitInput(this.fileList[0].url);
.catch(err => {
console.log(err);
reject(false);
});
});
},
handleUploadSuccess(res, file) {
this.showFileList = true;
this.fileList.pop();
let url = this.dataObj.host + '/' + this.dataObj.dir + '/' + file.name;
if (!this.useOss) {
//不使用oss直接获取图片路径
url = res.data.url;
}
this.fileList.push({ name: file.name, url: url });
this.emitInput(this.fileList[0].url);
}
}
};
</script>
<style>
</style>
<style></style>

View File

@ -0,0 +1,109 @@
<template>
<div class="blankDialog-comp-ct">
<el-dialog
@close="handleClose"
:width="contentWidth+'px'"
:visible.sync="showDialog">
<div
class="content"
:style="{
background: bg,
height: contentHeight + 'px',
contentWidth: contentWidth + 'px',
padding: padding + 'px'
}"
>
<div class="title">{{ dTitle }}</div>
<slot></slot>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'blankDialog',
props: {
bg: {
type: String,
default: '#fff'
},
contentWidth: {
type: Number,
default: 720
},
padding: {
type: Number,
default: 48
},
contentHeight: {
type: Number,
default: 500
},
value: {
type: Boolean,
default: false
},
dTitle: {
type: String
}
},
data () {
return {
showDialog: true
}
},
methods: {
handleClose () {
this.$emit('close')
}
},
watch: {
value (val) {
if (val !== this.showDialog) {
this.showDialog = val
}
},
showDialog (val) {
if (val !== this.value) {
this.$emit('input', val)
}
}
},
created () {
this.showDialog = this.value
}
}
</script>
<style lang="scss">
.blankDialog-comp-ct{
.el-dialog{
/* width: 800px;*/
.el-dialog__header{
padding: 0;
margin: 0;
.el-dialog__headerbtn .el-dialog__close{
color: #282828;
}
}
.el-dialog__body{
padding: 0;
height: auto;
width: auto;
}
}
}
</style>
<style lang="scss" scoped>
.blankDialog-comp-ct {
.content{
box-sizing: border-box;
overflow: auto;
/*padding: 48px;*/
.title{
margin-bottom: 16px;
font-size: 24px;
color: rgba(33, 33, 33, 1);
}
}
}
</style>

View File

@ -0,0 +1,6 @@
import blankDialog from './blankDialog.vue'
import Vue from 'vue'
blankDialog.install = function () {
Vue.component(blankDialog.name, blankDialog)
}
export default blankDialog

View File

@ -0,0 +1,239 @@
<template>
<div class="image-selection-comp">
<div class="header-ct m-b-16">
<div class="title">选择图片</div>
<div class="right">
<el-input
clearable
v-model="search"
placeholader="搜索内容"
class="width-200" size="mini" suffix-icon="el-icon-search">
<el-button slot="append">搜索</el-button>
</el-input>
</div>
</div>
<div class="main">
<div class="right">
<div
@click="handleClickImageItem(i, item)"
class="list-item cursor-p"
:key="item.uid"
v-for="(item, i) in imageList"
:style="{background: item.bg}">
<el-checkbox class="check-ct" :value="item.active"></el-checkbox>
<img :src="item.path" class="img"/>
<div class="text single-row-ellipsis">
{{item.name}}
</div>
</div>
</div>
</div>
<div class="bottom-ct">
<el-button @click="cancel">取消</el-button>
<el-button @click="submit" type="primary">确定</el-button>
</div>
</div>
</template>
<script>
import uuid from 'uuid'
export default {
props: {
// 是否单选
isSingle: {
type: Boolean,
default: true
},
value: {
type: Object
}
},
data () {
return {
search: '',
imageList: [
{
uid: uuid(),
name: '钢铁侠',
path: require('../assets/image/1.jpg')
},
{
uid: uuid(),
name: '蜘蛛侠',
path: require('../assets/image/2.jpg')
},
{
uid: uuid(),
name: '美国队长',
path: require('../assets/image/3.jpg')
},
{
uid: uuid(),
name: '奇异博士',
path: require('../assets/image/4.jpg')
},
{
uid: uuid(),
name: '蚁人',
path: require('../assets/image/5.jpg')
},
{
uid: uuid(),
name: '钢铁侠2',
path: require('../assets/image/6.jpg')
}
],
activeIndex: -1,
selectionImage: [],
selectionImageUids: [],
systemMaterialList: [],
materialList: [],
tagSelect: ''
// systemMaterialListCount: 0,
// materialListCount: 0
}
},
methods: {
handleClickImageItem (i, item) {
this.isSingle ? this.singleModeClick(i, item) : this.multipleModeClick(i, item)
},
singleModeClick (i, item) {
if (i === this.activeIndex) {
this.$set(this.imageList, i, { ...item, active: false })
this.activeIndex = -1
} else {
let oldItem = this.imageList[this.activeIndex]
this.$set(this.imageList, this.activeIndex, { ...oldItem, active: false })
this.activeIndex = i
this.$set(this.imageList, this.activeIndex, { ...item, active: true })
}
},
multipleModeClick (i, item) {
this.$set(this.imageList, i, { ...item, active: !item.active })
},
reset () {
this.imageList.forEach(v => {
v.active = false
})
},
async submit () {
let imageSelection = this.imageList.filter(v => v.active)
if (imageSelection.length === 0) {
this.$message.error('请选择图片!')
return false
}
this.$emit('success', this.isSingle ? imageSelection[0] : imageSelection)
this.reset()
},
cancel () {
this.$emit('cancel')
this.reset()
}
},
watch: {
value (val) {
if (val) {
// this.findBackground()
}
}
},
async created () {
}
}
</script>
<style lang="scss" scoped>
* {
box-sizing: border-box;
}
.image-selection-comp{
position: relative;
.header-ct{
display: flex;
justify-content: space-between;
align-items: center;
.title {
font-size: 27px;
font-weight: 400;
color: rgba(44, 62, 80, 1);
}
.right{
display: flex;
}
}
.main{
display: flex;
.left{
box-sizing: border-box;
width: 200px;
height: 400px;
border-right: 1px solid #E4E8EB;
.type-child-item{
position: relative;
padding-left: 24px;
height: 32px;
line-height: 32px;
&.active{
background: #409EFF;
color: white;
&:before{
background: white;
}
}
&:before{
content: '';
display: block;
position: absolute;
top: 13px;
left: 8px;
background: black;
width: 6px;
height: 6px;
overflow: hidden;
border-radius: 50%;
z-index: 9;
}
}
}
.right{
flex: 1;
display: grid;
flex-wrap: wrap;
grid-template-columns: repeat(auto-fill, 144px);
grid-template-rows: repeat(auto-fill, 144px);
grid-row-gap: 8px;
grid-column-gap: 8px;
margin-left: 16px;
.list-item{
position: relative;
width: 144px;
height: 144px;
border: 1px solid #e1e1e1;
overflow: hidden;
.check-ct{
position: absolute;
top: 8px;
left: 8px;
}
.img{
display: block;
width: 100%;
height: 100.8px;
}
}
.text{
height: 43px;
line-height: 43px;
text-align: center;
}
}
}
.bottom-ct{
/*position: absolute;
left: 0;
bottom: 0;*/
margin-top: 32px;
display: flex;
justify-content: flex-end;
width: 100%;
}
}
</style>

View File

@ -0,0 +1,93 @@
<template>
<div>
<el-tooltip
:key="item.icon"
v-for="item in iconList"
effect="dark"
:content="item.label"
placement="top-start">
<Icon
:active="(item.dir === 'x' && item.value === align.x) || (item.dir === 'y' && item.value === align.y)"
@click.native="handleClick(item)" :icon="item.icon"></Icon>
</el-tooltip>
</div>
</template>
<script>
import _ from 'lodash'
import Icon from './icon'
export default {
components: {
Icon
},
props: {
value: {
type: Object,
required: true
}
},
data () {
return {
align: {
x: 2,
y: 2
},
iconList: [
{
icon: 'zuoduiqi2',
label: '左对齐',
value: 1,
dir: 'x'
},
{
icon: 'shuipingjuzhongduiqi',
label: '水平居中对齐',
value: 2,
dir: 'x'
},
{
icon: 'youduiqi',
label: '右对齐',
value: 3,
dir: 'x'
},
{
icon: 'shangduiqi',
label: '上对齐',
value: 1,
dir: 'y'
},
{
icon: 'chuizhijuzhongduiqi',
label: '垂直居中对齐',
value: 2,
dir: 'y'
},
{
icon: 'xiaduiqi',
label: '下对齐',
value: 3,
dir: 'y'
}
]
}
},
methods: {
handleClick (item) {
this.align[item.dir] = item.value
this.$emit('input', this.align)
}
},
created () {
this.align = { ...this.value }
},
watch: {
value (val) {
if (!_.isEqual(val, this.align)) {
this.align = { ...val }
}
}
}
}
</script>
<style lang="scss">
</style>

View File

@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

View File

@ -0,0 +1,446 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>IconFont Demo</title>
<link rel="shortcut icon" href="https://gtms04.alicdn.com/tps/i4/TB1_oz6GVXXXXaFXpXXJDFnIXXX-64-64.ico" type="image/x-icon"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">&#xe86b;</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=1577785" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe65b;</span>
<div class="name">右对齐</div>
<div class="code-name">&amp;#xe65b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe64b;</span>
<div class="name">下对齐</div>
<div class="code-name">&amp;#xe64b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe600;</span>
<div class="name">水平居中对齐</div>
<div class="code-name">&amp;#xe600;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe67f;</span>
<div class="name">左对齐</div>
<div class="code-name">&amp;#xe67f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe632;</span>
<div class="name">居中对齐</div>
<div class="code-name">&amp;#xe632;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe64e;</span>
<div class="name">上对齐</div>
<div class="code-name">&amp;#xe64e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe650;</span>
<div class="name">左对齐</div>
<div class="code-name">&amp;#xe650;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe60e;</span>
<div class="name">右对齐</div>
<div class="code-name">&amp;#xe60e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe60f;</span>
<div class="name">左对齐</div>
<div class="code-name">&amp;#xe60f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe603;</span>
<div class="name">undo</div>
<div class="code-name">&amp;#xe603;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe670;</span>
<div class="name">垂直居中对齐</div>
<div class="code-name">&amp;#xe670;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe651;</span>
<div class="name">undo</div>
<div class="code-name">&amp;#xe651;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>兼容性最好,支持 IE6+,及所有现代浏览器。</li>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用如果有需求建议使用symbol 的引用方式</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.eot');
src: url('iconfont.eot?#iefix') format('embedded-opentype'),
url('iconfont.woff2') format('woff2'),
url('iconfont.woff') format('woff'),
url('iconfont.ttf') format('truetype'),
url('iconfont.svg#iconfont') format('svg');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-youduiqi"></span>
<div class="name">
右对齐
</div>
<div class="code-name">.icon-youduiqi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xiaduiqi"></span>
<div class="name">
下对齐
</div>
<div class="code-name">.icon-xiaduiqi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shuipingjuzhongduiqi"></span>
<div class="name">
水平居中对齐
</div>
<div class="code-name">.icon-shuipingjuzhongduiqi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-zuoduiqi"></span>
<div class="name">
左对齐
</div>
<div class="code-name">.icon-zuoduiqi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-card-text-center"></span>
<div class="name">
居中对齐
</div>
<div class="code-name">.icon-card-text-center
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shangduiqi"></span>
<div class="name">
上对齐
</div>
<div class="code-name">.icon-shangduiqi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-zuoduiqi2"></span>
<div class="name">
左对齐
</div>
<div class="code-name">.icon-zuoduiqi2
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-youduiqi1"></span>
<div class="name">
右对齐
</div>
<div class="code-name">.icon-youduiqi1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-zuoduiqi1"></span>
<div class="name">
左对齐
</div>
<div class="code-name">.icon-zuoduiqi1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-Undo"></span>
<div class="name">
undo
</div>
<div class="code-name">.icon-Undo
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-chuizhijuzhongduiqi"></span>
<div class="name">
垂直居中对齐
</div>
<div class="code-name">.icon-chuizhijuzhongduiqi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-ic_undo"></span>
<div class="name">
undo
</div>
<div class="code-name">.icon-ic_undo
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>兼容性良好,支持 IE8+,及所有现代浏览器。</li>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
<li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-youduiqi"></use>
</svg>
<div class="name">右对齐</div>
<div class="code-name">#icon-youduiqi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xiaduiqi"></use>
</svg>
<div class="name">下对齐</div>
<div class="code-name">#icon-xiaduiqi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shuipingjuzhongduiqi"></use>
</svg>
<div class="name">水平居中对齐</div>
<div class="code-name">#icon-shuipingjuzhongduiqi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zuoduiqi"></use>
</svg>
<div class="name">左对齐</div>
<div class="code-name">#icon-zuoduiqi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-card-text-center"></use>
</svg>
<div class="name">居中对齐</div>
<div class="code-name">#icon-card-text-center</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shangduiqi"></use>
</svg>
<div class="name">上对齐</div>
<div class="code-name">#icon-shangduiqi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zuoduiqi2"></use>
</svg>
<div class="name">左对齐</div>
<div class="code-name">#icon-zuoduiqi2</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-youduiqi1"></use>
</svg>
<div class="name">右对齐</div>
<div class="code-name">#icon-youduiqi1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zuoduiqi1"></use>
</svg>
<div class="name">左对齐</div>
<div class="code-name">#icon-zuoduiqi1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-Undo"></use>
</svg>
<div class="name">undo</div>
<div class="code-name">#icon-Undo</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-chuizhijuzhongduiqi"></use>
</svg>
<div class="name">垂直居中对齐</div>
<div class="code-name">#icon-chuizhijuzhongduiqi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-ic_undo"></use>
</svg>
<div class="name">undo</div>
<div class="code-name">#icon-ic_undo</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>

View File

@ -0,0 +1,65 @@
@font-face {font-family: "iconfont";
src: url('iconfont.eot?t=1578558136402'); /* IE9 */
src: url('iconfont.eot?t=1578558136402#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAYYAAsAAAAADMwAAAXLAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCEUgqKGId2ATYCJAM0CxwABCAFhG0HgUobxAojEaaMjp/sLxLMk0wHLVmncXb21PWwcny3xMGD4l8oJema4IHozH+zMxEOmwJO8uFUzpXOpgByNXhX++8HkAQIyENwg7lbAW7qrO0j3q7pt+DY9WnHNeDIsULKy3Kpdy10UV+stfpu03VfDAuFGt/EENXQIBMShCLi8eciHiqEQsmdxbya7IRiUma8ej8E4CS/skS1GvWaYEfBDxOA6Nkt3hF7JIDKYQvsbitxrnpXzMaCXZuiZQGznN8X3xDMDhoWCX9Q1KjehYiJOUYmkgnayEwy24sBt4tAAmWBArGXTGxHem1lSZwfZBQJIMBPYjUxpekzg2Zds4GZYbY2+5pjkkkY3tssOhdPCAICnxOb20Ff/+bZcWBBw4oNNwIXCoQVdLhh2epI0EQBEkwVnGB6VbCD6VPBAWZQBQuYdVXQwGygghXMqAo2MDMM/ThbgwoCzL4quMAcYzrRDo91Tm5QAaIriBNwVxdHWaGwYDWKLWhYEArRbnPg8kMgn///AtcIl9XZ3aO5O+IVfbyabwT+BmhO2UzVprlbeToKF62kS2smPVoHH95mmk+2dynnAM0rewkv7epZ4/JWsqNw0zxt2onEcWfq1JOZp+K+AwHG62+VQnHC/oMOTz7G3dJepNClzRZDOS2d+xnZ1GlzxdzS06UPdKvTR7BkSzHfpm15xNKtxb3rN7eIolKGC5G51emfujkmbTn/PJdvGmpof0hscaVNK24fEYr4ptXFa/q/Hpwty+qbNyC17/pgsTTQQi3uP24mFi1dn95lfkKPLdgkxL1XhUgs0MWiRaL/1PlgxMMnue49anr/dWsXzs4e3M0Xw9VuMt+2h+gSkxE8eNVSPPg6FModCoeyspay1Ihlkx0MGiGD9+lQkYo3diV+TMya9fL0yx8qFIwU5PNc8XA8tGRpeGlWEIO9MbIJJkNGiCVZoaWha0HfF0w20DNnPQNjTK6kNRa+eSibWim1CxtV44VrFxpSdXCuoi0wqhqFWrx2MVoVzSg0uOpgMpiWZLUvHPcVbg83H0K7w+Eq4Z5311jW9OzpvOVUoQ/6f8DFgnfy3Z6KPXo6bjnCaid9X4OgEj0ZOaYcVCR+7Yv3rqgjUT2oq+2PpGc1sgSOWSpZ6NNxj0Al/XigiiiiZ+UE8+lVXgRpDSulXwtcDByTldSjF6NXP6gkRc9Hjyo8OXBefxK0dS29kn41Oj9yVS+X1ecVibq2irFA6YjxhSJEcMa+f+PJ5+ObFs93PwsOTI09azI+p9PZ1NSHA4VtcQc6LLb7q9qW2LbvCO1I22FfbLtl//3nXV+1kWMJbBz16ajfP/nzU/Fav32086NRDuNf48NPhr8ezptJf745+OaQc6A7O7GweHnLapXTZcyfQNKUcZkbQCa0m1F8mB3XskVjylOZYK/Rvmt5IXvJQhhPqLlUIZmp5sDefyghcwHIH+OvvNR5mamz/obdi1Y8L3wf/zZcCoDHn8jDaGh/fCZgR4PSRn00RT2B5F/q6d3Mgx71nkUtfxKg5yyfHXWeaLMdDxF0RYsGOEUGkpBJ9bwfl156IAjs6AFo2MgHEjtF0QpfFiy4CIMVO5+BkzJqXuwiTX8kQjmA0iYwEPjtAg0vp0Dil41W+GdgIeA7sOJPwgOX/nq65pWX6PJVsFJsoN4DGZ6sDOulO/gL2zBUEjY7/D8UT2XI4jTe+YkTShsn+E2bq1qwwiN8sIfhMDDMwh0ajZ3qvE4SSyEUGx4Xl14JVFGoAWp7gBhsYq311WXi57+gVjCoSM6sn6Z/kPBo8yATS0ugPx1TqVnHMtLbaOUUWyxgbwPZCHxgDA2ijYGZ3quDDBVzNVpmawmuZss64v5d4zHfADhx5DyFrKiabpiW7bheOp9DE+ifzndUudFn7+z6M01tFw6OjTncQ+Cd700lTaS408jgTnTIpXdVAcJFOL9o0ZMlR2THv1PDT6bhNQdHl5YzMkWg/YsF') format('woff2'),
url('iconfont.woff?t=1578558136402') format('woff'),
url('iconfont.ttf?t=1578558136402') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('iconfont.svg?t=1578558136402#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-youduiqi:before {
content: "\e65b";
}
.icon-xiaduiqi:before {
content: "\e64b";
}
.icon-shuipingjuzhongduiqi:before {
content: "\e600";
}
.icon-zuoduiqi:before {
content: "\e67f";
}
.icon-card-text-center:before {
content: "\e632";
}
.icon-shangduiqi:before {
content: "\e64e";
}
.icon-zuoduiqi2:before {
content: "\e650";
}
.icon-youduiqi1:before {
content: "\e60e";
}
.icon-zuoduiqi1:before {
content: "\e60f";
}
.icon-Undo:before {
content: "\e603";
}
.icon-chuizhijuzhongduiqi:before {
content: "\e670";
}
.icon-ic_undo:before {
content: "\e651";
}

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,93 @@
{
"id": "1577785",
"name": "classcard",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "657594",
"name": "右对齐",
"font_class": "youduiqi",
"unicode": "e65b",
"unicode_decimal": 58971
},
{
"icon_id": "2404492",
"name": "下对齐",
"font_class": "xiaduiqi",
"unicode": "e64b",
"unicode_decimal": 58955
},
{
"icon_id": "2684435",
"name": "水平居中对齐",
"font_class": "shuipingjuzhongduiqi",
"unicode": "e600",
"unicode_decimal": 58880
},
{
"icon_id": "2791240",
"name": "左对齐",
"font_class": "zuoduiqi",
"unicode": "e67f",
"unicode_decimal": 59007
},
{
"icon_id": "4297547",
"name": "居中对齐",
"font_class": "card-text-center",
"unicode": "e632",
"unicode_decimal": 58930
},
{
"icon_id": "4875059",
"name": "上对齐",
"font_class": "shangduiqi",
"unicode": "e64e",
"unicode_decimal": 58958
},
{
"icon_id": "4875066",
"name": "左对齐",
"font_class": "zuoduiqi2",
"unicode": "e650",
"unicode_decimal": 58960
},
{
"icon_id": "5003035",
"name": "右对齐",
"font_class": "youduiqi1",
"unicode": "e60e",
"unicode_decimal": 58894
},
{
"icon_id": "5003037",
"name": "左对齐",
"font_class": "zuoduiqi1",
"unicode": "e60f",
"unicode_decimal": 58895
},
{
"icon_id": "8074641",
"name": "undo",
"font_class": "Undo",
"unicode": "e603",
"unicode_decimal": 58883
},
{
"icon_id": "8229624",
"name": "垂直居中对齐",
"font_class": "chuizhijuzhongduiqi",
"unicode": "e670",
"unicode_decimal": 58992
},
{
"icon_id": "8756570",
"name": "undo",
"font_class": "ic_undo",
"unicode": "e651",
"unicode_decimal": 58961
}
]
}

View File

@ -0,0 +1,62 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!--
2013-9-30: Created.
-->
<svg>
<metadata>
Created by iconfont
</metadata>
<defs>
<font id="iconfont" horiz-adv-x="1024" >
<font-face
font-family="iconfont"
font-weight="500"
font-stretch="normal"
units-per-em="1024"
ascent="896"
descent="-128"
/>
<missing-glyph />
<glyph glyph-name="youduiqi" unicode="&#58971;" d="M819.2 793.6l51.2 0 0-819.2-51.2 0 0 819.2ZM358.4 691.2l409.6 0 0-256-409.6 0 0 256ZM716.8 332.8l0-204.8L204.8 128l0 204.8L716.8 332.8M768 384 153.6 384l0-307.2 614.4 0L768 384 768 384z" horiz-adv-x="1024" />
<glyph glyph-name="xiaduiqi" unicode="&#58955;" d="M896 96v-48H128v48h768zM848 528V144h-240V528h240zM464 672v-480H272v480h192m48 48H224V144H512V720z" horiz-adv-x="1024" />
<glyph glyph-name="shuipingjuzhongduiqi" unicode="&#58880;" d="M486.40000000000015-25.600000000000136l-5.684341886080802e-14 102.4 51.2 2.842170943040401e-14 5.684341886080802e-14-102.4-51.2-2.842170943040401e-14ZM486.40000000000003 383.9999999999999l-2.2737367544323206e-13 409.6 51.2 2.842170943040401e-14 2.2737367544323206e-13-409.6-51.2-2.842170943040401e-14ZM332.79999999999995 435.19999999999993l-1.1368683772161603e-13 256 358.4 1.7053025658242404e-13 1.1368683772161603e-13-256-358.4-1.7053025658242404e-13ZM256.00000000000006 332.79999999999995l512 2.2737367544323206e-13L768 128.0000000000001 256.00000000000006 128 256.00000000000006 332.79999999999995M204.79999999999995 384L204.80000000000024 76.79999999999984l614.3999999999999 2.2737367544323206e-13-1.1368683772161603e-13 307.19999999999993L204.79999999999995 384 204.79999999999995 384z" horiz-adv-x="1024" />
<glyph glyph-name="zuoduiqi" unicode="&#59007;" d="M153.6 716.8h51.2v-665.6h-51.2zM870.4 358.4v-307.2H256V358.4h614.4z m-51.2-256V307.2H307.2v-204.8h512zM281.6 691.2h358.4v-256H281.6zM665.6 716.8v-307.2H256V716.8h409.6z m-51.2-256V665.6H307.2v-204.8h307.2z" horiz-adv-x="1024" />
<glyph glyph-name="card-text-center" unicode="&#58930;" d="M73.142857 18.285713999999984h1097.142857c43.885714 0 73.142857-29.257143 73.142857-73.142857s-29.257143-73.142857-73.142857-73.142857H73.142857c-43.885714 0-73.142857 29.257143-73.142857 73.142857s29.257143 73.142857 73.142857 73.142857zM321.828571 310.85714299999995h599.771429c43.885714 0 73.142857-29.257143 73.142857-73.142857s-29.257143-73.142857-73.142857-73.142857H321.828571c-43.885714 0-73.142857 29.257143-73.142857 73.142857s29.257143 73.142857 73.142857 73.142857zM197.485714 603.4285709999999h848.457143c43.885714 0 73.142857-29.257143 73.142857-73.142857s-29.257143-73.142857-73.142857-73.142857H197.485714c-43.885714 0-73.142857 29.257143-73.142857 73.142857s29.257143 73.142857 73.142857 73.142857zM446.171429 896h351.085714c43.885714 0 73.142857-29.257143 73.142857-73.142857s-29.257143-73.142857-73.142857-73.142857H446.171429c-43.885714 0-73.142857 29.257143-73.142858 73.142857s29.257143 73.142857 73.142858 73.142857z" horiz-adv-x="1243" />
<glyph glyph-name="shangduiqi" unicode="&#58958;" d="M95.001 696.75v52.125H929v-52.125H95.001z m469.124-469.125v417H824.75v-416.999H564.125zM459.875 592.5v-521.25h-208.5V592.5h208.5M512 644.625H199.23v-625.499H512V644.625z" horiz-adv-x="1024" />
<glyph glyph-name="zuoduiqi2" unicode="&#58960;" d="M199.25-32.999h-52.125V800.999h52.125v-833.998z m469.125 469.124h-417V696.75h416.999v-260.625zM303.5 331.875h521.25v-208.5H303.5v208.5M251.375 384v-312.77h625.499V384H251.375z" horiz-adv-x="1024" />
<glyph glyph-name="youduiqi1" unicode="&#58894;" d="M347.46496 845.91744v-49.81248c0-27.44704 22.29376-49.81376 50.0864-49.81376h701.9904c27.6608 0 50.0864 22.30144 50.0864 49.81376V845.91744c0 27.51232-22.4256 49.81376-50.0864 49.81376h-701.696c-27.70944 0-50.21824-22.25536-50.3808-49.81376zM116.3712 554.67648v-49.81248c0-27.34848 22.29248-49.81376 50.0864-49.81376h952.51712c27.6608 0 50.0864 22.30144 50.0864 49.81376V554.6752c0 27.51232-22.4256 49.81376-50.0864 49.81376H166.4576a49.93152 49.93152 0 0 1-35.50336-14.5024 49.3824 49.3824 0 0 1-14.58304-35.31136z m339.24864-241.42464c-27.73248 0.05376-50.272-22.2336-50.3808-49.81376v-49.81376c0-27.44576 22.4896-49.81376 50.18496-49.81376h651.80544c27.6544 0.05376 50.07616 22.30912 50.18368 49.81376V263.4368c0 27.34848-22.4896 49.81376-50.18368 49.81376h-651.6096zM51.20384 22.01088C23.47008 22.06464 0.92928-0.22144 0.82176-27.8016v-49.81248c0-27.44704 22.4896-49.81376 50.18368-49.81376h1052.88576c27.66208 0 50.0864 22.30144 50.0864 49.81376v49.81248c0 27.51232-22.42432 49.81376-50.0864 49.81376H51.20256z" horiz-adv-x="1169" />
<glyph glyph-name="zuoduiqi1" unicode="&#58895;" d="M0.832 847.08608v-48.65024c0-26.80576 22.5728-48.6528 50.7136-48.6528h710.76352c28.00768 0 50.71232 21.78304 50.71232 48.6528V847.08608c0 26.86976-22.70464 48.6528-50.71232 48.6528H51.84256C23.78752 895.7376 0.9984 874.00064 0.83328 847.0848z m0.29952-292.288v-48.65152c0-26.70976 22.57152-48.65152 50.71104-48.65152H1016.2688c28.0064 0 50.71232 21.78176 50.71232 48.6528v48.65024c0 26.86848-22.70464 48.65152-50.7136 48.65152H51.84384c-13.47328 0.0768-26.4192-5.02528-35.94624-14.16576C6.368 580.14464 1.0496 567.7248 1.13152 554.79808z m50.71104-243.44704C23.76448 311.40352 0.94208 289.6384 0.83328 262.69952v-48.65024c0-26.80576 22.7712-48.6528 50.81088-48.6528h659.95264c28.00128 0.05376 50.70208 21.78944 50.81216 48.6528v48.65024c0 26.71104-22.7712 48.6528-50.81216 48.6528H51.84256z m0-292.384C23.76448 19.01952 0.94208-2.74688 0.83328-29.68448v-48.65024c0-26.80576 22.7712-48.6528 50.81088-48.6528h1066.048c28.0064 0 50.71104 21.78304 50.71104 48.6528v48.65024c0 26.86976-22.70464 48.65152-50.71104 48.65152H51.84256z" horiz-adv-x="1168" />
<glyph glyph-name="Undo" unicode="&#58883;" d="M1023.99732 9.762c-4.13 223.3-169.472 551.151-511.966 561.698V759.467a17.067 17.067 0 1 1-26.317 14.37L7.84832 466.637a17.033 17.033 0 0 1-0.683-28.228L485.03132 97.075A17.135 17.135 0 0 1 512.03132 110.933V298.36c252.28-9.898 475.648-235.28 477.833-289.006l0.034-1.093a17.1 17.1 0 0 1 17.066-16.793h0.137a17.067 17.067 0 0 1 16.93 17.066l-0.034 1.23zM494.96432 332.8a17.067 17.067 0 0 1-17.066-17.067v-171.622L47.51032 451.516 477.89832 728.2v-173.534a17.067 17.067 0 0 1 17.066-17.067c279.552 0 447.898-238.763 486.469-447.317C895.48532 193.673 692.63032 332.8 494.96432 332.8z" horiz-adv-x="1024" />
<glyph glyph-name="chuizhijuzhongduiqi" unicode="&#58992;" d="M0.512 422.7072h125.8496v-61.44H0.512v61.44zM504.0128 422.7072h503.5008v-61.44H504.0128v61.44zM566.9376 607.0272h314.6752v-430.08h-314.6752zM441.0368 699.1872v-614.4H189.2864v614.4h251.7504z m62.976 61.44H126.3616v-737.28h377.6512v737.28z" horiz-adv-x="1024" />
<glyph glyph-name="ic_undo" unicode="&#58961;" d="M484.308604 648.193618v247.831671L0 456.655142 484.308604 17.209128V282.945372c134.562481 0 550.186308 0 729.560802-410.920083v45.646547c0 182.636768-179.399783 769.390892-729.560802 730.521782z" horiz-adv-x="1213" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,35 @@
<template>
<svg
:class="{active: active}"
class="icon el-icon cursor-p" aria-hidden="true">
<use :xlink:href="'#icon-' + icon"></use>
</svg>
</template>
<script>
import './iconfont.js'
export default {
props: {
icon: {
type: String,
required: true
},
active: {
type: Boolean,
default: false
}
}
}
</script>
<style lang="scss">
.icon{
font-size: 18px;
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: rgba(0,0,0,0.5);
overflow: hidden;
&.active{
fill: rgba(0,0,0,1);
}
}
</style>

View File

@ -0,0 +1,39 @@
<template>
<img
v-if="value"
:style="{
transform: `scale(${needScale ? dZoom : 1})`
}"
class="img-widget-ct"
:src="value"
/>
</template>
<script>
export default {
props: {
value: {
type: String,
required: true
},
// 解决chrome字体无法更小的问题
needScale: {
type: Boolean,
default: false
},
dZoom: {
type: Number,
required: true
}
},
created() {
console.log(this.value);
}
};
</script>
<style lang="scss">
.img-widget-ct {
width: 100%;
height: 100%;
user-select: none;
}
</style>

View File

@ -0,0 +1,11 @@
import 'element-ui/lib/theme-chalk/index.css'
import Vue from 'vue'
import ElementUI from 'element-ui'
import './assets/reset.css'
import './assets/common.scss'
import PosterEditor from './index.vue'
Vue.use(ElementUI)
PosterEditor.install = function (Vue) {
Vue.component(PosterEditor.name, PosterEditor)
}
export default PosterEditor

View File

@ -0,0 +1,750 @@
<template>
<div class="poster-editor-comp" :id="editorUid">
<div class="main-pane" :style="{ minHeight: 720 * dZoom + 58 + 'px' }">
<div class="header-ct">
<div class="left">
<el-tooltip effect="dark" content="撤销" placement="top-start">
<el-button
:disabled="!canClickPrev"
@click="getHistory(-1)"
type="text"
>
<Icon :active="canClickPrev" class="m-r-16" icon="Undo"></Icon>
</el-button>
</el-tooltip>
<el-tooltip effect="dark" content="前进" placement="top-start">
<el-button
:disabled="!canClickNext"
@click="getHistory(1)"
type="text"
>
<Icon :active="canClickNext" class="mirror" icon="Undo"></Icon>
</el-button>
</el-tooltip>
</div>
<div class="center">
轻点元素开始编辑
</div>
<div class="right">
<el-button @click="submitImg">提交</el-button>
</div>
</div>
<draggable
ref="posterContent"
v-bind="getOptions()"
@end="isDragging = false"
@start="isDragging = true"
:style="{
width: dZoom * page.width + 'px',
height: dZoom * page.height + 'px',
backgroundColor: value.background.color
}"
class="poster-content m-b-16"
tag="div"
>
<img class="bg-puppet" :src="value && value.background.img" />
<widget
:class="{ disabled: !item.active }"
@click.native="handleActiveWidget(item)"
@dragstart.native="dragStart($event, item)"
@dragend.native="dragEnd($event, item, index)"
@modify="pushHistory"
:widget-data="item"
:order="index"
:page="page"
:d-zoom="dZoom"
:key="item.uuid"
v-for="(item, index) in widgetList"
>
</widget>
</draggable>
</div>
<div class="right-pane">
<el-tabs>
<el-tab-pane label="当前组件">
<div v-if="activeWidget" class="style-setting-ct">
<el-collapse v-model="activeNames">
<el-collapse-item
v-if="activeWidget.setDataRange.content.show"
title="文本内容"
name="1"
>
<div class="style-config m-r-16">
<el-input
v-model="activeWidget.content"
type="textarea"
></el-input>
</div>
</el-collapse-item>
<el-collapse-item
v-if="activeWidget.setDataRange.box.show"
title="组件样式"
name="2"
>
<div class="style-config">
<span class="label">
X
</span>
<el-input-number
:precision="0"
v-model="activeWidget.style.left"
class="w-60"
:controls="false"
size="mini"
></el-input-number>
<span class="label">
Y
</span>
<el-input-number
:precision="0"
v-model="activeWidget.style.top"
class="w-60"
:controls="false"
size="mini"
></el-input-number>
</div>
<div class="style-config">
<span class="label">
宽度
</span>
<el-input-number
v-model="activeWidget.style.width"
class="w-60"
:controls="false"
size="mini"
></el-input-number>
<span class="label">
高度
</span>
<el-input-number
v-model="activeWidget.style.height"
class="w-60"
:controls="false"
size="mini"
></el-input-number>
</div>
<div class="style-config">
<template
v-if="activeWidget.setDataRange.box.detail.background"
>
<span class="label">
背景色
</span>
<el-color-picker
v-model="activeWidget.style.background"
class="w-60"
show-alpha
size="mini"
></el-color-picker>
</template>
<span class="label">
层级
</span>
<el-input-number
disabled
:value="activeWidget.style.zIndex"
class="w-60"
:controls="false"
size="mini"
></el-input-number>
</div>
<div class="style-config">
<!-- <span class="label">
对齐
</span>
{{activeWidget.style.textAlign}}-->
</div>
</el-collapse-item>
<el-collapse-item
v-if="activeWidget.setDataRange.innerStyle.show"
title="字体样式"
name="3"
>
<div class="style-config">
<span class="label">
大小
</span>
<el-input-number
v-model="activeWidget.style.fontSize"
class="w-60"
:controls="false"
size="mini"
></el-input-number>
<span class="label">
行高
</span>
<el-input-number
v-model="activeWidget.style.lineHeight"
class="w-60"
:controls="false"
size="mini"
></el-input-number>
</div>
<div class="style-config">
<span class="label">
字距
</span>
<el-input-number
v-model="activeWidget.style.letterSpacing"
class="w-60"
:controls="false"
size="mini"
></el-input-number>
<span class="label">
颜色
</span>
<el-color-picker
v-model="activeWidget.style.color"
class="w-60"
show-alpha
size="mini"
></el-color-picker>
</div>
<div class="style-config">
<!--<span class="label">
对齐
</span>
<el-input-number class="w-60" :controls="false" size="mini"></el-input-number>-->
<!-- <span class="label">
字体
</span>
<el-input-number class="w-60" :controls="false" size="mini"></el-input-number>-->
</div>
<div class="style-config">
<span class="label">
对齐
</span>
<align-select
v-model="activeWidget.style.align"
></align-select>
</div>
<div class="style-config">
<span class="label">其他</span>
<span
:class="{ active: activeWidget.style.isBold }"
@click="handleOtherClick('isBold')"
class="cursor-p other"
><b>B</b></span
>
<span
:class="{ active: activeWidget.style.isOblique }"
@click="handleOtherClick('isOblique')"
class="m-l-8 cursor-p other"
><i>I</i></span
>
<span></span>
</div>
</el-collapse-item>
</el-collapse>
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script>
import _ from 'lodash';
import draggable from 'vuedraggable';
import uuid from 'uuid';
import html2canvas from 'html2canvas';
import { Loading } from 'element-ui';
import alignSelect from './alignSelect';
import widget from './widget';
import blankDialog from '@/components/blankDialog';
import imageSelection from '@/components/imageSelection';
import { setDataRangeMap, defaultDataMap } from './widgetInitDataMap';
import Icon from './icon/index';
import { qrUpdate } from '@/api/index';
import VueQr from 'vue-qr';
let zIndex = 0;
export default {
name: 'posterEditor',
props: {
order: {
type: Number,
required: true
},
id: {
type: String,
required: true
},
value: {
type: Object,
required: true
},
page: {
type: Object,
default() {
return {
width: 375,
height: 620
};
}
}
},
components: {
widget,
draggable,
alignSelect,
blankDialog,
imageSelection,
Icon,
VueQr
},
data() {
return {
editorUid: 'uid' + uuid(),
dZoom: 0.52,
isDragging: false,
activeNames: ['1', '2', '3', '4', '5', '6'],
widgetList: [],
dragStartPosition: null,
widgetDragStart: null, // 当前拖的是哪个文本图层 便于后期交互值
handleResizeFn: null,
handleActiveWidgetChange: null,
showImageSelection: false,
showImageSelectionWidget: false,
widgetHistory: [], // 记录历史记录变动的
historyIndex: -1
};
},
methods: {
submitImg() {
// const
console.log(this.id);
// qrUpdate(this.value).then(res => {
// console.log(res);
// });
},
beforeAddImgWidget(imgObj) {
this.addWidget('img', imgObj.path);
this.showImageSelectionWidget = false;
},
addWidget(type, path) {
zIndex++;
const typeLabelMap = {
text: '文本',
img: '图片'
};
const item = {
label: typeLabelMap[type],
type,
content: type === 'text' ? '文本' : path,
uuid: uuid(),
active: false,
setDataRange: setDataRangeMap[type],
style: {
...defaultDataMap[type],
zIndex
}
};
this.widgetList.push(item);
this.$nextTick(() => {
this.handleActiveWidget(item);
});
console.log(this.value);
this.$emit('input', {
background: this.value.background,
widgetList: this.widgetList
});
this.pushHistory('add', item, this.widgetList.length - 1);
},
handleActiveWidget(item) {
this.widgetList.forEach(w => {
if (item.uuid === w.uuid) {
w.active = !item.active;
} else {
w.active = false;
}
});
},
getOptions() {
return {
filter: '.disabled'
};
},
dragStart(e) {
this.dragStartPosition = {
pageX: e.pageX,
pageY: e.pageY
};
},
dragEnd(e, item, index) {
item.history = {
content: item.content,
style: _.cloneDeep(item.style)
};
let target = item.style;
let left = (e.pageX - this.dragStartPosition.pageX) / this.dZoom;
let top = (e.pageY - this.dragStartPosition.pageY) / this.dZoom;
target.left = Math.max(
Math.min(left + target.left, this.page.width - target.width),
0
);
target.top = Math.max(
Math.min(top + target.top, this.page.height - target.height),
0
);
this.pushHistory('modify', item, index);
},
deleteWidget(item) {
let index = this.widgetList.findIndex(v => v.uuid === item.uuid);
if (index > -1) {
this.$confirm(
`此操作将永久删除该${item.label}图层, 是否继续?`,
'警告',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
this.widgetList.splice(index, 1);
this.pushHistory('delete', item, index);
});
}
},
handleOtherClick(key) {
this.activeWidget.style[key] = !this.activeWidget.style[key];
},
dragZIndexStart(item) {
this.widgetDragStart = item;
},
dragZIndexEnd(item) {
let tmp = item.style.zIndex;
item.style.zIndex = this.widgetDragStart.style.zIndex;
this.widgetDragStart.style.zIndex = tmp;
this.widgetDragStart = null;
},
getDZoom() {
// const currentEditorBox = document.querySelector(`#${this.editorUid}`).getBoundingClientRect()
// fix v-show隐藏元素宽度太小的问题
const currentEditorBox = document
.querySelector(`.poster-editor-comp`)
.getBoundingClientRect();
let width = currentEditorBox.width - 32 - 295;
if (width >= 480) {
this.dZoom = Number((width / 960).toFixed(2));
}
if (width >= 960) {
this.dZoom = 1;
}
},
// 上传当前poster截图
uploadCurrentPosterShot(cb) {
let instance = Loading.service({
text: '保存中,请稍候!',
background: 'rgba(0, 0, 0, 0.5)'
});
console.time('1');
this.widgetList.forEach(w => {
w.active = false;
});
return new Promise(resolve => {
// 激活当前编辑器 方便截图
this.$emit('active');
this.$nextTick(() => {
html2canvas(
document
.querySelector(`#${this.editorUid}`)
.querySelector('.poster-content'),
{
useCORS: true,
// 编辑器缩放保持 960 * 720 的尺寸
scale: 1 / this.dZoom
}
).then(async canvas => {
console.timeEnd('1');
console.time('2');
let file = canvas
.toDataURL('image/jpeg', 1)
.replace('data:image/jpeg;base64,', '');
// base64的图片
console.timeEnd('2');
console.time('3');
if (cb) {
await cb(file, resolve);
console.timeEnd('3');
instance.close();
}
});
});
});
},
changeBackground(imgUrl) {
console.log((this.value.background.img = imgUrl));
// this.value.background = imgUrl;
// this.value.material_uid = imgObj.uid;
// this.value.materialType = imgObj.expandType;
this.showImageSelection = false;
},
changeTextColor(color) {
this.value.background.color = color;
console.log(this.value.background);
},
pushHistory(type, item, index) {
const obj = {
uuid: item.uuid,
item,
index,
type
};
if (this.canClickNext) {
// 已经执行过撤销的操作了 再添加历史记录把后面的删除掉
this.widgetHistory.length = this.historyIndex + 1;
}
this.widgetHistory.push(obj);
this.historyIndex = this.widgetHistory.length - 1;
/* switch (type) {
case 'add':
obj.type = 'add'
this.historyIndex = this.widgetHistory.length - 1
break
case 'delete':
obj.type = 'delete'
this.widgetHistory.push(obj)
this.historyIndex = this.widgetHistory.length
break
case 'modify':
break
} */
},
getHistory(num) {
if ((num < 0 && this.canClickPrev) || (num > 0 && this.canClickNext)) {
if (num > 0) this.historyIndex += num;
let historyObj = this.widgetHistory[this.historyIndex];
switch (historyObj.type) {
case 'add':
// 撤回操作
if (num < 0) {
let index = this.widgetList.findIndex(
v => v.uuid === historyObj.uuid
);
if (index > -1) {
this.widgetList.splice(index, 1);
}
} else {
this.widgetList.push(historyObj.item);
}
break;
case 'delete':
if (num < 0) {
this.widgetList.splice(historyObj.index, 0, historyObj.item);
} else {
this.widgetList.splice(historyObj.index, 1);
}
break;
case 'modify':
if (num < 0) {
this.$set(this.widgetList, historyObj.index, {
...historyObj.item,
style: historyObj.item.history.style,
content: historyObj.item.history.content
});
} else {
this.$set(this.widgetList, historyObj.index, {
...historyObj.item
});
}
}
if (num < 0) {
this.historyIndex += num;
}
// this.widgetHistory[this.historyIndex - 1]
}
}
},
computed: {
activeWidget() {
return this.widgetList.find(w => w.active);
},
sortWidgetList() {
return this.widgetList
.slice(0)
.sort((a, b) => b.style.zIndex - a.style.zIndex);
},
canClickPrev() {
// 是否能点击上一步
return this.historyIndex > -1;
},
canClickNext() {
return (
this.historyIndex < this.widgetHistory.length - 1 &&
this.widgetHistory.length > 0
);
}
},
watch: {
widgetList: {
handler(val) {
zIndex = val.length;
val.forEach((v, i) => {
v.style.zIndex = i + 1;
});
this.$emit('input', {
background: this.value.background,
widgetList: this.widgetList
});
},
deep: true
},
'value.widgetList': {
handler(val) {
if (val !== this.widgetList) {
this.widgetList = val;
}
},
deep: true
}
},
mounted() {
this.getDZoom();
this.handleResizeFn = _.throttle(this.getDZoom, 100);
window.addEventListener('resize', this.handleResizeFn);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResizeFn);
},
created() {
this.widgetList = this.value.widgetList || [];
this.widgetList.forEach(v => {
v.history = {
content: v.content,
style: _.cloneDeep(v.style)
};
});
}
};
</script>
<style lang="scss" scoped>
.w-60 {
width: 60px !important;
}
.poster-editor-comp {
display: flex;
min-width: 830px;
.main-pane {
position: relative;
flex: 1;
padding: 0 16px;
.header-ct {
display: flex;
height: 40px;
align-items: center;
text-align: center;
.left {
display: flex;
align-items: center;
.mirror {
transform: rotateY(180deg);
}
}
.center {
flex: 1;
}
}
.poster-content {
top: 40px;
left: 50%;
position: absolute;
/*min-width: 480px;
min-height: 360px;
max-width: 960px;
max-height: 720px;*/
width: 960px;
height: 720px;
/* margin: 0 auto;*/
transform: translateX(-50%);
&:hover {
outline: 1px solid grey;
}
transform-origin: 0 0;
background-size: 100% 100% !important;
.bg-puppet {
width: 100%;
height: 100%;
z-index: -1;
}
}
}
.right-pane {
box-sizing: border-box;
width: 295px;
padding-left: 16px;
border: 1px solid #e4e4e4;
background: #fff;
z-index: 900;
.header-ct {
display: flex;
justify-content: flex-end;
align-items: center;
height: 40px;
}
.style-setting-ct {
.style-config {
display: flex;
align-items: center;
margin-bottom: 8px;
padding-left: 16px;
.label {
display: inline-block;
margin-left: 8px;
width: 48px;
text-align: left;
}
.other {
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
font-size: 18px;
color: rgba(0, 0, 0, 0.8);
&.active {
background: rgba(0, 0, 0, 0.8);
color: white;
}
}
}
}
.widget-zIndex-config-ct {
.widget-list-item {
cursor: move;
}
.item {
position: relative;
display: flex;
align-items: center;
height: 40px;
border-bottom: 1px solid #e1e1e1;
font-size: 14px;
.delete-btn {
position: absolute;
display: none;
transition: all 200ms linear;
}
&:hover .delete-btn {
display: block;
}
.view {
margin-left: 40px;
width: 24px;
height: 18px;
background-size: 100% 100% !important;
border: 1px solid rgba(0, 0, 0, 0.3);
}
.desc {
font-size: 14px;
}
}
.bg {
.view {
margin-left: 24px;
}
}
}
}
}
</style>

View File

@ -0,0 +1,33 @@
<template>
<div
:style="{
transform: `scale(${needScale ? dZoom : 1})`
}"
class="text-widget-ct">
{{value}}
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
required: true
},
// 解决chrome字体无法更小的问题
needScale: {
type: Boolean,
default: false
},
dZoom: {
type: Number,
required: true
}
}
}
</script>
<style lang="scss">
.text-widget-ct {
user-select: none;
}
</style>

View File

@ -0,0 +1,95 @@
<template>
<div
:style="{
...getStyleRaw
}"
class="widget-ct cursor-p"
>
<widgetWrapper
:d-zoom="dZoom"
:page="page"
:show-wrapper="showWrapper"
:widget-data="widgetData"
:widget-name="widgetData.type"
>
<vue-qr text="123" :size="140"></vue-qr>
</widgetWrapper>
<widgetWrapper
:d-zoom="dZoom"
:page="page"
:show-wrapper="showWrapper"
:widget-data="widgetData"
:widget-name="widgetData.type"
>
<component
:need-scale="widgetData.type === 'text' && !showWrapper"
:d-zoom="dZoom"
v-model="widgetData.content"
:is="childName"
></component>
</widgetWrapper>
</div>
</template>
<script>
import VueQr from 'vue-qr';
import widgetWrapper from './widgetWrapper';
import textWidget from './textWidget';
import imgWidget from './imgWidget';
export default {
created() {
console.log(this.dZoom);
console.log(this.widgetData);
console.log(this.showWrapper);
console.log(this.page);
},
props: {
dZoom: {
type: Number,
required: true
},
widgetData: {
type: Object,
required: true
},
order: {
type: Number
},
showWrapper: {
type: Boolean,
default: true
},
page: {
type: Object
}
},
computed: {
getStyleRaw() {
let obj = {};
let style = this.widgetData.style;
let zIndex = style.zIndex;
for (let key in style) {
obj[key] =
typeof style[key] === 'number'
? style[key] * this.dZoom + 'px'
: style[key];
}
obj.zIndex = zIndex;
return obj;
},
childName() {
return this.widgetData.type + 'Widget';
}
},
components: {
widgetWrapper,
textWidget,
imgWidget,
VueQr
}
};
</script>
<style lang="scss">
.widget-ct {
position: absolute;
}
</style>

View File

@ -0,0 +1,94 @@
const setDataRangeMap = {
text: {
box: {
show: true,
detail: {
top: true,
left: true,
height: true,
width: true,
background: true,
zIndex: true
}
},
content: {
show: true
},
innerStyle: {
show: true,
detail: {
align: true,
lineHeight: true,
fontSize: true,
color: true,
letterSpacing: true,
isOblique: true,
isBold: true
}
}
},
img: {
box: {
show: true,
detail: {
top: true,
left: true,
height: true,
width: true,
background: false,
zIndex: true
}
},
content: {
show: false
},
innerStyle: {
show: false,
detail: {
align: true,
lineHeight: true,
fontSize: true,
color: true,
letterSpacing: true,
isOblique: true,
isBold: true
}
}
}
}
const defaultDataMap = {
text: {
top: 0,
left: 0,
height: 40,
width: 100,
align: {
x: 2,
y: 2
},
// textAlign: 'center',
lineHeight: 14,
fontSize: 14,
background: 'rgba(0, 0, 0, 0)',
color: 'rgba(0, 0, 0, 1)',
letterSpacing: 0,
isOblique: false,
isBold: false
},
img: {
top: 0,
left: 0,
height: 40,
width: 100,
align: {
x: 2,
y: 2
}
}
}
export {
setDataRangeMap,
defaultDataMap
}

View File

@ -0,0 +1,240 @@
<template>
<div
:style="{
'font-weight': widgetData.style.isBold ? 'bold' : 'normal',
'font-style': widgetData.style.isOblique ? 'oblique' : 'normal',
'justify-content': alignMap[widgetData.style.align.x],
'align-items': alignMap[widgetData.style.align.y]
}"
:class="{active: showWrapper && widgetData.active}"
class="widget-wrapper">
<template v-if="showWrapper && widgetData.active">
<div
@mousedown.stop="handleMouseDown($event, item.cursor)"
:style="item"
:key="i"
v-for="(item, i) in sizeControls"
class="square"></div>
</template>
<slot></slot>
</div>
</template>
<script>
export default {
props: {
widgetData: {
type: Object,
required: true
},
showWrapper: {
type: Boolean,
default: true
},
dZoom: {
type: Number,
required: true
},
page: {
type: Object
}
},
data () {
return {
// 调整尺寸用的
sizeControls: [
// 左上
{
top: 0,
left: 0,
cursor: 'nw-resize'
},
{
top: 0,
left: '50%',
cursor: 'n-resize'
},
{
top: 0,
left: '100%',
cursor: 'ne-resize'
},
{
top: '50%',
left: '100%',
cursor: 'e-resize'
},
{
top: '100%',
left: '100%',
cursor: 'se-resize'
},
{
top: '100%',
left: '50%',
cursor: 's-resize'
},
{
top: '100%',
left: 0,
cursor: 'sw-resize'
},
{
top: '50%',
left: 0,
cursor: 'w-resize'
}
],
dMouseXY: {},
dActiveWidgetXY: {},
dResizeWH: {},
dirs: [],
// 对齐方式
alignMap: {
1: 'flex-start',
2: 'center',
3: 'flex-end'
},
isMoving: false
}
},
methods: {
handleMouseDown (e, cursor) {
const dirMap = {
n: 'top',
s: 'bottom',
e: 'right',
w: 'left'
}
let first = cursor[0]
let second = cursor[1]
this.dirs = []
this.dirs.push(dirMap[first])
if (/[swen]/.test(second)) {
this.dirs.push(dirMap[second])
}
e.stopPropagation()
this.initDResize({
startX: e.pageX,
startY: e.pageY,
originX: this.widgetData.style.left,
originY: this.widgetData.style.top,
width: this.widgetData.style.width,
height: this.widgetData.style.height
})
document.addEventListener('mousemove', this.handleMouseMove, true)
document.addEventListener('mouseup', this.handleMouseUp, true)
},
initDResize (payload) {
let mouseXY = this.dMouseXY
let widgetXY = this.dActiveWidgetXY
let resizeWH = this.dResizeWH
mouseXY.x = payload.startX
mouseXY.y = payload.startY
widgetXY.x = payload.originX
widgetXY.y = payload.originY
resizeWH.width = payload.width
resizeWH.height = payload.height
},
// 更新组件宽高
dResize ({ x, y, dirs }) {
let page = this.page
let target = this.widgetData.style
let mouseXY = this.dMouseXY
let widgetXY = this.dActiveWidgetXY
let resizeWH = this.dResizeWH
let parent = this.$parent
if (target.parent !== '-1') {
// parent = store.state.dWidgets.find(item => item.uuid === target.parent)
}
let dx = x - mouseXY.x
let dy = y - mouseXY.y
let left = 0
let top = 0
const minWidth = 20
for (let i = 0; i < dirs.length; ++i) {
let dir = dirs[i]
switch (dir) {
case 'top':
let t = widgetXY.y + Math.floor(dy / this.dZoom)
top = Math.max(t, 0)
top = Math.min(widgetXY.y + resizeWH.height - target.fontSize, top)
target.height += (target.top - top)
target.height = Math.max(target.height, target.fontSize)
target.top = top
break
case 'bottom':
top = Math.floor(dy / this.dZoom)
target.height = Math.max(Math.min(resizeWH.height + top, page.height - target.top), 40)
break
case 'left':
let tLeft = widgetXY.x + Math.floor(dx / this.dZoom)
left = Math.max(tLeft, 0)
target.width += (target.left - left)
target.width = Math.max(target.width, minWidth)
left = Math.min(widgetXY.x + resizeWH.width - minWidth, left)
target.left = left
break
case 'right':
left = Math.floor(dx / this.dZoom) // 实际偏移量
target.width = Math.max(Math.min(resizeWH.width + left, page.width - target.left), minWidth)
break
}
}
if (parent.uuid !== '-1') {
// store.dispatch('updateGroupSize', parent.uuid)
}
// store.dispatch('reChangeCanvas')
},
// 组件调整结束
stopDResize (store) {
/* if (store.state.dResizeing) {
store.dispatch('pushHistory')
}
store.state.dResizeing = false */
},
handleMouseMove (e) {
e.stopPropagation()
e.preventDefault()
this.dResize({
x: e.pageX,
y: e.pageY,
dirs: this.dirs
})
},
handleMouseUp () {
document.removeEventListener('mousemove', this.handleMouseMove, true)
document.removeEventListener('mouseup', this.handleMouseUp, true)
this.stopDResize()
}
}
}
</script>
<style lang="scss">
.widget-wrapper{
display: flex;
box-sizing: border-box;
width: 100%;
height: 100%;
position: relative;
&.active, &.active:hover{
border: 1px dashed;
}
.square{
box-sizing: border-box;
position: absolute;
width: 8px;
height: 8px;
z-index: 999;
background-color: #fff;
outline: 1px solid #3b74f1;
transform: translateX(-50%) translateY(-50%);
}
}
</style>