feat: 💥 增加dom全屏功能和增删表单功能,及优化部分模块

This commit is contained in:
zouzhibing 2022-11-27 20:54:11 +08:00
parent 2fa87b524a
commit eeb54d1726
13 changed files with 331 additions and 142 deletions

123
src/hooks/useFullscreen.ts Normal file
View File

@ -0,0 +1,123 @@
/**
* @description
* @vueuse/core useFullscreen useFullscreen
*
*/
import { ElMessage } from "element-plus";
import {onMounted} from "vue";
export const useFullscreen = () => {
/**
* @description: +
*/
const isFullscreen = ()=> {
let prefixName = ""; // 浏览器前缀
let fullscreenEnabled = false;
// 判断浏览器前缀
if (document.fullscreenEnabled) {
fullscreenEnabled = document.fullscreenEnabled;
// webkit
} else if (document.webkitFullscreenEnabled) {
fullscreenEnabled = document.webkitFullscreenEnabled;
prefixName = "webkit";
// moz
} else if (document.mozFullScreenEnabled) {
fullscreenEnabled = document.mozFullScreenEnabled;
prefixName = "moz";
// ms
} else if (document.msFullscreenEnabled) {
fullscreenEnabled = document.msFullscreenEnabled;
prefixName = "ms";
}
return {
fullscreenEnabled,
prefixName
}
}
/**
* @description:
* @return
*/
const isElementFullScreen = ()=> {
const fullscreenElement =
document.fullscreenElement ||
document.msFullscreenElement ||
document.mozFullScreenElement ||
document.webkitFullscreenElement;
if (fullscreenElement === null) {
return false; // 当前没有元素在全屏状态
} else {
return true; // 有元素在全屏状态
}
}
/**
* @description:
* @param {String} domName dom名称
*/
const Fullscreen = (target)=> {
const targetRef = target || (document == null ? void 0 : document.querySelector("html"));
const {prefixName} = isFullscreen()
const methodName =
prefixName === ""
? "requestFullscreen"
: `${prefixName}RequestFullScreen`;
targetRef[methodName]();
}
// 退出全屏
const exitFullscreen =()=> {
const {prefixName} = isFullscreen()
const methodName =
prefixName === ""
? "exitFullscreen"
: `${prefixName}ExitFullscreen`;
document[methodName]();
}
/**
* @description: ,,
* @param {Function} enterErrorFn
*/
const screenError = ()=> {
const {prefixName} = isFullscreen()
const methodName = `on${prefixName}fullscreenerror`;
document[methodName] = e => {
ElMessage.error('进入全屏失败')
};
}
/**
* @description: /
* @param {Function} enter
* @param {Function} quit
*/
const screenChange = (enter, quit)=> {
const {fullscreenEnabled,prefixName} = isFullscreen()
if (!fullscreenEnabled) return;
const methodName = `on${prefixName}fullscreenchange`;
document[methodName] = e => {
if (isElementFullScreen()) {
enter && enter(e); // 进入全屏回调
} else {
quit && quit(e); // 离开全屏的回调
}
};
}
onMounted(()=>{
screenError()
})
return{
isFullscreen,
isElementFullScreen,
Fullscreen,
exitFullscreen,
screenChange
}
}

View File

@ -1,50 +0,0 @@
<template>
<el-menu
:default-active="activeMenu"
background-color="#304156"
text-color="#bfcbd9"
:mode="mode"
:unique-opened="SettingStore.themeConfig.uniqueOpened"
:collapse-transition="false"
class="el-menu-vertical-demo"
:collapse="isCollapse"
>
<sub-item
v-for="route in permission_routes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
</el-menu>
</template>
<script lang="ts" setup>
import SubItem from './SubItem.vue'
import { useRoute } from 'vue-router'
import {usePermissionStore} from "@/store/modules/permission"
import {useSettingStore} from "@/store/modules/setting"
import { computed } from 'vue'
// setupstore
const route = useRoute()
const PermissionStore = usePermissionStore()
const SettingStore = useSettingStore()
//
const permission_routes = computed(() => PermissionStore.permission_routes)
const activeMenu = computed(() => {
const { meta, path } = route
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
return meta.activeMenu
}
return path
})
//
const isCollapse = computed(() => !SettingStore.isCollapse)
//
const mode = computed(() => SettingStore.themeConfig.mode)
</script>

