效果展示:(样式模仿飞书的,较为简单的设计,可以根据需求调整)
实现步骤:
1.定义HTML页面结构,由于我是在script标签中使用了JSX语法,所以结构写在render函数的return里面,如果在template里面其实更简单,我这里也给出template的结构
{
label: "商品e-ID",
prop: "eid",
render: row => {
let QRcodeName = row.eid + "-" + row.version
let clickstyle = 'left:'+proxy.left+'px'+';'+'top:'+proxy.top+'px'
// console.log(clickstyle)
// console.log(row.visible,969696)
if (!row.eidQrcode.smallImageUrl) return (<el-button onClick={() => proxy.makeQRcode(row)} type="text" >点击生成</el-button>)
return (
<div class="Ercode" onClick={() => proxy.cancelMenu(row)} onContextmenu={() => {proxy.openMenu(event,row)}} style="width:60px;margin:0 auto;">
<el-image
style="width:60px;height:60px;margin-right:5px;"
fit="cover"
src={row.eidQrcode.smallImageUrl}
preview-src-list={[row.eidQrcode.imageUrl]}
/>
<div class="myclick" v-show={row.visible && proxy.visible} style={clickstyle} >
<ul>
<li onClick={() => proxy.downloadthis(row)}>保存</li>
<li onClick={() => proxy.cancelMenu(row)}>取消</li>
</ul>
</div>
</div>
)
}
},
<div class="mask" @click="cancelMenu" @contextmenu.prevent="openMenu($event)">
</div>
<div class="myclick" v-show="visible" :style="{'left':left+'px','top':top+'px'}" >
<ul class="contextmenu">
<li @click="downloadthis">另存为</li>
<li @click="cancelMenu">取消</li>
</ul>
</div>
2.编写css代码结构,这里的代码没什么特别的,我将两个需要注意的点,一个是需要为myclick设置position为fixed,第二就是为他设置一个较高的层级,这样就能正常显示右键出现的div,不然可能会被遮住或者不显示。
.mask {
position: relative;
width:240px;
height:70px;
background:skyblue
}
.myclick {
position: fixed;
z-index: 99999;
width:120px;
height:60px;
background:white;
border-radius: 5px;
}
.myclick li {
list-style: none;
/* padding-left: 4px; */
margin: 4px;
border-radius: 5px;
color: #1F2329;
}
.myclick li:hover {
background-color: #EDEEEE;
margin: 4px;
}
3.编写方法部分,主要是打开openMenu的方法和取消以及点中的事件处理,这里需要注意的也有两个点,一个是参数的传入,一个是弹窗关闭的处理,我会在结尾处细讲这些问题,先展示代码
// 自定义右键下载按钮
// 检测页面滚动就关闭弹窗
const changeScoll = ()=>{
// console.log("检测到滚动了嘛?")
if (proxy.visible == true) {
proxy.visible = false
}
}
const openMenu = (e,row)=> {
console.log("点击了替换后的鼠标右键函数!")
if (!proxy.visible){
proxy.visible = true
}else{
document.body.addEventListener("click",function(){
// console.log("必须在界面外部点击后移除 不然会很大bug")
proxy.visible = false
})
}
e.preventDefault()
var x = e.pageX;
var y = e.pageY;
proxy.top = y;
proxy.left = x;
// let body = document.querySelector("body")
// body.onClick = function(row){
// console.log("绑定上了吗?")
// row.visible=false
// }
row.visible = true;//在这里控制右键菜单的打开
}
const cancelMenu = (row)=>{
if (row.visible == true){
console.log("取消点击")
row.visible = false;
}
}
const downloadthis =(row) => {
console.log("选中点击")
let QRcodeName = row.eid + "-" + row.version
proxy.download(row.eidQrcode.imageUrl, QRcodeName)
row.visible = false;
}
// 自定义右键下载按钮
4.数据的定义以及返回:
4.1数据的定义:
// 新调整,自定义右键下载按钮
const scrollTop = ref(0)
const visible = ref(true)
const top=ref(0)
const left = ref(0)
4.2数据以及方法的return(如果不做return不能在template中使用)
return {
// 自定义右键下载按钮
changeScoll,
cancelMenu,
downloadthis,
visible,
openMenu,
// 自定义右键下载按钮
}
5.方法的注意点:
其实也有比较多的插件可以使用,如果有符合预期的可以直接使用,由于我这个是自己写的,所以不可避免的就是bug的处理,有着较多的不符合预期现象产生,下面我分别提出问题以及解决:
①点击右键后,点击其他部分myclick部分依旧存在,预期是希望能够和游览器中的一样,点击其他部分就消失
问题解决:
代码部分:
if (!proxy.visible){
proxy.visible = true
}else{
document.body.addEventListener("click",function(){
// console.log("必须在界面外部点击后移除 不然会很大bug")
proxy.visible = false
})
}
思路是当点击打开弹窗的时候,为全局添加一个点击事件,如果超出了预期部分,比如我这里就是希望修改二维码部分的右键事件,其他部分照常使用,所以超出部分为body设置点击事件,结果是关闭弹窗
②在vue中添加@contextmenu.prevent即可阻止默认的鼠标右键的事件,但是语法无法在jsx中正常使用
问题解决:
采用了阻止默认事件的方法,禁止鼠标右键e.preventDefault()
③当页面发现变化后,或者说屏幕滚动的时候,右键打开的弹窗不能关闭会一直挂在那里,非常影响操作,较为严重的bug
代码部分:
const changeScoll = ()=>{
// console.log("检测到滚动了嘛?")
if (proxy.visible == true) {
proxy.visible = false
}
}
思路就是监视页面的滚动,一旦相关区域发生了scroll滚动的话就即使关闭视窗就可以了
④右键需要保存部分,整个cloumn部分的二维码处都弹出来了弹窗,这是因为如果只绑定了一个visible,使用proxy.visible控制,自然就会全部打开,因为每一个row用的都是同一个变量,这里需要为每一个row设置单独的ref变量,但是jsx中无法定义ref变量,只能使用js语句
代码部分:
if (data.records[0].devStatus){
item.visible = ref(false)
})
}
思路是在basic模板的地方加入一个ref变量,这里的if条件就是你需要加入的地方比如我这里是总表部分,为什么需要判断条件呢?因为如果是全加的话其他部分也会默认加上,我这里的basic模板是一个通用模板,所以在需要加入的页面中的cloumn的每一个row加入一个visible变量来控制每一个小row的二维码弹窗的展示即可,值得注意的是我这里处理row.visible来控制弹窗还引入了proxy.visible公共变量控制,这里是因为除了每个小条件以外,大家都有一个公共的特点,那就当页面滚动的时候和点击外部的时候关闭,所以这里可以使用一个变量来控制,所以看的时候不要搞混了。
<div class="myclick" v-show的控制用了两个变量 v-show={row.visible && proxy.visible} style={clickstyle} >
<ul>
<li onClick={() => proxy.downloadthis(row)}>保存</li>
<li onClick={() => proxy.cancelMenu(row)}>取消</li>
</ul>
</div>
补充:(个人感觉可能有错)
我感觉jsx主要还是和react相关,虽然带我的大佬说关系不大,但是我搜索相关问题的时候弹出大多都是react相关,因为我目前主要用的开发语言是vue,当初学的react比较基础也忘的差不多了,后续在业务不忙的时候学习一个回顾react,到时候会出一个补坑的文章,预测标题应该是vue和react中使用jsx需要的注意点。