mirror of
https://github.com/fugary/simple-element-plus-template.git
synced 2025-11-12 14:27:49 +00:00
图标选择控件
This commit is contained in:
@@ -57,6 +57,21 @@ html, body, #app, .index-container {
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.icon-dialog .el-dialog__body {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.icon-list::-webkit-scrollbar {
|
||||
z-index: 10;
|
||||
width: 6px;
|
||||
}
|
||||
.icon-list::-webkit-scrollbar-thumb {
|
||||
border-radius:5px;
|
||||
width:6px;
|
||||
background:var(--el-text-color-disabled)
|
||||
}
|
||||
|
||||
/**
|
||||
* slide-fade动画
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,7 @@ import ControlChild from '@/components/common-form-control/control-child.vue'
|
||||
* @property {boolean} required 是否必填,后面解析成为rules的一部分
|
||||
* @property {string|RegExp} pattern 正则表达式验证,解析成为rules的一部分
|
||||
* @property {string} patternMsg 正则表达式验证消息
|
||||
* @property {boolean} common 自定义组件
|
||||
* @property {boolean} disabled 禁用
|
||||
* @property {boolean} readonly 只读
|
||||
* @property {string} placeholder 占位提示符
|
||||
@@ -41,6 +42,9 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const inputType = computed(() => {
|
||||
if (props.option.common) {
|
||||
return `common-${props.option.type}`
|
||||
}
|
||||
return `el-${props.option.type || 'input'}`
|
||||
})
|
||||
|
||||
|
||||
167
src/components/common-icon-select/index.vue
Normal file
167
src/components/common-icon-select/index.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { filterIconsByKeywords } from '@/services/icon/IconService'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
dialogAttrs: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
colSize: {
|
||||
type: Number,
|
||||
default: 6
|
||||
},
|
||||
dialogHeight: {
|
||||
type: String,
|
||||
default: '400px'
|
||||
},
|
||||
dialogWidth: {
|
||||
type: String,
|
||||
default: '600px'
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
const iconSelectVisible = ref(false)
|
||||
const keyWords = ref('')
|
||||
|
||||
const filterIcons = computed(() => {
|
||||
if (iconSelectVisible.value) {
|
||||
return filterIconsByKeywords(keyWords.value, props.colSize)
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const vModel = useVModel(props, 'modelValue', emit)
|
||||
|
||||
const selectIcon = icon => {
|
||||
iconSelectVisible.value = false
|
||||
vModel.value = icon
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<label class="el-radio">
|
||||
<common-icon
|
||||
v-if="modelValue"
|
||||
:icon="modelValue"
|
||||
class="el-radio__input"
|
||||
/>
|
||||
<span
|
||||
v-if="modelValue"
|
||||
class="el-radio__label"
|
||||
>{{ modelValue }}</span>
|
||||
<el-button
|
||||
class="icon-select-button"
|
||||
type="primary"
|
||||
:disabled="disabled||readonly"
|
||||
size="small"
|
||||
@click="iconSelectVisible = true"
|
||||
>
|
||||
{{ $t('common.label.select') }}
|
||||
</el-button>
|
||||
</label>
|
||||
<el-button
|
||||
v-if="vModel"
|
||||
type="danger"
|
||||
:disabled="disabled||readonly"
|
||||
size="small"
|
||||
@click="vModel = ''"
|
||||
>
|
||||
{{ $t('common.label.clear') }}
|
||||
</el-button>
|
||||
<el-dialog
|
||||
v-model="iconSelectVisible"
|
||||
:width="dialogWidth"
|
||||
v-bind="dialogAttrs"
|
||||
draggable
|
||||
class="icon-dialog"
|
||||
:title="$t('common.msg.pleaseSelectIcon')"
|
||||
>
|
||||
<el-container
|
||||
style="overflow: auto;"
|
||||
:style="{ height: dialogHeight }"
|
||||
class="icon-container"
|
||||
>
|
||||
<el-header height="40px">
|
||||
<el-form label-width="120px">
|
||||
<el-form-item :label="$t('common.label.keywords')">
|
||||
<el-input
|
||||
v-model="keyWords"
|
||||
:placeholder="$t('common.msg.inputKeywords')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-header>
|
||||
<el-main>
|
||||
<RecycleScroller
|
||||
v-slot="{ item }"
|
||||
class="scroller icon-list"
|
||||
:items="filterIcons"
|
||||
:item-size="80"
|
||||
key-field="id"
|
||||
>
|
||||
<el-row>
|
||||
<el-col
|
||||
v-for="icon in item.icons"
|
||||
:key="icon"
|
||||
:span="24/colSize"
|
||||
class="text-center"
|
||||
>
|
||||
<a
|
||||
class="el-button el-button--large is-text"
|
||||
style="height:80px;"
|
||||
@click="selectIcon(icon)"
|
||||
>
|
||||
<div>
|
||||
<common-icon
|
||||
size="20"
|
||||
:icon="icon"
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</RecycleScroller>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.scroller {
|
||||
height: 100%;
|
||||
}
|
||||
.icon-container {
|
||||
overflow: auto;
|
||||
}
|
||||
.icon-container .el-input {
|
||||
width: 80%;
|
||||
}
|
||||
.icon-select-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.el-radio {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -27,7 +27,7 @@ const props = defineProps({
|
||||
required: true
|
||||
},
|
||||
/**
|
||||
* @type {'large'|'small'|'default'}
|
||||
* @type {''|'large'|'small'|'default'}
|
||||
*/
|
||||
buttonSize: {
|
||||
type: String,
|
||||
@@ -75,19 +75,21 @@ const props = defineProps({
|
||||
<template
|
||||
#default="scope"
|
||||
>
|
||||
<el-button
|
||||
v-for="(button, index) in column.buttons"
|
||||
:key="index"
|
||||
:type="button.type"
|
||||
:icon="button.icon"
|
||||
:size="button.size||buttonSize"
|
||||
:disabled="button.disabled"
|
||||
:round="button.round"
|
||||
:circle="button.circle"
|
||||
@click="button.click&&button.click(scope.row, scope)"
|
||||
>
|
||||
{{ button.label || $t(button.labelKey) }}
|
||||
</el-button>
|
||||
<template v-for="(button, index) in column.buttons">
|
||||
<el-button
|
||||
v-if="!button.buttonIf||button.buttonIf(scope.row, scope)"
|
||||
:key="index"
|
||||
:type="button.type"
|
||||
:icon="button.icon"
|
||||
:size="button.size||buttonSize"
|
||||
:disabled="button.disabled"
|
||||
:round="button.round"
|
||||
:circle="button.circle"
|
||||
@click="button.click&&button.click(scope.row, scope)"
|
||||
>
|
||||
{{ button.label || $t(button.labelKey) }}
|
||||
</el-button>
|
||||
</template>
|
||||
<slot
|
||||
name="default"
|
||||
v-bind="scope"
|
||||
|
||||
@@ -92,10 +92,7 @@ const onDropdownVisibleChange = (visible, tab) => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.common-tabs > .el-tabs__content {
|
||||
padding: 32px;
|
||||
color: #6b778c;
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
.common-tabs .el-tabs__header {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import CommonIcon from '@/components/common-icon/index.vue'
|
||||
import CommonIconSelect from '@/components/common-icon-select/index.vue'
|
||||
import CommonForm from '@/components/common-form/index.vue'
|
||||
import CommonFormControl from '@/components/common-form-control/index.vue'
|
||||
import CommonMenu from '@/components/common-menu/index.vue'
|
||||
@@ -15,6 +16,7 @@ export default {
|
||||
*/
|
||||
install (Vue) {
|
||||
Vue.component('CommonIcon', CommonIcon)
|
||||
Vue.component('CommonIconSelect', CommonIconSelect)
|
||||
Vue.component('CommonForm', CommonForm)
|
||||
Vue.component('CommonFormControl', CommonFormControl)
|
||||
Vue.component('CommonMenu', CommonMenu)
|
||||
|
||||
@@ -33,10 +33,15 @@ common.label.delete = '删除'
|
||||
common.label.search = '搜索'
|
||||
common.label.find = '查找'
|
||||
common.label.back = '返回'
|
||||
common.label.select = '选择'
|
||||
common.label.clear = '清空'
|
||||
common.label.tabMode = '多标签模式'
|
||||
common.label.cachedTabMode = '缓存标签页'
|
||||
common.label.showTabIcon = '标签图标'
|
||||
common.label.keywords = '关键字'
|
||||
|
||||
//* =======================msg=====================//
|
||||
common.msg.nonNull = '{0}不能为空'
|
||||
common.msg.patternInvalid = '{0}格式校验不通过'
|
||||
common.msg.pleaseSelectIcon = '请选择图标'
|
||||
common.msg.inputKeywords = '输入关键字搜索'
|
||||
|
||||
@@ -33,10 +33,15 @@ common.label.delete = 'Delete'
|
||||
common.label.search = 'Search'
|
||||
common.label.find = 'Find'
|
||||
common.label.back = 'Back'
|
||||
common.label.select = 'Select'
|
||||
common.label.clear = 'Clear'
|
||||
common.label.tabMode = 'Tabs Mode'
|
||||
common.label.cachedTabMode = 'Cache Tabs'
|
||||
common.label.showTabIcon = 'Tab Icon'
|
||||
common.label.keywords = 'Keywords'
|
||||
|
||||
//* =======================msg=====================//
|
||||
common.msg.nonNull = '{0} is required.'
|
||||
common.msg.patternInvalid = '{0} pattern check failed.'
|
||||
common.msg.pleaseSelectIcon = 'Please select icon'
|
||||
common.msg.inputKeywords = 'Input keywords to search'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createI18n, useI18n } from 'vue-i18n'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import { ref } from 'vue'
|
||||
import messagesCn from './messages_cn'
|
||||
import messagesEn from './messages_en'
|
||||
|
||||
@@ -10,6 +10,7 @@ menu.label.toolsManagement = '工具管理'
|
||||
menu.label.toolsIcons = '图标工具'
|
||||
menu.label.toolsForms = '表单工具'
|
||||
menu.label.toolsTables = '表格工具'
|
||||
menu.label.toolsTests = '测试页面'
|
||||
menu.label.errorPage = '错误页面'
|
||||
menu.label.errorPage404 = '找不到页面'
|
||||
menu.label.errorPage403 = '没有权限'
|
||||
|
||||
@@ -10,6 +10,7 @@ menu.label.toolsManagement = 'Tools'
|
||||
menu.label.toolsIcons = 'Icons'
|
||||
menu.label.toolsForms = 'Forms'
|
||||
menu.label.toolsTables = 'Tables'
|
||||
menu.label.toolsTests = 'Test Page'
|
||||
menu.label.errorPage = 'Error Page'
|
||||
menu.label.errorPage404 = 'Not Found'
|
||||
menu.label.errorPage403 = 'Access Denied'
|
||||
|
||||
@@ -6,6 +6,10 @@ export default [{
|
||||
path: '/forms',
|
||||
name: 'forms',
|
||||
component: () => import('@/views/tools/Forms.vue')
|
||||
}, {
|
||||
path: '/tests',
|
||||
name: 'tests',
|
||||
component: () => import('@/views/tools/TestPage.vue')
|
||||
}, {
|
||||
path: '/tables',
|
||||
name: 'tables',
|
||||
|
||||
@@ -117,6 +117,11 @@ export const useBusinessMenus = () => {
|
||||
index: '/tables',
|
||||
icon: 'Grid',
|
||||
labelKey: 'menu.label.toolsTables'
|
||||
},
|
||||
{
|
||||
index: '/tests',
|
||||
icon: 'TipsAndUpdatesOutlined',
|
||||
labelKey: 'menu.label.toolsTests'
|
||||
}
|
||||
]
|
||||
}])
|
||||
|
||||
20
src/services/icon/IconService.js
Normal file
20
src/services/icon/IconService.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { INSTALL_ICONS } from '@/icons'
|
||||
import chunk from 'lodash/chunk'
|
||||
|
||||
/**
|
||||
* @param keywords {string}
|
||||
* @param colSize {number}
|
||||
* @returns {{id: number, icons: *}[]}
|
||||
*/
|
||||
export const filterIconsByKeywords = (keywords, colSize) => {
|
||||
let installIcons = INSTALL_ICONS
|
||||
if (keywords) {
|
||||
installIcons = installIcons.filter(icon => icon.toLowerCase().includes(keywords.toLowerCase()))
|
||||
}
|
||||
return chunk(installIcons, colSize).map((arr, idx) => {
|
||||
return {
|
||||
id: idx,
|
||||
icons: arr
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -26,7 +26,10 @@ const showLeftMenu = computed(() => {
|
||||
<el-header>
|
||||
<top-nav />
|
||||
</el-header>
|
||||
<el-header v-if="tabsViewStore.isTabMode">
|
||||
<el-header
|
||||
v-if="tabsViewStore.isTabMode"
|
||||
class="tabs-header"
|
||||
>
|
||||
<common-tabs-view />
|
||||
</el-header>
|
||||
<el-main>
|
||||
@@ -51,3 +54,9 @@ const showLeftMenu = computed(() => {
|
||||
</el-container>
|
||||
</el-container>
|
||||
</template>
|
||||
<style scoped>
|
||||
.tabs-header {
|
||||
margin-top: 5px;
|
||||
height: 40px
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -95,6 +95,13 @@ const formOptions = [{
|
||||
value: 'unknown'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
label: '图标测试',
|
||||
prop: 'icon',
|
||||
value: '',
|
||||
type: 'icon-select',
|
||||
required: true,
|
||||
common: true
|
||||
}, {
|
||||
label: '地址',
|
||||
prop: 'address',
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
<script setup>
|
||||
import { INSTALL_ICONS } from '@/icons'
|
||||
import chunk from 'lodash/chunk'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { filterIconsByKeywords } from '@/services/icon/IconService'
|
||||
|
||||
const colSize = ref(8)
|
||||
const keyWords = ref('')
|
||||
|
||||
const filterIcons = computed(() => {
|
||||
let installIcons = INSTALL_ICONS
|
||||
if (keyWords.value) {
|
||||
installIcons = installIcons.filter(icon => icon.toLowerCase().includes(keyWords.value.toLowerCase()))
|
||||
}
|
||||
return chunk(installIcons, colSize.value).map((arr, idx) => {
|
||||
return {
|
||||
id: idx,
|
||||
icons: arr
|
||||
}
|
||||
})
|
||||
return filterIconsByKeywords(keyWords.value, colSize.value)
|
||||
})
|
||||
|
||||
const copyIcon = (icon) => {
|
||||
@@ -39,54 +30,55 @@ const copyIcon = (icon) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col>
|
||||
<el-form label-width="120px">
|
||||
<el-form-item label="图标名字">
|
||||
<el-input
|
||||
v-model="keyWords"
|
||||
:placeholder="`输入关键字搜索图标`"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<RecycleScroller
|
||||
v-slot="{ item }"
|
||||
page-mode
|
||||
class="scroller"
|
||||
:items="filterIcons"
|
||||
:item-size="80"
|
||||
key-field="id"
|
||||
>
|
||||
<el-row>
|
||||
<el-col
|
||||
v-for="icon in item.icons"
|
||||
:key="icon"
|
||||
:span="24/colSize"
|
||||
class="text-center"
|
||||
>
|
||||
<a
|
||||
class="el-button el-button--large is-text"
|
||||
style="height:80px;"
|
||||
@click="copyIcon(icon)"
|
||||
<el-container
|
||||
class="icon-container"
|
||||
>
|
||||
<el-header height="40px">
|
||||
<el-form label-width="120px">
|
||||
<el-form-item :label="$t('common.label.keywords')">
|
||||
<el-input
|
||||
v-model="keyWords"
|
||||
:placeholder="$t('common.msg.inputKeywords')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-header>
|
||||
<el-main>
|
||||
<RecycleScroller
|
||||
v-slot="{ item }"
|
||||
class="scroller icon-list"
|
||||
:items="filterIcons"
|
||||
:item-size="80"
|
||||
key-field="id"
|
||||
>
|
||||
<el-row>
|
||||
<el-col
|
||||
v-for="icon in item.icons"
|
||||
:key="icon"
|
||||
:span="24/colSize"
|
||||
class="text-center"
|
||||
>
|
||||
<div>
|
||||
<common-icon
|
||||
size="20"
|
||||
:icon="icon"
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</RecycleScroller>
|
||||
</div>
|
||||
<a
|
||||
class="el-button el-button--large is-text"
|
||||
style="height:80px;"
|
||||
@click="copyIcon(icon)"
|
||||
>
|
||||
<div>
|
||||
<common-icon
|
||||
size="20"
|
||||
:icon="icon"
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</RecycleScroller>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.scroller {
|
||||
.scroller, .icon-container {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,18 +3,21 @@ import { ref } from 'vue'
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
id: '1',
|
||||
birthday: '2016-05-03',
|
||||
userName: 'Tom',
|
||||
gender: 'male',
|
||||
address: 'No. 189, Grove St, Los Angeles'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
birthday: '2016-05-02',
|
||||
userName: 'Tom',
|
||||
gender: 'female',
|
||||
address: 'No. 189, Grove St, Los Angeles'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
birthday: '2016-05-04',
|
||||
userName: 'Tom',
|
||||
gender: 'male',
|
||||
@@ -54,12 +57,18 @@ const buttons = ref([{
|
||||
type: 'primary',
|
||||
click: item => {
|
||||
console.info('编辑=============', item)
|
||||
},
|
||||
buttonIf (item) {
|
||||
return !!item.id
|
||||
}
|
||||
}, {
|
||||
labelKey: 'common.label.delete',
|
||||
type: 'danger',
|
||||
click: item => {
|
||||
console.info('删除=============', item)
|
||||
},
|
||||
buttonIf (item) {
|
||||
return !!item.id
|
||||
}
|
||||
}, {
|
||||
label: '其他操作'
|
||||
|
||||
21
src/views/tools/TestPage.vue
Normal file
21
src/views/tools/TestPage.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const modelIcon = ref('Apple')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-container>
|
||||
<el-main>
|
||||
<el-form>
|
||||
<el-form-item label="图标选择">
|
||||
<common-icon-select v-model="modelIcon" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user