View File

@ -1,79 +0,0 @@
<template>
<template v-if="!item.hidden">
<template v-if="!item.alwaysShow && hasOneShowingChild(item.children, item)">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)">
<el-icon :size="20">
<component :is="onlyOneChild?.meta.icon"></component>
</el-icon>
<template #title>{{ onlyOneChild.meta && onlyOneChild.meta.title }}</template>
</el-menu-item>
</app-link>
</template>
<el-sub-menu :index="resolvePath(item.path)" v-else popper-append-to-body>
<template #title>
<el-icon :size="20"> <component :is="item.meta?.icon"></component></el-icon>
<span>{{ item.meta && item.meta.title }}</span>
</template>
<sub-item
v-for="child in item.children"
:key="child.path"
:item="child"
:base-path="resolvePath(child.path)"
/>
</el-sub-menu>
</template>
</template>
<script lang="ts" setup>
import { isExternal } from '@/utils/validate.js'
import AppLink from '../../SubMenu/Link.vue'
import path from 'path-browserify'
import { ref, computed } from 'vue'
const props = defineProps({
item: {
type: Object,
required: true,
},
basePath: {
type: String,
default: '',
},
})
const onlyOneChild = ref(null)
const hasOneShowingChild = (children = [], parent) => {
const showingChildren = children.filter((item) => {
//
if (item.hidden) {
return false
} else {
// 使
onlyOneChild.value = item
return true
}
})
//
if (showingChildren.length === 1) {
return true
}
//
if (showingChildren.length === 0) {
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }
return true
}
return false
}
const resolvePath = (routePath) => {
if (isExternal(routePath)) {
return routePath
}
if (isExternal(props.basePath)) {
return props.basePath
}
return path.resolve(props.basePath, routePath)
}
</script>

View File

@ -26,16 +26,15 @@
import Logo from './components/Logo.vue' import Logo from './components/Logo.vue'
import SubItem from '../SubMenu/SubItem.vue' import SubItem from '../SubMenu/SubItem.vue'
import {useSettingStore} from "@/store/modules/setting" import {useSettingStore} from "@/store/modules/setting"
import {usePermissionStore} from "@/store/modules/permission"
import { computed } from 'vue' import { computed } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import {usePermissionStore} from "@/store/modules/permission"
// setupstore // setupstore
const route = useRoute() const route = useRoute()
const PermissionStore = usePermissionStore() const PermissionStore = usePermissionStore()
const SettingStore = useSettingStore() const SettingStore = useSettingStore()
// //
const isCollapse = computed(() => !SettingStore.isCollapse) const isCollapse = computed(() => !SettingStore.isCollapse)
// //
@ -52,10 +51,6 @@ const activeMenu = computed(() => {
} }
return path return path
}) })
//
const mode = computed(() => SettingStore.themeConfig.mode)
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -24,7 +24,13 @@ const formRouter = [{
path: 'advancedForm', path: 'advancedForm',
component: () => import('@/views/form/advancedForm/index.vue'), component: () => import('@/views/form/advancedForm/index.vue'),
name: 'advanced-form', name: 'advanced-form',
meta: { title: '可收缩 Form', keepAlive: true , icon: 'MenuIcon'} meta: { title: '收缩 Form', keepAlive: true , icon: 'MenuIcon'}
},
{
path: 'appendForm',
component: () => import('@/views/form/appendForm/index.vue'),
name: 'append-form',
meta: { title: '增删 Form', keepAlive: true , icon: 'MenuIcon'}
}, },
] ]
}] }]

View File

@ -31,6 +31,12 @@ const functionPageRouter = [{
name: 'function-403', name: 'function-403',
meta: { title: '403 页面', keepAlive: true , icon: 'MenuIcon'} meta: { title: '403 页面', keepAlive: true , icon: 'MenuIcon'}
}, },
{
path: 'fullscreen',
component: () => import('@/views/functionPage/fullscreen/index.vue'),
name: 'fullscreen',
meta: { title: '元素 全屏', keepAlive: true , icon: 'MenuIcon'}
},
] ]
}] }]

View File

@ -0,0 +1,3 @@
.advancedForm{
padding: 20px;
}

View File

