feat: 组件解偶 使用继承

This commit is contained in:
fit2cloud-chenyw 2021-03-31 18:23:43 +08:00
parent 79d37827a4
commit ebf90fb02a
23 changed files with 698 additions and 61 deletions

View File

@ -22,6 +22,7 @@
"fit2cloud-ui": "^0.1.12",
"js-cookie": "2.2.0",
"jsencrypt": "^3.0.0-rc.1",
"lodash": "4.17.21",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"screenfull": "4.2.0",

View File

@ -24,14 +24,14 @@
:index="index"
:class="{ lock: item.isLock }"
>
<component
:is="item.component"
v-if="item.component !== 'v-text'"
<de-drawing-widget
v-if="item.type==='custom'"
:id="'component' + item.id"
class="component"
:style="getComponentStyle(item.style)"
:prop-value="item.propValue"
:element="item"
:item="item"
/>
<component
@ -42,8 +42,17 @@
:style="getComponentStyle(item.style)"
:prop-value="item.propValue"
:element="item"
@input="handleInput"
/>
<!-- <component
:is="item.component"
v-else
:id="'component' + item.id"
class="component"
:style="getComponentStyle(item.style)"
:prop-value="item.propValue"
:element="item"
@input="handleInput"
/> -->
</Shape>
<!-- 右击菜单 -->
<ContextMenu />

View File

