qb-pc-sdk 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ !function(n){"use strict";var e=void 0!==n&&n.window?n.window:"undefined"!=typeof window?window:n,i=e.document;if(i&&!e.AdSDK){var r=e.navigator&&e.navigator.userAgent||"",d=e.navigator&&e.navigator.platform||"";if(!/Android|iPhone|iPad|iPod|Mac|webOS|BlackBerry|IEMobile|Opera Mini/i.test(r)&&/Win|Windows/i.test(r+d)){e._qbPcSdkLoading=!0;var o="./core.min.js";if(i.currentScript&&i.currentScript.src&&(o=i.currentScript.src.replace(/\/[^/]+\.js$/i,"/core.min.js")),i.querySelector('script[src="'+o+'"]'))c(null);else{var t=i.createElement("script");t.src=o,t.async=!0,t.onload=function(){e.GDTAdSDK&&e.AdSDK?c(null):setTimeout(function(){c(e.GDTAdSDK&&e.AdSDK?null:new Error("SDK\u521d\u59cb\u5316\u5931\u8d25"))},100)},t.onerror=function(){c(new Error("SDK\u52a0\u8f7d\u5931\u8d25"))},i.head.appendChild(t)}}}function c(n){e._qbPcSdkLoading=!1,e.dispatchEvent(new CustomEvent("qb-pc-sdk-ready",{detail:n?{error:n,AdSDK:null,GDTAdSDK:null}:{AdSDK:e.AdSDK,GDTAdSDK:e.GDTAdSDK}}))}}("undefined"!=typeof window?window:"undefined"!=typeof global?global:this);
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "qb-pc-sdk",
3
- "version": "1.3.0",
4
- "description": "pc广告 SDK 封装器 - 去除容灾",
3
+ "version": "1.3.2",
4
+ "description": "pc广告 SDK 封装器 - 新增懒加载模式",
5
5
  "main": "core.min.js",
6
6
  "files": [
7
7
  "core.min.js",
8
8
  "inline-loader.js",
9
+ "inline-loader-local.js",
9
10
  "index.js","src",
10
11
  "README.md"
11
12
  ],
@@ -422,6 +422,7 @@
422
422
  }
423
423
 
424
424
  async _loadAd() {
425
+ if (this._isUnsupportedPlatform) return;
425
426
  try {
426
427
  await window.GDTAdSDK.init({ appId: this.gdtAppId });
427
428
 
@@ -662,6 +663,66 @@
662
663
 
663
664
  return true;
664
665
  }
666
+
667
+ var lazyAdObserver = null;
668
+ function loadLazyAd(element) {
669
+ if (element._qbAdInitialized) return;
670
+ var appId = element.getAttribute('data-app-id');
671
+ var placementId = element.getAttribute('data-ad-id') || element.getAttribute('data-placement-id');
672
+ if (!appId || !placementId) return;
673
+ element._qbAdInitialized = true;
674
+ element.innerHTML = '';
675
+ try {
676
+ var adSDKInstance = new window.AdSDK({
677
+ appId: appId,
678
+ placementId: placementId,
679
+ container: element,
680
+ onAdLoaded: function(ad, instance) {
681
+ if (window.qbAds._onAdLoaded && typeof window.qbAds._onAdLoaded === 'function') {
682
+ window.qbAds._onAdLoaded.call(this, ad, instance, element);
683
+ }
684
+ },
685
+ onAdError: function(err, msg) {
686
+ if (window.qbAds._onAdError && typeof window.qbAds._onAdError === 'function') {
687
+ window.qbAds._onAdError.call(this, err, msg, element);
688
+ }
689
+ },
690
+ onAdExpose: function() {
691
+ if (window.qbAds._onAdExpose && typeof window.qbAds._onAdExpose === 'function') {
692
+ window.qbAds._onAdExpose.call(this, element);
693
+ }
694
+ },
695
+ onAdClick: function() {
696
+ if (window.qbAds._onAdClick && typeof window.qbAds._onAdClick === 'function') {
697
+ window.qbAds._onAdClick.call(this, element);
698
+ }
699
+ }
700
+ });
701
+ window._qbAdsInstances.push({ element: element, instance: adSDKInstance });
702
+ } catch (error) {
703
+ element._qbAdInitialized = false;
704
+ }
705
+ }
706
+ function startLazyAdObserver() {
707
+ if (!window.AdSDK || !window.GDTAdSDK) return;
708
+ var lazyEls = window.document.querySelectorAll('.lazy-ad');
709
+ if (lazyEls.length === 0) return;
710
+ if (!lazyAdObserver) {
711
+ lazyAdObserver = new window.IntersectionObserver(function(entries) {
712
+ entries.forEach(function(entry) {
713
+ if (!entry.isIntersecting) return;
714
+ var el = entry.target;
715
+ loadLazyAd(el);
716
+ lazyAdObserver.unobserve(el);
717
+ });
718
+ }, { root: null, rootMargin: '200px', threshold: 0 });
719
+ }
720
+ lazyEls.forEach(function(el) {
721
+ if (el._qbLazyObserved) return;
722
+ el._qbLazyObserved = true;
723
+ lazyAdObserver.observe(el);
724
+ });
725
+ }
665
726
 
666
727
  const originalPush = window.qbAds.push.bind(window.qbAds);
667
728
 
@@ -670,6 +731,7 @@
670
731
  if (window.AdSDK && window.GDTAdSDK) {
671
732
  setTimeout(function() {
672
733
  initAllAdSlots();
734
+ startLazyAdObserver();
673
735
  }, 0);
674
736
  }
675
737
  };