@ -24,7 +24,7 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup name="advancedForm">
import AdvancedForm from "@/components/SearchForm/advancedForm/index.vue" import AdvancedForm from "@/components/SearchForm/advancedForm/index.vue"
import {reactive, ref} from 'vue' import {reactive, ref} from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
@ -103,7 +103,5 @@ const showRow = (number)=>{
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.advancedForm{ @import "./index.scss";
padding: 20px;
}
</style> </style>

View File

@ -0,0 +1,6 @@
.app-container-inner{
text-align: center;
.add{
margin: 0 0 30px 0;
}
}

View File

@ -0,0 +1,117 @@
<template>
<div class="app-container">
<div class="app-container-inner">
<el-form
ref="formRef"
:model="dynamicValidateForm"
label-width="120px"
class="demo-dynamic"
>
<el-row v-for="(domain, index) in dynamicValidateForm.domains" :gutter="20" :key="domain.key">
<el-col :span="10">
<el-form-item
:label="'Domain' + index"
:prop="'domains.' + index + '.name'"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="domain.name" />
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item
:label="'Domain' + index"
:prop="'domains.' + index + '.value'"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="domain.value" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-button @click.prevent="addDomain()" v-if="index===0">
<el-icon><Plus /></el-icon>
</el-button>
<el-button @click.prevent="removeDomain(domain)" v-else>
<el-icon ><Minus /></el-icon>
</el-button>
</el-col>
</el-row>
<el-form-item>
<el-button type="primary" @click="submitForm(formRef)">Submit</el-button>
<el-button @click="resetForm(formRef)">Reset</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script lang="ts" setup name="appendForm">
import { reactive, ref } from 'vue'
import type { FormInstance } from 'element-plus'
import {ElMessage} from "element-plus"
const formRef = ref<FormInstance>()
const dynamicValidateForm = reactive<{
domains: DomainItem[]
}>({
domains: [
{
key: 1,
value: '',
name:''
},
],
})
interface DomainItem {
key: number
value: string,
name:string
}
const removeDomain = (item: DomainItem) => {
const index = dynamicValidateForm.domains.indexOf(item)
if (index !== -1) {
dynamicValidateForm.domains.splice(index, 1)
}
}
const addDomain = () => {
dynamicValidateForm.domains.push({
key: Date.now(),
value: '',
name:''
})
}
const submitForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.validate((valid) => {
if (valid) {
ElMessage.success(`提交数据: ${JSON.stringify(dynamicValidateForm.domains)}`)
console.log('submit!',dynamicValidateForm.domains)
} else {
console.log('error submit!')
return false
}
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
}
</script>
<style lang="scss" scoped>
@import "./index.scss";
</style>

View File

@ -71,7 +71,7 @@
</u-container-layout> </u-container-layout>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup name="advancedForm">
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import Upload from './components/Upload.vue' import Upload from './components/Upload.vue'

View File

@ -0,0 +1,34 @@
.app-container-inner{
display: flex;
align-items: center;
justify-content: center;
position: relative;
.header{
padding: 20px;
position: absolute;
left: 0;
top: 0;
width: 100%;
border-bottom: 1px solid #0000001a;
.title{
margin-bottom: 20px;
}
}
.fullscreen{
display: flex;
flex-direction: column;
background: white;
width: 300px;
height: 300px;
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
.title{
padding: 20px;
}
.inner{
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
}
}

View File

@ -0,0 +1,30 @@
<template>
<div class="app-container">
<div class="app-container-inner">
<div class="header">
<div class="title">window切换全屏</div>
<el-button type="primary" @click="fullWindowScreenAction">{{ isFullscreen?'退出全屏':'点击全屏' }}</el-button>
</div>
<div class="fullscreen" @click="fullscreenAction" ref="domRef">
<div class="title">DOM元素切换全屏</div>
<div class="inner">
<el-button type="primary">{{ isFullscreen?'退出全屏':'点击全屏' }}</el-button>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import {ref} from "vue";
import { useFullscreen } from "@vueuse/core";
const domRef = ref<HTMLElement>(null);
const { enter, toggle:fullWindowScreenAction, exit, isFullscreen } = useFullscreen();
const { toggle: fullscreenAction } = useFullscreen(domRef);
</script>
<style lang="scss" scoped>
@import "./index.scss";
</style>