@ -0,0 +1,43 @@
<template>
<el-button
v-if="options!== null && options.attrs!==null"
:type="options.attrs.type"
:round="options.attrs.round"
>
{{ options.value }}
</el-button>
</template>
<script>
export default {
props: {
options: {
type: Object,
default: null
}
},
data() {
return {
}
},
mounted() {
this.$nextTick(() => {
// this.defaultOptions = Object.assign({}, this.options)
// const dom = this.$refs[this.options.refId]
// for (const key in this.options.attrs) {
// if (Object.hasOwnProperty.call(this.defaultOptions.attrs, key)) {
// const element = this.defaultOptions.attrs[key]
// dom.$props[key] = element
// }
// }
})
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,27 @@
<template>
<el-date-picker
v-if="options!== null && options.attrs!==null"
v-model="options.value"
:type="options.attrs.type"
:range-separator="options.attrs.rangeSeparator"
:start-placeholder="options.attrs.startPlaceholder"
:end-placeholder="options.attrs.endPlaceholder"
:placeholder="options.attrs.placeholder"
/>
</template>
<script>
export default {
props: {
options: {
type: Object,
default: null
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,20 @@
<script>
export default {
functional: true,
props: {
item: {
type: Object,
default: null
}
},
render(createElement, context) {
const item = context.props.item
return createElement(item.component, {
props: {
options: item.options,
element: item
}
})
}
}
</script>

View File

@ -0,0 +1,34 @@
<template>
<el-input v-if="options!== null && options.attrs!==null" v-model="options.value" style="width:260px;" :placeholder="options.attrs.placeholder">
<el-button slot="append" icon="el-icon-search" />
</el-input>
</template>
<script>
export default {
props: {
options: {
type: Object,
default: null
}
},
data() {
return {
}
},
mounted() {
this.$nextTick(() => {
})
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,24 @@
<template>
<el-quarter
v-if="options!== null && options.attrs!==null"
v-model="options.value"
:placeholder="options.attrs.placeholder"
/>
</template>
<script>
export default {
props: {
options: {
type: Object,
default: null
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,38 @@
<template>
<el-select v-if="options!== null && options.attrs!==null" v-model="options.value" :placeholder="options.attrs.placeholder">
<el-option
v-for="item in options.attrs.datas"
:key="item[options.attrs.key]"
:label="item[options.attrs.label]"
:value="item[options.attrs.value]"
/>
</el-select>
</template>
<script>
export default {
props: {
options: {
type: Object,
default: null
}
},
data() {
return {
}
},
mounted() {
this.$nextTick(() => {
})
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,32 +0,0 @@
<template>
<div>de-widget</div>
</template>
<script>
import { ApplicationContext } from '@/utils/ApplicationContext'
export default {
props: {
options: {
type: Object,
default: null
}
},
data() {
return {
widget: null
}
},
computed() {
this.widget = ApplicationContext.getService(this.options.name)
console.log(this.widget.name)
},
methods: {
onDraw() {
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,138 @@
<template>
<div>
<mark
v-show="showSeason"
style="position:fixed;top:0;bottom:0;left:0;right:0;background:rgba(0,0,0,0);z-index:999;"
@click.stop="showSeason=false"
/>
<el-input v-model="showValue" :placeholder="placeholder" style="width:138px;" @focus="showSeason=true">
<i slot="prefix" class="el-input__icon el-icon-date" />
</el-input>
<el-card
v-show="showSeason"
class="box-card"
style="width:322px;padding: 0 3px 20px;margin-top:10px;position:fixed;z-index:9999"
>
<div slot="header" class="clearfix" style="text-align:center;padding:0">
<button
type="button"
aria-label="前一年"
class="el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-d-arrow-left"
@click="prev"
/>
<span role="button" class="el-date-picker__header-label">{{ year }}</span>
<button
type="button"
aria-label="后一年"
class="el-picker-panel__icon-btn el-date-picker__next-btn el-icon-d-arrow-right"
@click="next"
/>
</div>
<div class="text item" style="text-align:center;">
<el-button
type="text"
size="medium"
style="width:40%;color: #606266;float:left;"
@click="selectSeason(0)"
>第一季度</el-button>
<el-button
type="text"
size="medium"
style="float:right;width:40%;color: #606266;"
@click="selectSeason(1)"
>第二季度</el-button>
</div>
<div class="text item" style="text-align:center;">
<el-button
type="text"
size="medium"
style="width:40%;color: #606266;float:left;"
@click="selectSeason(2)"
>第三季度</el-button>
<el-button
type="text"
size="medium"
style="float:right;width:40%;color: #606266;"
@click="selectSeason(3)"
>第四季度</el-button>
</div>
</el-card>
</div>
</template>
<script>
/**
* @file: View 组件 季节选择控件
* @author: v_zhuchun
* @date: 2019-05-23
* @description: UI组件 可选择季节
* @api: valueArr : 季度value defalut['01-03', '04-06', '07-09', '10-12'] 默认值待设置
*/
export default {
props: {
placeholder: {
type: String,
default: ''
},
valueArr: {
default: () => {
return ['01-03', '04-06', '07-09', '10-12']
},
type: Array
},
getValue: {
default: () => {},
type: Function
},
defaultValue: {
default: '',
type: String
}
},
data() {
return {
showSeason: false,
season: '',
year: new Date().getFullYear(),
showValue: ''
}
},
watch: {
defaultValue: function(value, oldValue) {
const arr = value.split('-')
this.year = arr[0].slice(0, 4)
const str = arr[0].slice(4, 6) + '-' + arr[1].slice(4, 6)
const arrAll = this.valueArr
this.showValue = `${this.year}${arrAll.indexOf(str) + 1}季度`
}
},
created() {
if (this.defaultValue) {
const value = this.defaultValue
const arr = value.split('-')
this.year = arr[0].slice(0, 4)
const str = arr[0].slice(4, 6) + '-' + arr[1].slice(4, 6)
const arrAll = this.valueArr
this.showValue = `${this.year}${arrAll.indexOf(str) + 1}季度`
}
},
methods: {
one() {
this.showSeason = false
},
prev() {
this.year = this.year * 1 - 1
},
next() {
this.year = this.year * 1 + 1
},
selectSeason(i) {
const that = this
that.season = i + 1
const arr = that.valueArr[i].split('-')
that.getValue(that.year + arr[0] + '-' + that.year + arr[1])
that.showSeason = false
this.showValue = `${this.year}${this.season}季度`
}
}
}
</script>

View File

@ -1,4 +1,36 @@
// import store from '@/store'
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
const requireComponent = require.context('./DeWidget', true, /\.vue$/)
requireComponent.keys().forEach(fileName => {
// 获取组件配置
const componentConfig = requireComponent(fileName)
// 这个地方直接传入filename其实就是内部会调用了resolve方法会返回对应的文件内容不理解可以console一下看看
// 获取组件的 PascalCase 命名
const componentName = upperFirst(
camelCase(
// 获取和目录深度无关的文件名
fileName
.split('/')
.pop()
.replace(/\.\w+$/, '')
)
)
// 全局注册组件
Vue.component(
componentName,
// 如果这个组件选项是通过 `export default` 导出的,
// 那么就会优先使用 `.default`
// 否则回退到使用模块的根。
componentConfig.default || componentConfig
)
})
const req = require.context('./serviceImpl', false, /\.js$/)
const requireAll = requireContext => requireContext.keys()

View File

@ -16,6 +16,7 @@ export class WidgetService {
options = { ...commonAttr, ...options }
Object.assign(this, options)
this.style = { ...commonStyle, ...options.style }
this.type = 'custom'
this.storeWidget()
}
storeWidget() {

View File

@ -17,8 +17,15 @@ const defaultOptions = {
color: '',
backgroundColor: ''
},
propValue: '按钮',
component: 'v-button'
component: 'de-button',
options: {
refId: '1234567890',
attrs: {
type: 'primary',
round: true
},
value: '测试按钮'
}
}
class ButtonSureServiceImpl extends WidgetService {

View File

@ -0,0 +1,48 @@
import { WidgetService } from '../service/WidgetService'
const defaultOptions = {
name: 'textInputWidget',
icon: null,
label: '文本搜索',
style: {
width: 100,
height: 34,
borderWidth: '',
borderColor: '',
borderRadius: '',
fontSize: 14,
fontWeight: 500,
lineHeight: '',
letterSpacing: 0,
textAlign: '',
color: '',
backgroundColor: ''
},
component: 'de-input-search',
options: {
refId: '1234567890',
attrs: {
placeholder: '请输入关键字'
},
value: ''
}
}
class TextInputServiceImpl extends WidgetService {
constructor(options) {
Object.assign(options, defaultOptions)
super(options)
}
initWidget() {
// console.log('this is first initWidget')
}
toDrawWidget() {
// console.log('this is first toDrawWidget')
}
// 移动到画布之前回掉
beforeToDraw() {
}
}
const textInputServiceImpl = new TextInputServiceImpl({ name: 'textInputWidget' })
export default textInputServiceImpl

View File

@ -0,0 +1,67 @@
import { WidgetService } from '../service/WidgetService'
const defaultOptions = {
name: 'textSelectWidget',
icon: null,
label: '文本下拉',
style: {
width: 200,
height: 22,
fontSize: 14,
fontWeight: 500,
lineHeight: '',
letterSpacing: 0,
textAlign: '',
color: ''
},
options: {
refId: '1234567890',
attrs: {
multiple: false,
placeholder: '请选择',
datas: [
{
id: '0',
text: '北京'
},
{
id: '1',
text: '上海'
},
{
id: '2',
text: '广东'
},
{
id: '3',
text: '深圳'
}
],
key: 'id',
label: 'text',
value: 'id'
},
value: ''
},
component: 'de-select'
}
class TextSelectServiceImpl extends WidgetService {
constructor(options) {
Object.assign(options, defaultOptions)
super(options)
}
initWidget() {
// console.log('this is first initWidget')
}
toDrawWidget() {
// console.log('this is first toDrawWidget')
}
// 移动到画布之前回掉
beforeToDraw() {
}
}
const textSelectServiceImpl = new TextSelectServiceImpl({ name: 'textSelectWidget' })
export default textSelectServiceImpl

View File

@ -0,0 +1,47 @@
import { WidgetService } from '../service/WidgetService'
const defaultOptions = {
name: 'timeDateRangeWidget',
icon: null,
label: '日期范围',
style: {
width: 200,
height: 22,
fontSize: 14,
fontWeight: 500,
lineHeight: '',
letterSpacing: 0,
textAlign: '',
color: ''
},
options: {
refId: '1234567890',
attrs: {
type: 'daterange',
rangeSeparator: '至',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期'
},
value: ''
},
component: 'de-date'
}
class TimeDateRangeServiceImpl extends WidgetService {
constructor(options) {
Object.assign(options, defaultOptions)
super(options)
}
initWidget() {
// console.log('this is first initWidget')
}
toDrawWidget() {
// console.log('this is first toDrawWidget')
}
// 移动到画布之前回掉
beforeToDraw() {
}
}
const timeDateRangeServiceImpl = new TimeDateRangeServiceImpl({ name: 'timeDateRangeWidget' })
export default timeDateRangeServiceImpl

View File

@ -0,0 +1,45 @@
import { WidgetService } from '../service/WidgetService'
const defaultOptions = {
name: 'timeDateWidget',
icon: null,
label: '日期',
style: {
width: 200,
height: 22,
fontSize: 14,
fontWeight: 500,
lineHeight: '',
letterSpacing: 0,
textAlign: '',
color: ''
},
options: {
refId: '1234567890',
attrs: {
type: 'date',
placeholder: '请选择日期'
},
value: ''
},
component: 'de-date'
}
class TimeDateServiceImpl extends WidgetService {
constructor(options) {
Object.assign(options, defaultOptions)
super(options)
}
initWidget() {
// console.log('this is first initWidget')
}
toDrawWidget() {
// console.log('this is first toDrawWidget')
}
// 移动到画布之前回掉
beforeToDraw() {
}
}
const timeDateServiceImpl = new TimeDateServiceImpl({ name: 'timeDateWidget' })
export default timeDateServiceImpl

View File

@ -0,0 +1,45 @@
import { WidgetService } from '../service/WidgetService'
const defaultOptions = {
name: 'timeMonthWidget',
icon: null,
label: '年月',
style: {
width: 200,
height: 22,
fontSize: 14,
fontWeight: 500,
lineHeight: '',
letterSpacing: 0,
textAlign: '',
color: ''
},
options: {
refId: '1234567890',
attrs: {
type: 'month',
placeholder: '请选择年月'
},
value: ''
},
component: 'de-date'
}
class TimeMonthServiceImpl extends WidgetService {
constructor(options) {
Object.assign(options, defaultOptions)
super(options)
}
initWidget() {
// console.log('this is first initWidget')
}
toDrawWidget() {
// console.log('this is first toDrawWidget')
}
// 移动到画布之前回掉
beforeToDraw() {
}
}
const timeMonthServiceImpl = new TimeMonthServiceImpl({ name: 'timeMonthWidget' })
export default timeMonthServiceImpl

View File

@ -0,0 +1,45 @@
import { WidgetService } from '../service/WidgetService'
const defaultOptions = {
name: 'timeQuarterWidget',
icon: null,
label: '季度',
style: {
width: 200,
height: 22,
fontSize: 14,
fontWeight: 500,
lineHeight: '',
letterSpacing: 0,
textAlign: '',
color: ''
},
options: {
refId: '1234567890',
attrs: {
placeholder: '请选择季度'
},
value: ''
},
component: 'de-quarter'
}
class TimeQuarterServiceImpl extends WidgetService {
constructor(options) {
Object.assign(options, defaultOptions)
super(options)
}
initWidget() {
// console.log('this is first initWidget')
}
toDrawWidget() {
// console.log('this is first toDrawWidget')
}
// 移动到画布之前回掉
beforeToDraw() {
}
}
const timeQuarterServiceImpl = new TimeQuarterServiceImpl({ name: 'timeQuarterWidget' })
export default timeQuarterServiceImpl

View File

@ -13,10 +13,15 @@ const defaultOptions = {
textAlign: '',
color: ''
},
deProp: {
type: 'year'
options: {
refId: '1234567890',
attrs: {
type: 'year',
placeholder: '请选择年份'
},
value: ''
},
component: 'el-date-picker'
component: 'de-date'
}
class TimeYearServiceImpl extends WidgetService {

View File

@ -1,16 +0,0 @@
// import { WidgetService } from '../service/WidgetService'
// class WidgetServiceImpl extends WidgetService {
// constructor(options) {
// super(options)
// console.log('init child class WidgetServiceImpl')
// }
// initWidget() {
// console.log('this is first initWidget')
// }
// toDrawWidget() {
// console.log('this is first toDrawWidget')
// }
// }
// const widgetServiceImpl = new WidgetServiceImpl({ name: 'testWidget' })
// export default widgetServiceImpl

View File

@ -64,9 +64,9 @@ Vue.use(message)
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store,
i18n,
render: h => h(App)
})
}).$mount('#app')

View File

@ -49,7 +49,16 @@ export default {
componentList,
widgetSubjects: {
'时间过滤组件': [
'timeYearWidget'
'timeYearWidget',
'timeMonthWidget',
'timeQuarterWidget',
'timeDateWidget',
'timeDateRangeWidget'
],
'文本过滤组件': [
'textSelectWidget',
'textInputWidget'
],
'按钮': [
'buttonSureWidget'