perf: 优化长按菜单

This commit is contained in:
kuaifan 2025-04-17 09:46:57 +08:00
parent 8f2f68dffc
commit ab616c5d32
9 changed files with 77 additions and 79 deletions

View File

@ -155,7 +155,12 @@
</ul> </ul>
</div> </div>
</Scrollbar> </Scrollbar>
<div class="operate-position" :style="operateStyles" v-show="operateVisible"> <div
v-transfer-dom
:data-transfer="true"
class="operate-position"
:style="operateStyles"
v-show="operateVisible">
<Dropdown <Dropdown
trigger="custom" trigger="custom"
:placement="windowLandscape ? 'bottom' : 'top'" :placement="windowLandscape ? 'bottom' : 'top'"
@ -356,6 +361,7 @@ import MobileTabbar from "../components/Mobile/Tabbar";
import TaskAdd from "./manage/components/TaskAdd"; import TaskAdd from "./manage/components/TaskAdd";
import Report from "./manage/components/Report"; import Report from "./manage/components/Report";
import longpress from "../directives/longpress"; import longpress from "../directives/longpress";
import TransferDom from "../directives/transfer-dom";
import DialogModal from "./manage/components/DialogModal"; import DialogModal from "./manage/components/DialogModal";
import TaskModal from "./manage/components/TaskModal"; import TaskModal from "./manage/components/TaskModal";
import CheckinExport from "./manage/components/CheckinExport"; import CheckinExport from "./manage/components/CheckinExport";
@ -391,7 +397,7 @@ export default {
MicroApps, MicroApps,
ComplaintManagement ComplaintManagement
}, },
directives: {longpress}, directives: {longpress, TransferDom},
data() { data() {
return { return {
loadIng: 0, loadIng: 0,
@ -1144,13 +1150,12 @@ export default {
} }
this.operateVisible = false; this.operateVisible = false;
this.operateItem = $A.isJson(projectItem) ? projectItem : {}; this.operateItem = $A.isJson(projectItem) ? projectItem : {};
this.$nextTick(() => { requestAnimationFrame(() => {
const rect = element.getBoundingClientRect(); const rect = element.getBoundingClientRect();
const parentRect = this.$refs.boxMenu?.getBoundingClientRect() || {top: 0, left: 0}
this.operateStyles = { this.operateStyles = {
left: `${event.clientX - parentRect.left}px`, left: `${event.clientX}px`,
top: `${rect.top + this.windowScrollY - parentRect.top}px`, top: `${rect.top}px`,
height: rect.height + 'px', height: `${rect.height}px`,
} }
this.operateVisible = true; this.operateVisible = true;
}) })

View File

@ -292,7 +292,12 @@
</div> </div>
<!--长按右键--> <!--长按右键-->
<div class="operate-position" :style="operateStyles" v-show="operateVisible"> <div
class="operate-position"
v-transfer-dom
:data-transfer="true"
:style="operateStyles"
v-show="operateVisible">
<Dropdown <Dropdown
ref="operate" ref="operate"
trigger="custom" trigger="custom"
@ -655,6 +660,7 @@ import DialogGroupVote from "./DialogGroupVote";
import DialogComplaint from "./DialogComplaint"; import DialogComplaint from "./DialogComplaint";
import touchclick from "../../../directives/touchclick"; import touchclick from "../../../directives/touchclick";
import longpress from "../../../directives/longpress"; import longpress from "../../../directives/longpress";
import TransferDom from "../../../directives/transfer-dom";
import {languageList} from "../../../language"; import {languageList} from "../../../language";
import {isLocalResourcePath} from "../../../components/Replace/utils"; import {isLocalResourcePath} from "../../../components/Replace/utils";
import emitter from "../../../store/events"; import emitter from "../../../store/events";
@ -680,7 +686,7 @@ export default {
DialogGroupVote, DialogGroupVote,
DialogComplaint, DialogComplaint,
}, },
directives: {touchclick, longpress}, directives: {touchclick, longpress, TransferDom},
props: { props: {
dialogId: { dialogId: {
@ -3080,7 +3086,7 @@ export default {
}) })
} }
} }
this.$nextTick(() => { requestAnimationFrame(() => {
this.operateItem.clientX = event.clientX this.operateItem.clientX = event.clientX
this.operateItem.clientY = event.clientY this.operateItem.clientY = event.clientY
this.onSelectionchange() this.onSelectionchange()
@ -3146,34 +3152,36 @@ export default {
return return
} }
// //
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect(),
const scrollerRect = this.$refs.scroller.$el.getBoundingClientRect(); scrollerRect = this.$refs.scroller.$el.getBoundingClientRect();
let top = rect.top + this.windowScrollY, const operatePosition = {
height = rect.height; left: this.operateItem.clientX,
top: rect.top,
height: rect.height
}
if (rect.top < scrollerRect.top) { if (rect.top < scrollerRect.top) {
top = scrollerRect.top operatePosition.top = scrollerRect.top
height -= scrollerRect.top - rect.top operatePosition.height -= scrollerRect.top - rect.top
} }
if (rect.bottom > scrollerRect.bottom) { if (rect.bottom > scrollerRect.bottom) {
height -= rect.bottom - scrollerRect.bottom operatePosition.height -= rect.bottom - scrollerRect.bottom
} }
let left = this.operateItem.clientX
if (this.windowWidth < 500) { if (this.windowWidth < 500) {
if (this.operateItem.created_at) { if (this.operateItem.created_at) {
left = this.windowWidth / 2 operatePosition.left = this.windowWidth / 2
} else { } else {
left = rect.left + (rect.width / 2) operatePosition.left = rect.left + (rect.width / 2)
} }
} }
this.operateStyles = { this.operateStyles = {
left: `${left}px`, left: `${operatePosition.left}px`,
top: `${top}px`, top: `${operatePosition.top}px`,
height: `${height}px`, height: `${operatePosition.height}px`,
} }
if (this.location === 'messenger') { this.operateClient = {
this.operateStyles.marginTop = "calc(var(--status-bar-height) * -1)" x: operatePosition.left,
} y: this.operateItem.clientY
this.operateClient = {x: left, y: this.operateItem.clientY}; };
if (this.operateVisible) { if (this.operateVisible) {
try { try {
this.$refs.operate.$refs.drop.popper.update() this.$refs.operate.$refs.drop.popper.update()

View File

@ -56,7 +56,12 @@
</div> </div>
</li> </li>
</ul> </ul>
<div class="operate-position" :style="operateStyles" v-show="operateVisible"> <div
v-transfer-dom
:data-transfer="true"
class="operate-position"
:style="operateStyles"
v-show="operateVisible">
<Dropdown <Dropdown
trigger="custom" trigger="custom"
:placement="windowLandscape ? 'bottom' : 'top'" :placement="windowLandscape ? 'bottom' : 'top'"
@ -77,10 +82,11 @@
<script> <script>
import {mapState} from "vuex"; import {mapState} from "vuex";
import longpress from "../../../directives/longpress"; import longpress from "../../../directives/longpress";
import TransferDom from "../../../directives/transfer-dom";
export default { export default {
name: "ProjectList", name: "ProjectList",
directives: {longpress}, directives: {longpress, TransferDom},
data() { data() {
return { return {
projectKeyValue: '', projectKeyValue: '',
@ -189,13 +195,12 @@ export default {
} }
this.operateVisible = false; this.operateVisible = false;
this.operateItem = $A.isJson(projectItem) ? projectItem : {}; this.operateItem = $A.isJson(projectItem) ? projectItem : {};
this.$nextTick(() => { requestAnimationFrame(() => {
const rect = element.getBoundingClientRect(); const rect = element.getBoundingClientRect();
const parentRect = this.$el.getBoundingClientRect() || {top: 0, left: 0}
this.operateStyles = { this.operateStyles = {
left: `${event.clientX - parentRect.left}px`, left: `${event.clientX}px`,
top: `${rect.top + this.windowScrollY - parentRect.top}px`, top: `${rect.top}px`,
height: rect.height + 'px', height: `${rect.height}px`,
} }
this.operateVisible = true; this.operateVisible = true;
}) })

View File

@ -177,7 +177,12 @@
<Icon @click="tabActive='contacts'" :class="{active:tabActive==='contacts'}" type="md-person" /> <Icon @click="tabActive='contacts'" :class="{active:tabActive==='contacts'}" type="md-person" />
</div> </div>
</div> </div>
<div class="operate-position" :style="operateStyles" v-show="operateVisible"> <div
v-transfer-dom
:data-transfer="true"
class="operate-position"
:style="operateStyles"
v-show="operateVisible">
<Dropdown <Dropdown
trigger="custom" trigger="custom"
transferClassName="scrollbar-hidden" transferClassName="scrollbar-hidden"
@ -272,6 +277,7 @@
import {mapGetters, mapState} from "vuex"; import {mapGetters, mapState} from "vuex";
import DialogWrapper from "./components/DialogWrapper"; import DialogWrapper from "./components/DialogWrapper";
import longpress from "../../directives/longpress"; import longpress from "../../directives/longpress";
import TransferDom from "../../directives/transfer-dom";
import emitter from "../../store/events"; import emitter from "../../store/events";
const navDatas = { const navDatas = {
@ -290,7 +296,7 @@ const navDatas = {
export default { export default {
components: {DialogWrapper}, components: {DialogWrapper},
directives: {longpress}, directives: {longpress, TransferDom},
data() { data() {
return { return {
firstLoad: true, firstLoad: true,
@ -1058,13 +1064,12 @@ export default {
if (!this.operateItem) { if (!this.operateItem) {
return return
} }
requestAnimationFrame(() => {
const rect = element.getBoundingClientRect(); const rect = element.getBoundingClientRect();
this.$nextTick(() => {
const parentRect = this.$refs.select?.getBoundingClientRect() || {top: 0, left: 0}
this.operateStyles = { this.operateStyles = {
left: `${event.clientX}px`, left: `${event.clientX}px`,
top: `${rect.top + this.windowScrollY - parentRect.top}px`, top: `${rect.top}px`,
height: rect.height + 'px', height: `${rect.height}px`,
} }
this.operateVisible = true; this.operateVisible = true;
}) })

View File

@ -999,3 +999,16 @@ body.window-portrait {
margin-left: 54px; margin-left: 54px;
} }
} }
/*操作位置*/
.operate-position {
position: absolute;
top: 0;
left: 0;
width: 1px;
height: auto;
margin-top: var(--window-scroll-y);
opacity: 0;
visibility: hidden;
pointer-events: none;
}

View File

@ -2073,16 +2073,6 @@
} }
} }
.operate-position {
position: fixed;
top: 0;
left: 0;
width: 1px;
opacity: 0;
visibility: hidden;
pointer-events: none;
}
.apply-reasoning { .apply-reasoning {
margin: 0 0 12px 0; margin: 0 0 12px 0;
padding: 0 0 0 13px; padding: 0 0 0 13px;

View File

@ -191,14 +191,4 @@
} }
} }
} }
.operate-position {
position: fixed;
top: 0;
left: 0;
width: 1px;
opacity: 0;
visibility: hidden;
pointer-events: none;
}
} }

View File

@ -200,15 +200,6 @@
} }
} }
} }
.operate-position {
position: fixed;
top: 0;
left: 0;
width: 1px;
opacity: 0;
visibility: hidden;
pointer-events: none;
}
.manage-project-search { .manage-project-search {
width: 80%; width: 80%;
padding: 0 6px; padding: 0 6px;

View File

@ -555,15 +555,6 @@
} }
} }
} }
.operate-position {
position: fixed;
top: 0;
left: 0;
width: 1px;
opacity: 0;
visibility: hidden;
pointer-events: none;
}
} }
.messenger-msg { .messenger-msg {
flex: 1; flex: 1;