@@ -692,13 +754,14 @@
692
754
  }
693
755
  }
694
756
 
695
- // 尝试初始化所有广告位
757
+ // 尝试初始化所有广告位(即插即用 ins)
696
758
  const initialized = initAllAdSlots();
759
+ startLazyAdObserver();
697
760
 
698
761
  if (!initialized && window.AdSDK && window.GDTAdSDK) {
699
- // 如果 SDK 已经加载但初始化失败,稍后重试
700
762
  setTimeout(function() {
701
763
  initAllAdSlots();
764
+ startLazyAdObserver();
702
765
  }, 100);
703
766
  }
704
767
 
@@ -711,30 +774,31 @@
711
774
  setTimeout(function() {
712
775
  if (window.AdSDK && window.GDTAdSDK) {
713
776
  initAllAdSlots();
777
+ startLazyAdObserver();
714
778
  }
715
779
  }, 0);
716
780
  } else {
717
- // 监听 DOMContentLoaded 事件
718
781
  window.addEventListener('DOMContentLoaded', function() {
719
782
  setTimeout(function() {
720
783
  if (window.AdSDK && window.GDTAdSDK) {
721
784
  initAllAdSlots();
785
+ startLazyAdObserver();
722
786
  }
723
787
  }, 0);
724
788
  });
725
789
  }
726
790
 
727
- // 如果 SDK 已经加载完成(同步加载的情况),立即尝试初始化
728
791
  if (window.AdSDK && window.GDTAdSDK) {
729
792
  setTimeout(function() {
730
793
  initAllAdSlots();
794
+ startLazyAdObserver();
731
795
  }, 0);
732
796
  }
733
797
 
734
- // 监听 SDK 就绪事件(异步加载的情况)
735
798
  window.addEventListener('qb-pc-sdk-ready', function() {
736
799
  setTimeout(function() {
737
800
  initAllAdSlots();
801
+ startLazyAdObserver();
738
802
  }, 0);
739
803
  });
740
804
 
