Răsfoiți Sursa

json格式化增加图片的鼠标跟随预览

zxlie 4 luni în urmă
părinte
comite
87302c2a2e

+ 81 - 0
apps/json-format/format-lib.js

@@ -539,6 +539,87 @@ window.Formatter = (function () {
             }
         });
 
+        // 图片预览功能:针对所有data-is-link=1的a标签
+        let $imgPreview = null;
+        // 加载缓存
+        function getImgCache() {
+            try {
+                return JSON.parse(sessionStorage.getItem('fehelper-img-preview-cache') || '{}');
+            } catch (e) { return {}; }
+        }
+        function setImgCache(url, isImg) {
+            let cache = getImgCache();
+            cache[url] = isImg;
+            sessionStorage.setItem('fehelper-img-preview-cache', JSON.stringify(cache));
+        }
+        $('#jfContent').on('mouseenter', 'a[data-is-link="1"]', function(e) {
+            const url = $(this).attr('data-link-url');
+            if (!url) return;
+            let cache = getImgCache();
+            if (cache.hasOwnProperty(url)) {
+                if (cache[url]) {
+                    if (!$imgPreview || !$imgPreview.length) {
+                        $imgPreview = $('#fh-img-preview');
+                        if (!$imgPreview.length) {
+                            $imgPreview = $('<div id="fh-img-preview" style="position:fixed;z-index:999999;border:1px solid #ccc;background:#fff;padding:4px;box-shadow:0 2px 8px #0002;pointer-events:none;"><img style="max-width:300px;max-height:200px;display:block;"></div>').appendTo('body');
+                        }
+                    }
+                    $imgPreview.find('img').attr('src', url);
+                    $imgPreview.show();
+                    $(document).on('mousemove.fhimg', function(ev) {
+                        $imgPreview.css({
+                            left: ev.pageX + 20 + 'px',
+                            top: ev.pageY + 20 + 'px'
+                        });
+                    });
+                    $imgPreview.css({
+                        left: e.pageX + 20 + 'px',
+                        top: e.pageY + 20 + 'px'
+                    });
+                }
+                return;
+            }
+            // 创建图片对象尝试加载
+            const img = new window.Image();
+            img.src = url;
+            img.onload = function() {
+                // 保证页面上只存在一个浮窗节点
+                if (!$imgPreview || !$imgPreview.length) {
+                    $imgPreview = $('#fh-img-preview');
+                    if (!$imgPreview.length) {
+                        $imgPreview = $('<div id="fh-img-preview" style="position:fixed;z-index:999999;border:1px solid #ccc;background:#fff;padding:4px;box-shadow:0 2px 8px #0002;pointer-events:none;"><img style="max-width:300px;max-height:200px;display:block;"></div>').appendTo('body');
+                    }
+                }
+                $imgPreview.find('img').attr('src', url);
+                $imgPreview.show();
+                $(document).on('mousemove.fhimg', function(ev) {
+                    $imgPreview.css({
+                        left: ev.pageX + 20 + 'px',
+                        top: ev.pageY + 20 + 'px'
+                    });
+                });
+                $imgPreview.css({
+                    left: e.pageX + 20 + 'px',
+                    top: e.pageY + 20 + 'px'
+                });
+            };
+            img.onerror = function() {
+                setImgCache(url, false);
+            };
+        }).on('mouseleave', 'a[data-is-link="1"]', function(e) {
+            if ($imgPreview) $imgPreview.hide();
+            $(document).off('mousemove.fhimg');
+        });
+
+        // 新增:全局监听,防止浮窗残留
+        $(document).on('mousemove.fhimgcheck', function(ev) {
+            let $target = $(ev.target).closest('a[data-is-link="1"]');
+            if ($target.length === 0) {
+                if ($imgPreview) $imgPreview.hide();
+                $(document).off('mousemove.fhimg');
+            }
+        });
+
     };
     
     /**

+ 16 - 0
apps/json-format/index.css

@@ -172,3 +172,19 @@ html.fh-jf .x-toolbar.x-inpage {
     background:#ebebeb -webkit-linear-gradient(#fefefe, #f8f8f8 40%, #e9e9e9);border-color:#999;color:#222}
 #btnLeftRight.selected, #btnUpDown.selected{-webkit-box-shadow:inset 0px 1px 5px rgba(0,0,0,0.2);
     background:#ebebeb -webkit-linear-gradient(#e4e4e4, #dfdfdf 40%, #dcdcdc);color:#333}
+
+#fh-img-preview {
+  display: none;
+  pointer-events: none;
+  border-radius: 4px;
+  background: #fff;
+  box-shadow: 0 2px 8px #0002;
+  padding: 4px;
+  max-width: 320px;
+  max-height: 220px;
+}
+#fh-img-preview img {
+  max-width: 300px;
+  max-height: 200px;
+  display: block;
+}

+ 1 - 1
apps/json-format/index.js

@@ -324,7 +324,7 @@ new Vue({
         },
 
         setDemo: function () {
-            let demo = '{"BigIntSupported":995815895020119788889,"date":"20180322","url":"https://www.baidu.com?wd=fehelper","message":"Success !","status":200,"city":"北京","count":632,"data":{"shidu":"34%","pm25":73,"pm10":91,"quality":"良","wendu":"5","ganmao":"极少数敏感人群应减少户外活动","yesterday":{"date":"21日星期三","sunrise":"06:19","high":"高温 11.0℃","low":"低温 1.0℃","sunset":"18:26","aqi":85,"fx":"南风","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"},"forecast":[{"date":"22日星期四","sunrise":"06:17","high":"高温 17.0℃","low":"低温 1.0℃","sunset":"18:27","aqi":98,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"23日星期五","sunrise":"06:16","high":"高温 18.0℃","low":"低温 5.0℃","sunset":"18:28","aqi":118,"fx":"无持续风向","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"},{"date":"24日星期六","sunrise":"06:14","high":"高温 21.0℃","low":"低温 7.0℃","sunset":"18:29","aqi":52,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"25日星期日","sunrise":"06:13","high":"高温 22.0℃","low":"低温 7.0℃","sunset":"18:30","aqi":71,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"26日星期一","sunrise":"06:11","high":"高温 21.0℃","low":"低温 8.0℃","sunset":"18:31","aqi":97,"fx":"西南风","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"}]}}';
+            let demo = '{"BigIntSupported":995815895020119788889,"date":"20180322","url":"https://www.baidu.com?wd=fehelper","img":"http://gips0.baidu.com/it/u=1490237218,4115737545&fm=3028&app=3028&f=JPEG&fmt=auto?w=1280&h=720","message":"Success !","status":200,"city":"北京","count":632,"data":{"shidu":"34%","pm25":73,"pm10":91,"quality":"良","wendu":"5","ganmao":"极少数敏感人群应减少户外活动","yesterday":{"date":"21日星期三","sunrise":"06:19","high":"高温 11.0℃","low":"低温 1.0℃","sunset":"18:26","aqi":85,"fx":"南风","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"},"forecast":[{"date":"22日星期四","sunrise":"06:17","high":"高温 17.0℃","low":"低温 1.0℃","sunset":"18:27","aqi":98,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"23日星期五","sunrise":"06:16","high":"高温 18.0℃","low":"低温 5.0℃","sunset":"18:28","aqi":118,"fx":"无持续风向","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"},{"date":"24日星期六","sunrise":"06:14","high":"高温 21.0℃","low":"低温 7.0℃","sunset":"18:29","aqi":52,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"25日星期日","sunrise":"06:13","high":"高温 22.0℃","low":"低温 7.0℃","sunset":"18:30","aqi":71,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"26日星期一","sunrise":"06:11","high":"高温 21.0℃","low":"低温 8.0℃","sunset":"18:31","aqi":97,"fx":"西南风","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"}]}}';
             editor.setValue(demo);
             this.$nextTick(() => {
                 this.format();

+ 3 - 3
apps/json-format/json-worker.js

@@ -128,7 +128,7 @@ function formatStringValue(str) {
     if (urlRegex.test(str)) {
         // 如果是URL,转换为链接
         const escapedUrl = htmlspecialchars(str);
-        return '<a href="' + escapedUrl + '" target="_blank" rel="noopener noreferrer">' + htmlspecialchars(str) + '</a>';
+        return '<a href="' + escapedUrl + '" target="_blank" rel="noopener noreferrer" data-is-link="1" data-link-url="' + escapedUrl + '">' + htmlspecialchars(str) + '</a>';
     } else {
         // 直接显示解析后的字符串内容,不需要重新转义
         // 这样可以保持用户原始输入的意图
@@ -154,8 +154,8 @@ function createNode(value) {
                     // 判断原始字符串是否为URL
                     if (isUrl(this.value)) {
                         // 用JSON.stringify保证转义符显示,内容包裹在<a>里
-                        return '<div class="item item-line"><span class="string"><a href="' 
-                            + htmlspecialchars(this.value) + '" target="_blank" rel="noopener noreferrer">' 
+                        return '<div class="item item-line"><span class="string"><a href="'
+                            + htmlspecialchars(this.value) + '" target="_blank" rel="noopener noreferrer" data-is-link="1" data-link-url="' + htmlspecialchars(this.value) + '">' 
                             + htmlspecialchars(JSON.stringify(this.value)) + '</a></span></div>';
                     } else {
                         return '<div class="item item-line"><span class="string">' + formatStringValue(JSON.stringify(this.value)) + '</span></div>';