标签中的文本内容\r\n const figcaption = figure.querySelector('figcaption');\r\n if (figcaption) {\r\n const figureText = figcaption.textContent.replace(/\\s+/g, ' ').trim();\r\n textContent = textContent.replace(figureText, '');\r\n }\r\n });\r\n\r\n // 函数:递归移除子节点中的标签,仅保留文本内容\r\n function removeInnerTags(node) {\r\n const childNodes = Array.from(node.childNodes);\r\n childNodes.forEach((child) => {\r\n if (child.nodeType === Node.ELEMENT_NODE) {\r\n removeInnerTags(child); // 递归处理子节点\r\n const textContent = child.textContent;\r\n child.replaceWith(textContent);\r\n }\r\n });\r\n }\r\n\r\n // 函数:获取标签内的纯文本内容\r\n function getTextContent(node) {\r\n return node.textContent.replace(/\\s+/g, ' ').trim();\r\n }\r\n\r\n // 获取所有 标签的文本内容,并保留 和 标签的结构\r\n const formattedPTags = Array.from(doc.querySelectorAll('p')).map((p) => {\r\n const cloneP = p.cloneNode(true);\r\n const childNodes = Array.from(cloneP.childNodes);\r\n\r\n childNodes.forEach((node) => {\r\n if (node.nodeType === Node.ELEMENT_NODE) {\r\n if (node.nodeName === 'STRONG' || node.nodeName === 'EM') {\r\n removeInnerTags(node);\r\n } else {\r\n const textContent = node.textContent;\r\n node.replaceWith(textContent);\r\n }\r\n }\r\n });\r\n\r\n return {\r\n tag: 'p',\r\n content: getTextContent(cloneP),\r\n };\r\n });\r\n\r\n // 构建新的 HTML 结构\r\n let resultHTML = textContent;\r\n\r\n formattedPTags.forEach((pTag) => {\r\n if (resultHTML.includes(pTag.content)) {\r\n resultHTML = resultHTML.replace(pTag.content, `${pTag.content}
`);\r\n }\r\n });\r\n\r\n // 临时容器,用于进一步处理 和 标签\r\n const tempDiv = document.createElement('div');\r\n tempDiv.innerHTML = resultHTML;\r\n\r\n const elementsToWrap = ['strong', 'em'];\r\n\r\n elementsToWrap.forEach((tag) => {\r\n const nodes = tempDiv.querySelectorAll(tag);\r\n nodes.forEach((node) => {\r\n const content = getTextContent(node);\r\n if (resultHTML.includes(content)) {\r\n resultHTML = resultHTML.replace(content, `<${tag}>${content}${tag}>`);\r\n }\r\n });\r\n });\r\n\r\n // 处理 和 标签中的嵌套标签\r\n elementsToWrap.forEach((tag) => {\r\n const nodes = tempDiv.querySelectorAll(tag);\r\n nodes.forEach((node) => {\r\n removeInnerTags(node);\r\n });\r\n });\r\n\r\n return tempDiv.innerHTML;\r\n}\r\nexport default {\r\n timeDifference,\r\n handleScroll,\r\n translateLabels,\r\n removeContinueReading,\r\n extractAndFormatPTags,\r\n};\r\n","\n \n
\n \n
\n \n
\n
![\"thumbnail\"]()
\n
\n
\n
\n
\n \n \n
\n
\n\n\n\n\n\n","import mod from \"-!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!../../node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./NewsView.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!../../node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./NewsView.vue?vue&type=script&lang=js\"","import { render, staticRenderFns } from \"./NewsView.vue?vue&type=template&id=b12e8964\"\nimport script from \"./NewsView.vue?vue&type=script&lang=js\"\nexport * from \"./NewsView.vue?vue&type=script&lang=js\"\nimport style0 from \"./NewsView.vue?vue&type=style&index=0&id=b12e8964&prod&lang=less\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/@vue/vue-loader-v15/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","var render = function render(){var _vm=this,_c=_vm._self._c;return _c('div',{staticClass:\"box\"},_vm._l((_vm.list),function(item,index){return _c('a',{key:index,staticClass:\"item\",attrs:{\"click_tracking_url\":item.click_tracking_url,\"impression_tracking_url\":item.impression_tracking_url},on:{\"click\":function($event){$event.preventDefault();return _vm.click_fun.apply(null, arguments)}}},[_c('span',{staticClass:\"title\"},[_vm._v(_vm._s(item.title))]),_c('span',[_vm._v(\"分类:\"+_vm._s(item.category))]),_c('span',[_vm._v(\"CTR:\"+_vm._s(item.ctr))]),_c('span',[_vm._v(\"时间:\"+_vm._s(_vm.checkTimestampWithinThreeDays(item.publish_time).status)+\" 日期:\"+_vm._s(_vm.checkTimestampWithinThreeDays(item.publish_time).timePoint))])])}),0)\n}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\r\n \r\n\r\n\r\n\r\n\r\n\r\n","import mod from \"-!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!../../node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./TestView.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[1]!../../node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./TestView.vue?vue&type=script&lang=js\"","import { render, staticRenderFns } from \"./TestView.vue?vue&type=template&id=d7f769f6&scoped=true\"\nimport script from \"./TestView.vue?vue&type=script&lang=js\"\nexport * from \"./TestView.vue?vue&type=script&lang=js\"\nimport style0 from \"./TestView.vue?vue&type=style&index=0&id=d7f769f6&prod&lang=less&scoped=true\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/@vue/vue-loader-v15/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"d7f769f6\",\n null\n \n)\n\nexport default component.exports","import Vue from 'vue';\nimport VueRouter from 'vue-router';\nimport NewsView from '../views/NewsView.vue';\nimport TestView from '../views/TestView.vue';\n\nVue.use(VueRouter);\n\nconst routes = [\n {\n path: '/',\n name: 'News',\n component: NewsView,\n },\n {\n path: '/test',\n name: 'Test',\n component: TestView,\n },\n];\n\nconst router = new VueRouter({\n mode: 'history',\n routes,\n});\nexport default router;\n","import Vue from 'vue';\nimport Vuex from 'vuex';\n\nVue.use(Vuex);\n\nexport default new Vuex.Store({\n state: {\n adData: [\n { div: `` },\n { div: `` },\n { div: `` },\n\n\n // { div: `` },\n\n\n { div: `` },\n { div: `` },\n { div: `` },\n ],\n count: 0,\n },\n getters: {},\n mutations: {\n countAdd(state) {\n // console.log('before countAdd', state.count);\n state.count++;\n // console.log(' countAdd over', state.count);\n },\n },\n actions: {},\n modules: {},\n});\n","import axios from 'axios';\r\n\r\naxios.defaults.baseURL = process.env.NODE_ENV === 'production' ? 'https://api.imelynews.com/feed' : '/feed';\r\naxios.interceptors.response.use(\r\n function (response) {\r\n return response.data;\r\n },\r\n function (error) {\r\n return Promise.reject(error);\r\n }\r\n);\r\n\r\nexport default axios;\r\n","import http from './http.js';\r\n// // 获取feed详情\r\nfunction getFeedDetail(id, country,client_info,os_ver,publish_time,channel,language,mocel,category) {\r\n return http.get(`/detail?fid=${id}&country=${country}&client_info=${client_info}&os_ver=${os_ver}&publish_time=${publish_time}&channel=${channel}&language=${language}&mocel=${mocel}&category=${category}`);\r\n}\r\n// 获取feed列表\r\nfunction getFeedList(category) {\r\n return http.get(`/list?category=${category}`);\r\n}\r\n\r\n//测试用 \r\nfunction testApi(token, count, client_info, user_ip, model, os_ver, language, country) {\r\n return http.get(`/m/list?token=${token}&count=${count}&client_info=${client_info}&user_ip=${user_ip}&model=${model}&os_version=${os_ver}&language=${language}&country=${country}`);\r\n // https://api.imelynews.com/feed/m/list?\r\n}\r\n\r\nfunction show(url) {\r\n url = url.replace('https://api.imelynews.com/feed', '');\r\n return http.get(`${url}`);\r\n}\r\n\r\nexport default {\r\n getFeedList,\r\n getFeedDetail,\r\n testApi,\r\n show,\r\n};\r\n","import Vue from \"vue\";\r\nimport App from \"./App.vue\";\r\nimport router from \"./router\";\r\nimport store from \"./store\";\r\nimport api from \"./api/index.js\"; //可以通过this.$api.xxx()调用`/src/http/index.js`中的xxx方法。\r\n// import Ads from \"vue-google-adsense\";\r\nimport Adsense from 'vue-google-adsense/dist/Adsense.min.js'\r\n\r\n\r\nVue.config.productionTip = false;\r\nVue.prototype.$api = api;\r\n\r\nVue.use(require('vue-script2'))\r\nVue.use(Adsense)\r\n\r\n// Vue.use(Ads.Adsense);\r\n// Vue.use(Ads.InArticleAdsense);\r\n// Vue.use(Ads.InFeedAdsense);\r\n\r\nnew Vue({\r\n router,\r\n store,\r\n render: (h) => h(App),\r\n}).$mount(\"#app\");\r\n\r\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","var deferred = [];\n__webpack_require__.O = function(result, chunkIds, fn, priority) {\n\tif(chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar chunkIds = deferred[i][0];\n\t\tvar fn = deferred[i][1];\n\t\tvar priority = deferred[i][2];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every(function(key) { return __webpack_require__.O[key](chunkIds[j]); })) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif(priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif(fulfilled) {\n\t\t\tdeferred.splice(i--, 1)\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = function(module) {\n\tvar getter = module && module.__esModule ?\n\t\tfunction() { return module['default']; } :\n\t\tfunction() { return module; };\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","// no baseURI\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t524: 0\n};\n\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n__webpack_require__.O.j = function(chunkId) { return installedChunks[chunkId] === 0; };\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = function(parentChunkLoadingFunction, data) {\n\tvar chunkIds = data[0];\n\tvar moreModules = data[1];\n\tvar runtime = data[2];\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif(chunkIds.some(function(id) { return installedChunks[id] !== 0; })) {\n\t\tfor(moduleId in moreModules) {\n\t\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif(runtime) var result = runtime(__webpack_require__);\n\t}\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n}\n\nvar chunkLoadingGlobal = self[\"webpackChunkapexnews\"] = self[\"webpackChunkapexnews\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));","// startup\n// Load entry module and return exports\n// This entry module depends on other loaded chunks and execution need to be delayed\nvar __webpack_exports__ = __webpack_require__.O(undefined, [504], function() { return __webpack_require__(8245); })\n__webpack_exports__ = __webpack_require__.O(__webpack_exports__);\n"],"names":["render","_vm","this","_c","_self","attrs","staticRenderFns","script","component","detailData","meta","staticClass","on","handleScroll","_v","_s","title","publisher","timeAgo","image_url","ref","url","language","continueReading","require","recommendedForYou","_l","groupedNews","group","item","key","id","_e","RelatedNewsData","fid","click_tracking_url","impression_tracking_url","style","getBackgroundImageStyle","publisher_icon","name","props","Object","data","methods","iconUrl","components","mounted","timeDifference","date","eventDate","Date","now","timeDiff","seconds","Math","floor","minutes","hours","days","weeks","months","years","getTimeAgo","timeUnits","de","value","unit","en","es","units","translateLabels","labels","percentageRead","format","num","round","abs","content","document","getElementById","rect","getBoundingClientRect","top","bottom","c","max","documentElement","clientHeight","window","innerHeight","t","b","ceil","removeContinueReading","text","phrases","forEach","phrase","regex","RegExp","replace","extractAndFormatPTags","htmlString","textContent","parser","DOMParser","doc","parseFromString","blacklist","figureTags","querySelectorAll","removeInnerTags","node","childNodes","Array","from","child","nodeType","Node","ELEMENT_NODE","replaceWith","getTextContent","trim","figure","figcaption","querySelector","figureText","formattedPTags","map","p","cloneP","cloneNode","nodeName","tag","resultHTML","pTag","includes","tempDiv","createElement","innerHTML","elementsToWrap","nodes","RelatedNews","relatedNewsData","startTime","content_html","getFeedDetailData","$route","query","country","client_info","os_ver","publish_time","channel","model","category","$api","getFeedDetail","JSON","parse","util","contentxml","handle_content","$nextTick","$refs","recList","error","handleLinkClick","event","targetElement","target","preventDefault","tagName","className","console","log","getAttribute","sendClickToGA","location","href","parentElement","sendToGA","endTime","getTime","sendViewToGA","handleIntersection","entries","observer","entry","isIntersecting","show","warn","unobserve","observeElements","IntersectionObserver","root","rootMargin","threshold","elements","element","observe","addEventListener","code","computed","pub_date","groups","i","length","push","slice","updated","beforeDestroy","removeEventListener","list","index","$event","click_fun","apply","arguments","ctr","checkTimestampWithinThreeDays","status","timePoint","token","count","user_ip","mdoel","os_version","fetchData","testApi","categoryCount","reduce","acc","totalCount","categoryPercentage","percentage","toFixed","parseFloat","sort","a","e","closestParentA","findClosestAParent","timestamp","threeDaysInMillis","formattedDate","getFullYear","String","getMonth","padStart","getDate","getHours","getMinutes","toLowerCase","parentNode","Vue","use","VueRouter","routes","path","NewsView","TestView","router","mode","Vuex","state","adData","div","getters","mutations","countAdd","actions","modules","axios","defaults","baseURL","interceptors","response","Promise","reject","mocel","http","get","getFeedList","config","productionTip","prototype","api","Adsense","store","h","App","$mount","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","call","m","deferred","O","result","chunkIds","fn","priority","notFulfilled","Infinity","fulfilled","j","keys","every","splice","r","n","getter","__esModule","d","definition","o","defineProperty","enumerable","g","globalThis","Function","obj","prop","hasOwnProperty","Symbol","toStringTag","installedChunks","chunkId","webpackJsonpCallback","parentChunkLoadingFunction","moreModules","runtime","some","chunkLoadingGlobal","self","bind","__webpack_exports__"],"sourceRoot":""}