@@ -742,18 +806,20 @@
742
806
  if (window.MutationObserver) {
743
807
  const observer = new window.MutationObserver(function(mutations) {
744
808
  let shouldInit = false;
809
+ let shouldInitLazy = false;
745
810
  mutations.forEach(function(mutation) {
746
811
  mutation.addedNodes.forEach(function(node) {
747
812
  if (node.nodeType === 1) {
748
- // 检查是否是广告位标签,或其包含广告位标签
749
813
  if (node.tagName && node.tagName.toLowerCase() === 'ins' &&
750
814
  node.classList && node.classList.contains('qb-adsbyqubian')) {
751
815
  shouldInit = true;
752
- } else if (node.querySelectorAll) {
816
+ } else if (node.classList && node.classList.contains('lazy-ad')) {
817
+ shouldInitLazy = true;
818
+ }
819
+ if (node.querySelectorAll) {
753
820
  const adSlots = node.querySelectorAll('ins.qb-adsbyqubian');
754
- if (adSlots.length > 0) {
755
- shouldInit = true;
756
- }
821
+ if (adSlots.length > 0) shouldInit = true;
822
+ if (node.querySelectorAll('.lazy-ad').length > 0) shouldInitLazy = true;
757
823
  }
758
824
  }
759
825
  });
@@ -762,7 +828,12 @@
762
828
  if (shouldInit && window.AdSDK && window.GDTAdSDK) {
763
829
  setTimeout(function() {
764
830
  initAllAdSlots();
765
- }, 100); // 延迟一点,确保 DOM 完全插入
831
+ }, 100);
832
+ }
833
+ if (shouldInitLazy && window.AdSDK && window.GDTAdSDK) {
834
+ setTimeout(function() {
835
+ startLazyAdObserver();
836
+ }, 100);
766
837
  }
767
838
  });
768
839
 
@@ -1,26 +1,87 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="zh-CN">
3
+
3
4
  <head>
4
5
  <meta charset="UTF-8">
5
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
7
  <title>Native广告异步加载测试</title>
7
- <!-- 内联版本:极简引导器,只负责容灾和异步加载,Windows环境检测在loader.min.js -->
8
- <!-- <script>
9
- (function(g){"use strict";var w=g&&g.window?g.window:(typeof window!=="undefined"?window:g),d=w.document;if(!d||w._qbPcSdkLoading||w.AdSDK)return;w._qbPcSdkLoading=true;var pr="https://unpkg.com/qb-pc-sdk@latest/loader.min.js",fb="https://file.qubiankeji.com/qb-pc-sdk/loader.min.js";var loaded=false;var timeoutId=setTimeout(function(){if(!loaded&&fb&&!d.querySelector('script[src="'+fb+'"]')){loaded=true;var fs=d.createElement("script");fs.src=fb;fs.async=true;fs.onerror=function(){w._qbPcSdkLoading=false;w.dispatchEvent(new CustomEvent("qb-pc-sdk-ready",{detail:{error:new Error("SDK加载失败"),AdSDK:null,GDTAdSDK:null}}));};d.head.appendChild(fs);}},2000);var s=d.createElement("script");s.src=pr;s.async=true;s.onload=function(){if(!loaded){loaded=true;clearTimeout(timeoutId);}};s.onerror=function(){if(!loaded){loaded=true;clearTimeout(timeoutId);if(fb&&!d.querySelector('script[src="'+fb+'"]')){var fs=d.createElement("script");fs.src=fb;fs.async=true;fs.onerror=function(){w._qbPcSdkLoading=false;w.dispatchEvent(new CustomEvent("qb-pc-sdk-ready",{detail:{error:new Error("SDK加载失败"),AdSDK:null,GDTAdSDK:null}}));};d.head.appendChild(fs);}else{w._qbPcSdkLoading=false;w.dispatchEvent(new CustomEvent("qb-pc-sdk-ready",{detail:{error:new Error("SDK加载失败"),AdSDK:null,GDTAdSDK:null}}));}}};d.head.appendChild(s);})(typeof window!=="undefined"?window:(typeof global!=="undefined"?global:this));
10
- </script> -->
11
- <script src="https://www.qubiankeji.com/file/inline-loader.js" defer></script>
8
+ <script src="https://unpkg.com/qb-pc-sdk@latest/inline-loader.js" defer></script>
12
9
  <style>
13
- body { margin: 0; padding: 20px; font-family: sans-serif; background: #f0f2f5; }
14
- .control-panel { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); margin-bottom: 20px; display: flex; gap: 15px; max-width: 900px; margin: 0 auto; }
15
- .input-group { display: flex; flex-direction: column; gap: 6px; flex: 1; }
16
- button#loadBtn { padding: 10px 24px; background-color: #007bff; color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: 600; height: 42px; }
17
- button#loadBtn:disabled { background-color: #ccc; cursor: not-allowed; }
18
- #ad-slot-wrapper { max-width: 900px; margin: 20px auto; background: #fff; padding: 20px; border-radius: 8px; min-height: 240px; border: 2px dashed #e0e0e0; }
19
- #log-container { max-width: 900px; margin: 20px auto; background: #2d2d2d; color: #00ff00; padding: 15px; border-radius: 8px; font-family: monospace; font-size: 12px; height: 250px; overflow-y: auto; }
20
- .log-error { color: #ff4444; }
21
- .log-success { color: #00ff00; }
10
+ body {
11
+ margin: 0;
12
+ padding: 20px;
13
+ font-family: sans-serif;
14
+ background: #f0f2f5;
15
+ }
16
+
17
+ .control-panel {
18
+ background: white;
19
+ padding: 20px;
20
+ border-radius: 8px;
21
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
22
+ margin-bottom: 20px;
23
+ display: flex;
24
+ gap: 15px;
25
+ max-width: 900px;
26
+ margin: 0 auto;
27
+ }
28
+
29
+ .input-group {
30
+ display: flex;
31
+ flex-direction: column;
32
+ gap: 6px;
33
+ flex: 1;
34
+ }
35
+
36
+ button#loadBtn {
37
+ padding: 10px 24px;
38
+ background-color: #007bff;
39
+ color: white;
40
+ border: none;
41
+ border-radius: 6px;
42
+ cursor: pointer;
43
+ font-weight: 600;
44
+ height: 42px;
45
+ }
46
+
47
+ button#loadBtn:disabled {
48
+ background-color: #ccc;
49
+ cursor: not-allowed;
50
+ }
51
+
52
+ #ad-slot-wrapper {
53
+ max-width: 900px;
54
+ margin: 20px auto;
55
+ background: #fff;
56
+ padding: 20px;
57
+ border-radius: 8px;
58
+ min-height: 240px;
59
+ border: 2px dashed #e0e0e0;
60
+ }
61
+
62
+ #log-container {
63
+ max-width: 900px;
64
+ margin: 20px auto;
65
+ background: #2d2d2d;
66
+ color: #00ff00;
67
+ padding: 15px;
68
+ border-radius: 8px;
69
+ font-family: monospace;
70
+ font-size: 12px;
71
+ height: 250px;
72
+ overflow-y: auto;
73
+ }
74
+
75
+ .log-error {
76
+ color: #ff4444;
77
+ }
78
+
79
+ .log-success {
80
+ color: #00ff00;
81
+ }
22
82
  </style>
23
83
  </head>
84
+
24
85
  <body>
25
86
 
26
87
  <div class="control-panel">
@@ -65,7 +126,7 @@
65
126
  }
66
127
 
67
128
  // --- 核心逻辑:处理异步加载的时序 ---
68
-
129
+
69
130
  const initUI = () => {
70
131
  const loadBtn = document.getElementById('loadBtn');
71
132
  loadBtn.disabled = false;
@@ -102,7 +163,7 @@
102
163
 
103
164
  function handleLoadClick() {
104
165
  if (!isSdkReady) return;
105
-
166
+
106
167
  const appId = document.getElementById('appIdInput').value.trim();
107
168
  const placementId = document.getElementById('placementIdInput').value.trim();
108
169
 
@@ -130,4 +191,5 @@
130
191
  document.getElementById('loadBtn').onclick = handleLoadClick;
131
192
  </script>
132
193
  </body>
194
+
133
195
  </html>
@@ -0,0 +1,37 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Native 广告懒加载测试 (SDK 内置 .lazy-ad)</title>
7
+ <!-- 用户只需引用 SDK,懒加载由 SDK 内部 IntersectionObserver 完成 -->
8
+ <script src="https://unpkg.com/qb-pc-sdk@latest/inline-loader.js" defer></script>
9
+ <style>
10
+ body { margin: 0; padding: 20px; font-family: sans-serif; background: #f0f2f5; }
11
+ .section { max-width: 900px; margin: 0 auto 24px; background: #fff; padding: 24px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
12
+ .section h2 { margin: 0 0 16px; font-size: 18px; color: #333; }
13
+ .lazy-ad { min-height: 220px; border: 2px dashed #e0e0e0; border-radius: 8px; display: flex; align-items: center; justify-content: center; color: #999; font-size: 14px; box-sizing: border-box; }
14
+ </style>
15
+ </head>
16
+ <body>
17
+
18
+ <div class="section">
19
+ <h2>首屏广告位</h2>
20
+ <div class="lazy-ad" id="ad-pos-1" data-app-id="2009110913851875373" data-ad-id="2009111010614468619">广告位 1 - 进入视口约 200px 内时加载</div>
21
+ </div>
22
+
23
+ <div class="section" style="height: 400px;">
24
+ <h2>占位内容(向下滚动触发下方广告)</h2>
25
+ </div>
26
+
27
+ <div class="section">
28
+ <h2>下方广告位</h2>
29
+ <div class="lazy-ad" id="ad-pos-2" data-app-id="2009110913851875373" data-ad-id="2009111010614468619">广告位 2 - 懒加载</div>
30
+ </div>
31
+
32
+ <p style="max-width:900px;margin:20px auto;color:#666;font-size:14px;">
33
+ 接入说明:页面中放入 <code>&lt;div class="lazy-ad" data-app-id="应用ID" data-ad-id="广告位ID"&gt;&lt;/div&gt;</code>,引用 SDK 后即可自动懒加载(rootMargin 200px),无需额外脚本。
34
+ </p>
35
+
36
+ </body>
37
+ </html>