您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Mortal牌谱解析增强脚本 (雀魂麻将/天凤/麻雀一番街)
当前为
// ==UserScript== // @name Mortal 显示恶手率 // @description Mortal牌谱解析增强脚本 (雀魂麻将/天凤/麻雀一番街) // @version 2.2.0 // @homepage https://www.bilibili.com/read/cv26608482/ // @namespace https://viayoo.com/ // @author Miku39 // @icon https://mjai.ekyu.moe/favicon.ico // @resource js_layui https://cdn.staticfile.org/layui/2.8.17/layui.min.js // @resource css_layui https://cdn.staticfile.org/layui/2.8.17/css/layui.min.css // @resource css_fontAwesome https://cdn.staticfile.org/font-awesome/6.4.2/css/all.min.css // @match *://mjai.ekyu.moe/* // @grant GM_getResourceText // @grant GM_getResourceURL // @grant GM_setClipboard // @run-at document-idle // @license BSD 3-Clause License // ==/UserScript== (()=>{ 'use strict'; // ---------------------------- 全局变量: App变量 ---------------------------- const badMoveUpperLimit = 5; //恶手率 const badMoveUpperLimitCustom = 10; //恶手率 let badChooseNum = 0; let badChooseNumCustom = 0; const lang = document.documentElement.lang; const i18nText = {}; if (lang == "zh-CN") { i18nText.badMove = "恶手"; i18nText.badMoveRatio = "恶手率"; i18nText.matchRatio = "AI 一致率"; i18nText.metaData = "元数据"; } else if (lang == "ja") { i18nText.badMove = "Bad move"; i18nText.badMoveRatio = "bad moves/total"; i18nText.matchRatio = "AI一致率"; i18nText.metaData = "メタデータ"; } else if (lang == "ko") { i18nText.badMove = "Bad move"; i18nText.badMoveRatio = "bad moves/total"; i18nText.matchRatio = "matches/total"; i18nText.metaData = "메타데이터"; } else { i18nText.badMove = "Bad move"; i18nText.badMoveRatio = "bad moves/total"; i18nText.matchRatio = "matches/total"; i18nText.metaData = "Metadata"; } i18nText.modelTag = "model tag"; // i18nText.seatTypeA0 = "东起"; i18nText.seatTypeA1 = "南起"; i18nText.seatTypeA2 = "西起"; i18nText.seatTypeA3 = "北起"; // i18nText.seatTypeB0 = "东家"; i18nText.seatTypeB1 = "南家"; i18nText.seatTypeB2 = "西家"; i18nText.seatTypeB3 = "北家"; // i18nText.seatTypeC0 = "自家"; i18nText.seatTypeC1 = "下家"; i18nText.seatTypeC2 = "对家"; i18nText.seatTypeC3 = "上家"; // i18nText.Ron = "荣和"; i18nText.Tsumo = '自摸'; i18nText.Ryuukyoku = '流局'; i18nText.RyuukyokuTsumo = "流局满贯"; i18nText.RyuukyokuType1 = "九种九牌"; //四风连打、四杠散了、四家立直 //三家和了 // i18nText.badMoveError = "(恶手率统计只支持最新版本Mortal,当前版本生成结果不可靠)" // i18nText.badMoveUp = " (严重鸡打 权重<=5%)"; i18nText.badMoveDown = " (普通错误 权重5~10%)"; i18nText.badMoveNull = " "; i18nText.badMoveSymbol = "%"; i18nText.badMoveDiffer = "差值: "; // i18nText.badMoveDiffer1 = "微差(0~5): "; i18nText.badMoveDiffer2 = "小幅差距(5~10): "; i18nText.badMoveDiffer3 = "低等差距(10~20): "; i18nText.badMoveDiffer4 = "中等差距(20~40): "; i18nText.badMoveDiffer5 = "高等差距(40~60): "; i18nText.badMoveDiffer6 = "大幅度差距(60~80): "; i18nText.badMoveDiffer7 = "压倒性差距(80~100): "; // i18nText.badMoveSum = " (总计)"; const tenhouText = {}; tenhouText.Ron = '和了'; //荣和 tenhouText.Tsumo = '和了'; //自摸 tenhouText.Ryuukyoku = '流局'; //荒牌流局 tenhouText.RyuukyokuTsumo = "流し満貫"; //流局满贯 tenhouText.RyuukyokuType1 = "九種九牌"; //九种九牌 //四风连打、四杠散了、四家立直 //三家和了 const matchRule = {}; matchRule.isInit = false; matchRule.isRon3 = true; //是否允许三家荣和 let strArray2 = []; let strArray3 = []; // ---------------------------- 全局变量: 模板 ---------------------------- const CSSCompatibilityFlag = ".ui"; const CSSCompatibilityFlagNoPoint = CSSCompatibilityFlag.substring(1); const commonCSS = '\ .position_re { position: relative; }\ .position_ab { position: absolute; }\ .position_fi { position: fixed; }\ \ .font_weight_900 { font-weight: 900; } \ .font_weight_700 { font-weight: 700; } \ .font_weight_400 { font-weight: 400; } \ \ .w-auto { width: auto; }\ .w-100 { width: 100%; }\ .w-80 { width: 80%; }\ .w-75 { width: 75%; }\ .w-60 { width: 60%; }\ .w-50 { width: 50%; }\ .w-40 { width: 40%; }\ .w-25 { width: 25%; }\ .w-20 { width: 20%; }\ .w-10 { width: 10%; }\ .w-5 { width: 5%; }\ \ .min-w-auto { min-width: auto; }\ .min-w-100 { min-width: 100%; }\ .min-w-80 { min-width: 80%; }\ .min-w-75 { min-width: 75%; }\ .min-w-60 { min-width: 60%; }\ .min-w-50 { min-width: 50%; }\ .min-w-40 { min-width: 40%; }\ .min-w-25 { min-width: 25%; }\ .min-w-20 { min-width: 20%; }\ .min-w-10 { min-width: 10%; }\ .min-w-5 { min-width: 5%; }\ \ .max-w-auto { max-width: auto; }\ .max-w-100 { max-width: 100%; }\ .max-w-80 { max-width: 80%; }\ .max-w-75 { max-width: 75%; }\ .max-w-60 { max-width: 60%; }\ .max-w-50 { max-width: 50%; }\ .max-w-40 { max-width: 40%; }\ .max-w-25 { max-width: 25%; }\ .max-w-20 { max-width: 20%; }\ .max-w-10 { max-width: 10%; }\ .max-w-5 { max-width: 5%; }\ '; const pageExtendBaseCSS = '\ details.collapseEntryL1 { border: 2px solid #f00; } \ details.collapseEntryL2 { border: 2px solid #6600FF; } \ .badChoose { font-size: 20px; } \ .level1 { color: #f00; font-weight: 900; } \ .level2 { color: #6600FF; font-weight: 700; } \ .color1 { color: #f00; } \ .color2 { color: #6600FF; } \ .color3 { color: #FF0066; } \ .color4 { color: #990000; } \ .l-130px { left: 130px; } \ .l-170px { left: 170px; } \ .color5 { color: #CC0000; } \ .color6 { color: #333; } \ '; const MainAppBaseCSS = '\ .commonDIV { padding: 5px; } \ #settingUI { width: 800px; height: 600px; border: 1px solid red; position: fixed; top: 100px; left: 100px; z-index: 10; } \ #catalogUI { border: 1px solid blue; position: fixed; z-index: 10; } \ '; const origSettingUITemplate = '\ <div class="commonDIV" id="origSettingUI">\ <fieldset id="panel">\ <legend>设置</legend>\ <span style="font-weight:700">布局:</span>\ <label><input checked="" name="layout" onclick="toggleLayout()" type="radio" value="vertical">垂直</label>\ <label><input name="layout" onclick="toggleLayout()" type="radio" value="horizontal">水平</label>\ <br><span style="font-weight:700">展开:</span><label><input name="expand" onclick="toggleExpand()" type="radio" value="all">全部</label>\ <label><input checked="" name="expand" onclick="toggleExpand()" type="radio" value="diff-only">仅差异项</label>\ <label><input name="expand" onclick="toggleExpand()" type="radio" value="none">无</label>\ <br><a class="no-visit" download="" href="">💾保存本页面</a>\ </fieldset>\ </div>\ '; const settingUIBase = '\ <div class="ui commonDIV" id="settingUI">\ </div>\ '; const settingUITemplate = '\ '; const catalogUIBase = '\ <div class="ui commonDIV" id="catalogUI">\ </div>\ '; const catalogUITemplate = '\ <div class="ui layui-btn-container" id="catalogUIBuf">\ <button type="button" class="ui layui-btn" id="kyoku_prev">\ <i class="ui layui-icon layui-icon-prev"></i>\ </button>\ <button type="button" class="ui layui-btn" id="kyoku_next">\ <i class="ui layui-icon layui-icon-next"></i>\ </button>\ <button type="button" class="ui layui-btn layui-btn-disabled" id="diff_prev">\ <i class="ui layui-icon layui-icon-left"></i>\ </button>\ <button type="button" class="ui layui-btn layui-btn-disabled" id="diff_next">\ <i class="ui layui-icon layui-icon-right"></i>\ </button>\ </div>\ <ul class="ui layui-nav layui-nav-tree layui-bg-gray" id="selectorGroups" lay-filter="selector-filter-nav" style="width: 100%; overflow: auto;">\ <!-- 对局选择器 -->\ <li class="ui layui-nav-item layui-nav-itemed">\ <a class="ui" href="javascript:;">对局选择器</a>\ <dl class="ui layui-nav-child" id="selector1">\ {{# layui.each(d.selector1, function(index, item){ }}\ <dd class="ui"><a class="ui" href="{{= item.href }}" name="{{= item.href }}">{{= item.name }}</a></dd>\ {{# }); }}\ </dl>\ </li>\ <!-- 不一致选择器 -->\ <li class="ui layui-nav-item">\ <a class="ui" href="javascript:;">不一致选择器 (等待完善)</a>\ <dl class="ui layui-nav-child" id="selector2">\ {{# layui.each(d.selector2, function(index, item){ }}\ <dd class="ui"><a class="ui" href="{{= item.href }}" name="{{= item.href }}">{{= item.name }}</a></dd>\ {{# }); }}\ </dl>\ </li>\ <!-- 恶手选择器 -->\ <li class="ui layui-nav-item">\ <a class="ui" href="javascript:;">恶手选择器 (等待完善)</a>\ <dl class="ui layui-nav-child" id="selector3">\ {{# layui.each(d.selector3, function(index, item){ }}\ <dd class="ui"><a class="ui" href="{{= item.href }}" name="{{= item.href }}">{{= item.name }}</a></dd>\ {{# }); }}\ </dl>\ </li>\ <li class="ui layui-nav-item"><a class="ui" href="javascript:;">打开设置 (等待完善)</a></li>\ </ul>\ '; // ---------------------------- 其他 ---------------------------- //交叉观察器 var ObserverEleSetList = []; const io = new IntersectionObserver((ioes) => { ioes.forEach(ioe => { const ele = ioe.target const intersectionRatio = ioe.intersectionRatio if (intersectionRatio > 0 && intersectionRatio <= 1) { //0~1范围内的值为显示状态, 等于0的值为隐藏 const section = ele.parentElement; const titleEle = section.children[0]; const titleKyokuEle = titleEle.getElementsByTagName("a"); //只有1个元素 //console.log("可见: " + titleKyokuEle[0].innerText, titleKyokuEle[0].id); let targetEleArray = document.getElementsByName(titleKyokuEle[0].id); setNewActivateEle(targetEleArray); } ele.onload = () => {} ele.onerror = () => {} }); }); function setNewActivateEle(targetEleArray) { if(targetEleArray.length > 0) { //清除旧数据 for (let j = 0; j < ObserverEleSetList.length; j++) { const element = ObserverEleSetList[j]; element.parentElement.classList.remove("layui-this"); } ObserverEleSetList.length = 0; //清空数组 //处理新数据 let tagretChildEle = targetEleArray[0]; tagretChildEle.parentElement.classList.add("layui-this"); ObserverEleSetList.push(tagretChildEle); } } function isInViewPortByObserver(ele) { io.observe(ele); //添加观察对象 } // ---------------------------- 基本框架 ---------------------------- class Utils { // 拓展系统库 static { //保留n位小数 Math.constructor.roundEx = (nValue, n) => { return Math.round(nValue*Math.pow(10,n))/Math.pow(10,n); } } static loadjscssFile(filePath, fileType) { let ele = undefined; if (fileType == "js") { ele = document.createElement('script'); ele.setAttribute("src", filePath); } else if (fileType == "css") { ele = document.createElement("link"); ele.setAttribute("rel", "stylesheet"); ele.setAttribute("href", filePath); }else{ console.log("不支持的文件类型!"); } if (ele != undefined) { document.getElementsByTagName("head")[0].appendChild(ele); } } static addNewStyle(id, newStyle) { var styleElement = document.getElementById(id); if (!styleElement) { styleElement = document.createElement('style'); styleElement.id = id; document.getElementsByTagName('head')[0].appendChild(styleElement); } styleElement.appendChild(document.createTextNode(newStyle)); } static addNewScript(id, newScript) { var scriptElement = document.getElementById(id); if (!scriptElement) { scriptElement = document.createElement('script'); scriptElement.id = id; document.getElementsByTagName('head')[0].appendChild(scriptElement); } scriptElement.appendChild(document.createTextNode(newScript)); } static addElementsByHTMLTemplateText(htmlTemplate, parentElement) { let ele = document.createElement("div"); if(parentElement == undefined) document.body.appendChild(ele); else parentElement.appendChild(ele); ele.outerHTML = htmlTemplate; } } class CustomUtils extends Utils { static handleCSSCompatibility(idPrefix, cssText) { //处理css兼容性, 防止外部css库修改原始css样式 let retCssText = cssText; let splitStrArray = cssText.split(/\{[\s\S]+?\}/g); //提取每一段的css选择器 let startIndex = 0, endIndex = 0; splitStrArray.forEach((item,index)=> { let cssSelectArray = item.match(/[A-Za-z0-9\:\-\_\@\.\#\+\>\<\*\?\;\!\[\]\=\"\'\`\/\\\(\)\{\}\~\^\$\|\%\&]+/g); //提取单个css选择器 //排除了, //console.log("cssSelectArray: " + cssSelectArray); if(cssSelectArray != null) { for (let i = 0; i < cssSelectArray.length; i++) { const cssSelectStr = cssSelectArray[i]; if(cssSelectStr.startsWith('@')) //需要排除的内容 break; if(cssSelectStr == "from" || cssSelectStr == "to") //需要排除的内容 break; if(cssSelectStr.indexOf("%") != -1) //需要排除的内容 break; if(cssSelectStr.indexOf(":") != -1) //需要排除的内容 (伪类元素选择器) break; //console.log("cssSelectArray: " + cssSelectArray); startIndex = retCssText.indexOf(cssSelectStr, startIndex); endIndex = startIndex + cssSelectStr.length; retCssText = retCssText.substring(0, startIndex) + cssSelectStr + idPrefix + retCssText.substring(endIndex); startIndex += idPrefix.length + 1 + cssSelectStr.length; //重新设置startIndex,防止重复查找 } startIndex = retCssText.indexOf("}", startIndex) + 1; //重新设置startIndex,防止从错误的位置开始查找 //console.log("\n" + retCssText); } }); //重定向字体文件 retCssText = retCssText.replaceAll("url(../", "url(https://cdn.staticfile.org/layui/2.8.17/"); //console.log("\n" + retCssText); return retCssText; } static handleJSCompatibility(idPrefix, jsText) { //处理js兼容性, 解决动态添加的节点与css兼容性的问题 jsText = jsText.replaceAll('class="', `class="${CSSCompatibilityFlagNoPoint} `); //全部匹配 //console.log("\n" + jsText); return jsText; } } class Console { static bDebug = true; //调试模式 static origCon = window.console; //保存原始对象 static clear(){ clear(); } static log(...args){ Console.bDebug && Console.origCon.log('%c[log]', 'background: #ffa500; padding: 1px; color: #fff;', ...args); } static warn(...args){ Console.bDebug && Console.origCon.log('%c[warn]', 'background: #ffa500; padding: 1px; color: #fff;', ...args); } static error(...args){ Console.bDebug && Console.origCon.log('%c[error]', 'background: red; padding: 1px; color: #fff;', ...args); } static info(...args){ Console.bDebug && Console.origCon.log('%c[info]', 'background: #ffa500; padding: 1px; color: #fff;', ...args); } static table(...args){ Console.bDebug && Console.origCon.table(...args); } } const URLTYPE = { LINK: 1, //链接 FUZZYMATCH: 1 << 1, //模糊匹配 RegExp: 1 << 2, //正则表达式 } class URL { static test(testURL, urlTYPE, urlRule) { if(urlTYPE == URLTYPE.LINK){ return urlRule.includes(testURL); //子串 }else if(urlTYPE == URLTYPE.FUZZYMATCH){ let targetURL = urlRule; //转义可能的特殊字符 //\和/这种字符必须首先执行 //*和?这种通配符放在后面单独处理 let specharsArray = ['\\', '/', '[', ']', '(', ')', '{', '}', '^', '$', '-', '.', '+', '|', ',', ':', '=', '!', '<', '%']; specharsArray.forEach((item,index)=> { targetURL = targetURL.replaceAll(item, '\\' + item); }); //替换通配符 //?必须比*先执行 targetURL = targetURL.replaceAll("?", "[\\s\\S]?"); targetURL = targetURL.replaceAll("*", "([\\s\\S]+)?"); //测试URL let regExp = new RegExp(targetURL); return regExp.test(testURL); }else if(urlTYPE == URLTYPE.RegExp){ return urlRule.test(testURL); } } } class CallBack { static reportInit() { //加载库 Utils.addNewScript("js_layui", CustomUtils.handleJSCompatibility(CSSCompatibilityFlag, GM_getResourceText("js_layui"))); Utils.addNewStyle("css_layui", CustomUtils.handleCSSCompatibility(CSSCompatibilityFlag, GM_getResourceText("css_layui"))); Utils.loadjscssFile(GM_getResourceURL("css_fontAwesome"), "css"); //加载自定义内容 Utils.addNewStyle("commonCSS", commonCSS); Utils.addNewStyle("pageExtend", pageExtendBaseCSS); Utils.addNewStyle("MainAppBaseCSS", MainAppBaseCSS); //addElementsByHTMLTemplateText(settingUITemplate); Utils.addElementsByHTMLTemplateText(catalogUIBase); } static mainPageInit() { } static reportPageCallBack() { PageExtend.run(); MainApp.run(); } static mainPageCallBack() { document.getElementsByName("show-rating").forEach((ele)=>{ele.checked = true}); //默认勾选 显示Rating const map = new Map(); let childEle = document.getElementById("mortal-model-tag").children; for (let i = 0; i < childEle.length; i++) { const ele = childEle[i]; map.set(ele.value, ele.innerText); //将数据保存到map } const jsonStr = JSON.stringify(Object.fromEntries(map)); localStorage.setItem("Mortal_New", childEle[0].value); //牌谱解析页面,默认使用最新的Mortal localStorage.setItem("Mortal_Type", jsonStr); } } class App { static URLRuleSet = [{ name: "牌谱解析页面", url: /^https?:\/\/mjai.ekyu.moe\/report\/[A-Za-z0-9-_]+.html/, urlType: URLTYPE.RegExp, init: CallBack.reportInit, entry: CallBack.reportPageCallBack, },{ name: "主页", url: /^https?:\/\/mjai.ekyu.moe\/?([A-Za-z0-9-_]+.html)?/, urlType: URLTYPE.RegExp, init: CallBack.mainPageInit, entry: CallBack.mainPageCallBack, }, ]; //URL规则集 constructor(){ this.init(); } init() { return true; } yun(){ for (const [index, value] of App.URLRuleSet.entries()) { if(URL.test(window.location.href, value.urlType, value.url)){ value.init.call(); value.entry.call(); return; } } } } // ---------------------------- 功能定义 ---------------------------- class MortalBase { constructor(){ } static init(){ return true; } static run(){ } static stop(){ } static clean(){ } } const OUTSTYLE = { A: 1, B: 1 << 1, C: 1 << 2, } class PageExtend extends MortalBase { constructor(){ //super(); init(); } static init(){ return true; } static run(){ //显示恶手 PageExtend.showBadChoose(); //修改 元数据 选项卡 PageExtend.alterMetaData(); //起始信息详细化 PageExtend.showStartInfo(); //列出选择权重 PageExtend.showChooseWeight(); } static stop(){ } static clean(){ } //显示恶手 static showBadChoose() { const orderLossEleArray = document.getElementsByClassName("order-loss"); for (let i = 0; i < orderLossEleArray.length; i++) { const orderLoss = orderLossEleArray[i]; const nChooseIndex = parseInt(orderLoss.innerText.match(/[\d]+/)[0]); const nChooseSum = parseInt(orderLoss.nextSibling.textContent.match(/[\d]+/)[0]); const turnInfo = orderLoss.parentElement; const summary = turnInfo.parentElement; const collapseEntry = summary.parentElement; const table = collapseEntry.lastChild.firstChild; const tbody = table.lastChild; const nChooseTR = tbody.childNodes[nChooseIndex -1]; const nChooseWeightTD = nChooseTR.lastChild; const chosenWeight = parseFloat(nChooseWeightTD.innerHTML.replace(/<.*?>/g, "")); //过滤html标签, 只保留文字内容 const kyokuTitleEle = collapseEntry.parentElement.parentElement.firstChild.getElementsByTagName("a")[0]; if (chosenWeight <= parseFloat(badMoveUpperLimit)) { //严重恶手 const badChooseNode = document.createElement("span"); badChooseNode.classList.add("badChoose"); badChooseNode.classList.add("level1"); badChooseNode.innerHTML = ` \u00A0\u00A0\u00A0${i18nText.badMove}${i18nText.badMoveUp}`; turnInfo.appendChild(badChooseNode); collapseEntry.classList.add("collapseEntryL1"); badChooseNum++; //收集数据3-恶手 strArray3.push({ name: kyokuTitleEle.textContent + " " + summary.textContent, href: kyokuTitleEle.href.match(/#[\S\s]+$/)[0] }); }else if (chosenWeight <= parseFloat(badMoveUpperLimitCustom)) { //普通恶手 const badChooseNode = document.createElement("span"); badChooseNode.classList.add("badChoose"); badChooseNode.classList.add("level2"); badChooseNode.innerHTML = ` \u00A0\u00A0\u00A0${i18nText.badMove}${i18nText.badMoveDown}`; turnInfo.appendChild(badChooseNode); collapseEntry.classList.add("collapseEntryL2"); badChooseNumCustom++; //收集数据3-恶手 strArray3.push({ name: kyokuTitleEle.textContent + " " + summary.textContent, href: kyokuTitleEle.href.match(/#[\S\s]+$/)[0] }); } //收集数据2-不一致 strArray2.push({ name: kyokuTitleEle.textContent + " " + summary.textContent, href: kyokuTitleEle.href.match(/#[\S\s]+$/)[0] }); } //for } //修改 元数据 选项卡 static alterMetaData() { // 新增 显示 Mortal 版本 const jsonStr = localStorage.getItem("Mortal_Type"); const mortal_New = localStorage.getItem("Mortal_New"); var mortalMap = null; if(jsonStr != null) { let obj = Object.entries(JSON.parse(jsonStr)); mortalMap = new Map(obj); } // 修改 元数据 选项卡 let metaData = null; const detailsElements = document.getElementsByTagName("details"); for (let i = 0; i < detailsElements.length; i++) { const details = detailsElements[i]; const summary = details.firstChild; if (summary.firstChild.textContent == i18nText.metaData) { metaData = details; metaData.toggleAttribute("open", true); //打开 元数据 选项卡 break; } } const metaDataDL = metaData.lastChild; let matchRatioDD = null; let version = null; for (let i = 0; i < metaDataDL.childNodes.length; i++) { const metaDataChild = metaDataDL.childNodes[i]; if(metaDataChild.nodeName == "DT" && metaDataChild.textContent == i18nText.modelTag) { let ele = metaDataDL.childNodes[i + 1]; //判断当前是否是最新版本的mortal if(mortal_New != null) { if(mortal_New != ele.innerText) { let aiEle = metaDataDL.childNodes[i - 1]; aiEle.classList.add("color1"); aiEle.innerText = aiEle.innerText + ` \u00A0\u00A0\u00A0${i18nText.badMoveError}`; } } //处理当前版本 if(mortalMap != null) { let mortalValue = mortalMap.get(ele.innerText); if(mortalValue != undefined) { ele.innerText = mortalValue; } } } if (metaDataChild.nodeName == "DT" && metaDataChild.textContent == i18nText.matchRatio) { matchRatioDD = metaDataDL.childNodes[i + 1]; version = metaDataDL.childNodes[i + 2]; // metaDataDL.childNodes[i-2].classList.add("color2"); //rating metaDataDL.childNodes[i-1].classList.add("color2"); metaDataDL.childNodes[i].classList.add("color2"); //AI 一致率 metaDataDL.childNodes[i+1].classList.add("color2"); break; } } const matchRatioText = matchRatioDD.textContent; const chooseNumStr = matchRatioText.substring(matchRatioText.indexOf("/") + 1); const chooseNum = parseInt(chooseNumStr); const badChooseRatioDT = document.createElement("dt"); badChooseRatioDT.classList.add("color3"); badChooseRatioDT.innerHTML = i18nText.badMoveRatio + i18nText.badMoveNull + badMoveUpperLimit + i18nText.badMoveSymbol; const badChooseRatioDD = document.createElement("dd"); badChooseRatioDD.classList.add("color3"); badChooseRatioDD.innerHTML = `${badChooseNum}/${chooseNum} = ${(100 * badChooseNum / chooseNum).toFixed(3)}%`; metaDataDL.insertBefore(badChooseRatioDD, version); metaDataDL.insertBefore(badChooseRatioDT, badChooseRatioDD); /* 新增 计算总恶手数 */ badChooseNumCustom += badChooseNum; //计算总恶手数 const badChooseRatioDT2 = document.createElement("dt"); badChooseRatioDT2.classList.add("color3"); badChooseRatioDT2.innerText = i18nText.badMoveRatio + i18nText.badMoveNull + badMoveUpperLimitCustom + i18nText.badMoveSymbol; const badChooseRatioDD2 = document.createElement("dd"); badChooseRatioDD2.classList.add("color3"); badChooseRatioDD2.innerHTML = `${badChooseNumCustom}/${chooseNum} = ${(100 * badChooseNumCustom / chooseNum).toFixed(3)}%`; metaDataDL.insertBefore(badChooseRatioDD2, version); metaDataDL.insertBefore(badChooseRatioDT2, badChooseRatioDD2); } //起始信息详细化 static showStartInfo() { /* 起始信息详细化 */ function parmeHandle(eastScoreChange, southScoreChange, westScoreChange, northScoreChange) { let scoreArray = [{sc: eastScoreChange, i: 0}, {sc: southScoreChange, i: 1}, {sc: westScoreChange, i: 2}, {sc: northScoreChange, i: 3}]; let newScoreArray = scoreArray.filter((obj) => { return obj.sc != 0; }); let scoreAddArray = newScoreArray.filter((obj) => { //荣和的玩家 return obj.sc > 0; }); let scoreSubArray = newScoreArray.filter((obj) => { //放铳的玩家 return obj.sc < 0; }); scoreAddArray.sort((a,b)=>{return b.sc-a.sc}); return {scoreArray: scoreArray, newScoreArray: newScoreArray, scoreAddArray: scoreAddArray, scoreSubArray: scoreSubArray}; } function handleRon(kyoku, startPlayerIndex, eastScoreChange, southScoreChange, westScoreChange, northScoreChange) { //处理荣和 let obj = parmeHandle(eastScoreChange, southScoreChange, westScoreChange, northScoreChange); let scoreAddArray = obj.scoreAddArray; let scoreSubArray = obj.scoreSubArray; let selfPlayerIndex = getPlayerIndexByPlayerSeatName(getPlayerSeatNameByPlayerIndex(startPlayerIndex, kyoku, OUTSTYLE.B), OUTSTYLE.B); // let str = ""; for (let i = 0; i < scoreAddArray.length; i++) { const scoreAdd = scoreAddArray[i]; let scAddPlayerSeatName = getPlayerSeatNameByPlayerIndex(scoreAdd.i, kyoku, OUTSTYLE.B); //荣和的玩家 let scAddPlayerViewName = getSelfViewPlayerNameByTargetPlayerIndex(selfPlayerIndex, getPlayerIndexByPlayerSeatName(scAddPlayerSeatName, OUTSTYLE.B)); let scSubPlayerSeatName = getPlayerSeatNameByPlayerIndex(scoreSubArray[0].i, kyoku, OUTSTYLE.B); //放铳的玩家 let scSubPlayerViewName = getSelfViewPlayerNameByTargetPlayerIndex(selfPlayerIndex, getPlayerIndexByPlayerSeatName(scSubPlayerSeatName, OUTSTYLE.B)); str += scAddPlayerSeatName + ` (${scAddPlayerViewName}) ` + `<span class="color4">${i18nText.Ron}</span>` + i18nText.badMoveNull + scSubPlayerSeatName + ` (${scSubPlayerViewName}) ` + "+" + scoreAdd.sc + i18nText.badMoveNull + scoreSubArray[0].sc; } return str; } function handleTsumo(kyoku, startPlayerIndex, eastScoreChange, southScoreChange, westScoreChange, northScoreChange) { //处理自摸 } function handleRyuukyoku(kyoku, startPlayerIndex, eastScoreChange, southScoreChange, westScoreChange, northScoreChange) { //处理流局 } function getTextByOutStyle(outStyle, index) { if(outStyle == OUTSTYLE.A) return eval("i18nText.seatTypeA" + index); //seatTypeA0 //东起 else if(outStyle == OUTSTYLE.B) return eval("i18nText.seatTypeB" + index); //seatTypeB0 //东家 else if(outStyle == OUTSTYLE.C) return eval("i18nText.seatTypeC" + index); //seatTypeC0 //自家 else{ console.warn("outStyle是无效的!"); } } function getSelfViewPlayerNameByTargetPlayerIndex(selfIndex, targetPlayerIndex) { const viewMap = new Map(); let viewArray = [ { value: -3, name: i18nText.seatTypeC1 }, //下家 { value: -2, name: i18nText.seatTypeC2 }, //对家 { value: -1, name: i18nText.seatTypeC3 }, //上家 { value: 0, name: i18nText.seatTypeC0 }, //自家 { value: 1, name: i18nText.seatTypeC1 }, //下家 { value: 2, name: i18nText.seatTypeC2 }, //对家 { value: 3, name: i18nText.seatTypeC3 }, //上家 ]; viewArray.forEach((item,index)=> { viewMap.set(item.value, item.name); }); const getValue = (offset) => { if(offset > 0) return offset -4; else return offset +4; } let offset = targetPlayerIndex - selfIndex; let result; do { result = viewMap.get(offset); } while (offset = getValue(offset), result == undefined); return result; } function getPlayerIndexByPlayerSeatName(playerSeatName, outStyle) { var seatArray; if(outStyle == OUTSTYLE.A) seatArray = [i18nText.seatTypeA0, i18nText.seatTypeA1, i18nText.seatTypeA2, i18nText.seatTypeA3]; //东起, 南起, 西起, 北起 else if(outStyle == OUTSTYLE.B) seatArray = [i18nText.seatTypeB0, i18nText.seatTypeB1, i18nText.seatTypeB2, i18nText.seatTypeB3]; //东家, 南家, 西家, 北家 else{ console.warn("outStyle是无效的!"); seatArray = [i18nText.seatTypeA0, i18nText.seatTypeA1, i18nText.seatTypeA2, i18nText.seatTypeA3]; //东起, 南起, 西起, 北起 } const seatMap = new Map(); seatArray.forEach((item,index)=> { seatMap.set(item, index); }); return seatMap.get(playerSeatName); } function getPlayerSeatNameByPlayerIndex(playerIndex, kyoku, outStyle) { var seatArray; if(outStyle == OUTSTYLE.A) seatArray = [i18nText.seatTypeA0, i18nText.seatTypeA3, i18nText.seatTypeA2, i18nText.seatTypeA1]; //东起, 北起, 西起, 南起 else if(outStyle == OUTSTYLE.B) seatArray = [i18nText.seatTypeB0, i18nText.seatTypeB3, i18nText.seatTypeB2, i18nText.seatTypeB1]; //东家, 北家, 西家, 南家 else{ console.warn("outStyle是无效的!"); seatArray = [i18nText.seatTypeA0, i18nText.seatTypeA3, i18nText.seatTypeA2, i18nText.seatTypeA1]; //东起, 北起, 西起, 南起 } const seatMap = new Map(); seatArray.forEach((item,index)=> { seatMap.set(item, index); }); const getValueByEachArray = (array, startIndex, eachCount) => { let length = array.length; let targetIndex = startIndex; for (let i = eachCount; i > 0; i--) { if(++targetIndex >= length) targetIndex = 0; } return array[targetIndex]; } const getStart = (playerIndex, kyoku, outStyle) => { switch (playerIndex + kyoku) { case 0: return getTextByOutStyle(outStyle, 0); //东起 case 1: return getTextByOutStyle(outStyle, 1); //南起 case 2: return getTextByOutStyle(outStyle, 2); //西起 case 3: return getTextByOutStyle(outStyle, 3); //北起 default: return getStart(playerIndex, kyoku -4, outStyle); } } const get = (playerIndex, kyoku, outStyle) => { let startIndex = seatMap.get(getStart(playerIndex, 0, outStyle)); return getValueByEachArray(seatArray, startIndex, kyoku); } if(kyoku == 0) return getStart(playerIndex, kyoku, outStyle); else return get(playerIndex, kyoku, outStyle); } function getTextLineNum(ele) { let styles = getComputedStyle(ele, null); let lineHeight = parseFloat(styles.lineHeight); let height = parseFloat(styles.height); let offsetHeight = parseFloat(ele.offsetHeight); let lineNum = offsetHeight / lineHeight; return Math.round(lineNum); } const summaryEle = document.getElementsByClassName("kyoku-toc")[0]; summaryEle.classList.add("position_re"); for (let j = 0; j < summaryEle.children.length; j++) { const summary = summaryEle.children[j]; summary.classList.add("min-w-20"); } const kyokuEle = summaryEle.getElementsByTagName("a"); const endInfoEle = summaryEle.getElementsByClassName("end-status"); // const section = document.getElementsByTagName("section"); for (let i = 0, length = section.length; i != length; ++i) { const titleEle = section[i].children[0]; const titleKyokuEle = titleEle.getElementsByTagName("a"); //只有1个元素 const titleEndInfoEle = titleEle.getElementsByClassName("end-status"); //只有1个元素 const tenhouData = section[i].getElementsByTagName("iframe")[0].src; const playerIndexStr = tenhouData.match(/tw=[0-3]/)[0]; const startPlayerIndex = parseInt(playerIndexStr.substring(playerIndexStr.length -1)); //起始玩家索引 const json = JSON.parse(decodeURI(tenhouData.substring(tenhouData.indexOf("{")))); //天凤对局数据 const kyoku = json.log[0][0][0]; //局数 const count = json.log[0][0][1]; //本场数 const currScore = json.log[0][1]; //当前点数 const scoreChange = json.log[0][json.log[0].length -1]; //点数变动 const endMode = scoreChange[0]; //解析规则 if(matchRule.isInit == false) { const disp = json.rule.disp; if(disp.indexOf("間") != -1) { //雀魂 matchRule.isRon3 = true; //console.log("雀魂牌谱"); }else if(disp.indexOf("Player") != -1) { //一番街 matchRule.isRon3 = false; //console.log("一番街牌谱"); }else{ //默认为天凤 matchRule.isRon3 = false; //console.log("默认为天凤牌谱(包括自定义牌谱)"); } matchRule.isInit = true; } //四家当前分数 const eastScore = currScore[0]; //东 const southScore = currScore[1]; //南 const westScore = currScore[2]; //西 const northScore = currScore[3]; //北 //四家分数变化(直接) //送棒的-1000没有显示 let eastScoreChange = []; let southScoreChange = []; let westScoreChange = []; let northScoreChange = []; let ronCount = (scoreChange.length -1) / 2; if(scoreChange.length > 1) { //比如九种九牌, 是没有分数变化的数据的 //是否有多家荣和 for (let j = 0; j < ronCount; j++) { //处理可能的多家荣和 eastScoreChange.push(scoreChange[1+ j*2][0]); //东 southScoreChange.push(scoreChange[1+ j*2][1]); //南 westScoreChange.push(scoreChange[1+ j*2][2]); //西 northScoreChange.push(scoreChange[1+ j*2][3]); //北 } } //判断模式 if(endMode == tenhouText.Ron) { //自摸、荣和 let str = ""; for (let j = 0; j < ronCount; j++) { //处理可能的多家荣和 if(j>0) //处理多家 str += ", "; let obj = parmeHandle(eastScoreChange[j], southScoreChange[j], westScoreChange[j], northScoreChange[j]); if(eastScoreChange[j] == 0 || southScoreChange[j] == 0 || westScoreChange[j] == 0 || northScoreChange[j] == 0) { //如果有任何一家分数变动为0, 则为荣和 str += handleRon(kyoku, startPlayerIndex, eastScoreChange[j], southScoreChange[j], westScoreChange[j], northScoreChange[j]); }if(obj.scoreAddArray.length == 3) { //判断是否是三家荣和 if(matchRule.isRon3) //如果启用了三家和了的规则 //? 可能是没有必要的判断? 等待使用三种游戏牌谱分别进行查证 str += handleRon(kyoku, startPlayerIndex, eastScoreChange[j], southScoreChange[j], westScoreChange[j], northScoreChange[j]); else{ //流局 //? 可能是没有必要的判断? 等待使用三种游戏牌谱分别进行查证 // let str = handleRyuukyoku(kyoku, startPlayerIndex, eastScoreChange[j], southScoreChange[j], westScoreChange[j], northScoreChange[j]); // console.log(str); } }else{ //否则都是自摸 // str += handleTsumo(kyoku, startPlayerIndex, eastScoreChange[j], southScoreChange[j], westScoreChange[j], northScoreChange[j]); } }//for if(str.length > 0) { const span = document.createElement("span"); span.innerHTML = ` \u00A0\u00A0\u00A0` + str; endInfoEle[i].parentElement.appendChild(span); let lineNum = getTextLineNum(span) if(lineNum > 1){ //如果新添加的文字有多行, 则进行对齐 for (let j = 1; j < lineNum; j++) { summaryEle.children[0].insertBefore(document.createElement("br"), kyokuEle[i].parentElement.nextElementSibling); } } } }else if(endMode == tenhouText.Ryuukyoku){ //荒牌流局 //流局, 如果有分数改变则处理 // let str = handleRyuukyoku(kyoku, startPlayerIndex, eastScoreChange[j], southScoreChange[j], westScoreChange[j], northScoreChange[j]); // console.log(str); }else if(endMode == tenhouText.RyuukyokuTsumo) { //流局满贯 (等同于自摸8000) // let str = handleRyuukyoku(kyoku, startPlayerIndex, eastScoreChange[j], southScoreChange[j], westScoreChange[j], northScoreChange[j]); // console.log(str); }else if(endMode == tenhouText.RyuukyokuType1) { //九种九牌 //流局, 如果有分数改变则处理 // let str = handleRyuukyoku(kyoku, startPlayerIndex, eastScoreChange[j], southScoreChange[j], westScoreChange[j], northScoreChange[j]); // console.log(str); }else{ //四风连打、四杠散了、四家立直 //三家和了 //流局, 如果有分数改变则处理 // let str = handleRyuukyoku(kyoku, startPlayerIndex, eastScoreChange[j], southScoreChange[j], westScoreChange[j], northScoreChange[j]); // console.log(str); } const span = document.createElement("span"); let str = getPlayerSeatNameByPlayerIndex(startPlayerIndex, kyoku, OUTSTYLE.A); span.innerText = ` \u00A0\u00A0\u00A0` + str; span.classList.add("position_ab"); span.classList.add("l-130px"); if(str == i18nText.seatTypeA0) //东起 span.classList.add("color5"); else span.classList.add("color6"); kyokuEle[i].parentElement.appendChild(span); titleKyokuEle[0].innerText += `\u00A0\u00A0` + str; // 将页面滚动导致的元素可见性改变与选择器绑定 //分别获取父元素的第一个子元素和最后一个子元素 //第一个子元素作为向下滚动时的监听对象, 最后一个子元素作为向上滚动时的监听对象 //这样无需去监听滚动事件,提高性能 titleKyokuEle[0].id = titleKyokuEle[0].href.match(/#[\S\s]+$/)[0]; //第一个子元素 isInViewPortByObserver(titleEle); //最后一个子元素 let lastEle = section[i].children[section[i].children.length -1]; isInViewPortByObserver(lastEle); }//for } //列出选择权重 static showChooseWeight() { /* 列出选择权重 */ const map = new Map(); //使用map保证重置循坏后的唯一性 const boxObjStr = '{"left":0,"top":0}'; const entry = document.getElementsByClassName("collapse entry"); for (let i = 0, length = entry.length; i != length; ++i) { entry[i].classList.add("position_re"); const roleEle = entry[i].getElementsByClassName("role"); let selfPai = roleEle[0].parentElement; let mortalPai = roleEle[1].nextElementSibling; if(mortalPai.tagName.toLocaleLowerCase() == 'details') { mortalPai = roleEle[1].nextSibling; } if (Object.prototype.toString.call(selfPai.childNodes[selfPai.childNodes.length -2]) == '[object SVGSVGElement]') { if(selfPai.childNodes[selfPai.childNodes.length -2].tagName.toLocaleLowerCase() == 'svg') { //如果有多张牌图片,就使用最后一张牌图片 selfPai = selfPai.childNodes[selfPai.childNodes.length -2]; } } if(mortalPai.nextElementSibling.tagName.toLocaleLowerCase() == 'svg') { //如果有多张牌图片,就使用最后一张牌图片 mortalPai = mortalPai.nextElementSibling; } const dataEle = entry[i].getElementsByTagName("tbody")[0].childNodes; var selfPaiData = 0; var mortalPaiData = 0; var selfBoxObj = JSON.parse(boxObjStr), mortalBoxObj = JSON.parse(boxObjStr); map.clear(); //清除map let j = 0, size = dataEle.length; while (j != size) { let selfPaiStr = null; let mortalPaiStr = null; let isResetLoop = false; //是否重置循坏 if(selfPai != null){ if(Object.prototype.toString.call(selfPai) == '[object Text]') { selfPaiStr = selfPai.data; }else{ let obj = selfPai.getElementsByClassName("face"); if(obj[0] != null){ selfPaiStr = obj[0].href.baseVal; }else{ //选择跳过的情况 selfPaiStr = selfPai.childNodes[selfPai.childNodes.length -1].data; } } } if(mortalPai != null){ if(Object.prototype.toString.call(mortalPai) == '[object Text]') { mortalPaiStr = mortalPai.data; }else{ let obj = mortalPai.getElementsByClassName("face"); if(obj[0] != null){ mortalPaiStr = obj[0].href.baseVal; }else{ //选择跳过的情况 mortalPaiStr = mortalPai.childNodes[mortalPai.childNodes.length -1].data; } } } let data = dataEle[j].childNodes[2].innerHTML.replace(/<.*?>/g, ""); //过滤html标签, 只保留文字内容 let obj1 = dataEle[j].childNodes[0].getElementsByClassName("face"); let dataPaiStr; if(obj1[obj1.length - 1] != null) { // 如果有多张牌, 则选择最后一张牌作为对比牌 (主要用于吃的情况、碰杠这些牌都是一样的) dataPaiStr = obj1[obj1.length - 1].href.baseVal; }else{ dataPaiStr = dataEle[j].childNodes[0].innerHTML; if(map.has(j) == false) { map.set(j, true); //保存当前j的值,防止重复开始循坏 j = 0; //如果 有 选择跳过的情况, 则重新开始循坏, 以找到正确的数据 isResetLoop = true; } } if(selfPaiStr == dataPaiStr) { //如果目标操作是自己的操作 selfPaiData = data; const span = document.createElement("span"); span.innerText = ` \u00A0\u00A0\u00A0` + data; span.classList.add("position_ab"); if(selfBoxObj.top == 0) { if(!isNaN(selfPai.offsetTop)) { selfBoxObj.top = (selfPai.offsetTop + selfPai.offsetHeight / 2 - 10); }else if(!isNaN(selfPai.parentElement.offsetTop)) { selfBoxObj.top = (selfPai.parentElement.offsetTop + selfPai.parentElement.offsetHeight / 2 - 10); }else{ console.error("[dom struct inconsistency] source:", "selfPai"); console.info("[debug]", `i: ${i}`); } span.style.top = selfBoxObj.top + 2 + "px"; } span.classList.add("l-170px"); entry[i].insertBefore(span, entry[i].childNodes[3].nextSibling); selfPai = null; //置null, 防止继续计算 }else if(mortalPaiStr == dataPaiStr) { //如果目标操作是Mortal的操作 mortalPaiData = data; const span = document.createElement("span"); span.innerText = ` \u00A0\u00A0\u00A0` + data; span.classList.add("position_ab"); if(mortalBoxObj.top == 0) { if(!isNaN(mortalPai.offsetTop)) { mortalBoxObj.top = (mortalPai.offsetTop + mortalPai.offsetHeight / 2 - 10); }else if(!isNaN(mortalPai.previousElementSibling.offsetTop)) { mortalBoxObj.top = (mortalPai.previousElementSibling.offsetTop + mortalPai.previousElementSibling.offsetHeight / 2 - 10); }else if(!isNaN(mortalPai.previousElementSibling.previousElementSibling.offsetTop)) { mortalBoxObj.top = (mortalPai.previousElementSibling.previousElementSibling.offsetTop + mortalPai.previousElementSibling.previousElementSibling.offsetHeight / 2 - 10); }else{ console.error("[dom struct inconsistency] source:", "mortalPai"); console.info("[debug]", `i: ${i}`); } span.style.top = mortalBoxObj.top + 1 + "px"; } span.classList.add("l-170px"); if(Object.prototype.toString.call(mortalPai.nextSibling) == '[object Text]') { //如果有多张牌图片,就使用最后一张牌图片后面的文字的位置 mortalPai = mortalPai.nextSibling; } entry[i].insertBefore(span, mortalPai.nextSibling); mortalPai = null; //置null, 防止继续计算 } if(selfPaiStr == mortalPaiStr) { //如果自己选择打出的牌与mortal选择打出的牌相同 if(map.has(j) == false) { map.set(j, true); //保存当前j的值,防止重复开始循坏 j = 0; //如果 有 选择跳过的情况, 则重新开始循坏, 以找到正确的数据 isResetLoop = true; } } if(selfPai == null && mortalPai == null) { //是否处理完毕 break; //跳出循坏 } if(isResetLoop == false){ //不重置循坏时, index++ ++j; } }//for /* 计算自己的选择与mortal选择的差值 */ const defaultHandleFunc = (newNode, index, colorStr) => { newNode.style.color = colorStr; //设置为目标颜色 newNode.innerHTML = ` \u00A0\u00A0\u00A0` + eval("i18nText.badMoveDiffer" + index) + differData; } const differData = Math.constructor.roundEx(Math.abs(mortalPaiData - selfPaiData), 5); //保留5位小数 if (differData != 0) { //忽略自己和mortal打出的牌一样的结果 const turnInfo = entry[i].children[0]; const newNode = document.createElement("span"); newNode.classList.add("font_weight_400"); if (differData < 5) { //微差 defaultHandleFunc(newNode, 1, "#000"); //黑色 }else if (differData < 10) { //小幅差距 defaultHandleFunc(newNode, 2, "#996633"); //褐色 }else if (differData < 20) { //低等差距 defaultHandleFunc(newNode, 3, "#009966"); //淡绿 }else if (differData < 40) { //中等差距 defaultHandleFunc(newNode, 4, "#3399FF"); //淡蓝 }else if (differData < 60) { //高等差距 defaultHandleFunc(newNode, 5, "#3333CC"); //深蓝 }else if (differData < 80) { //大幅度差距 defaultHandleFunc(newNode, 6, "#CC0099"); //淡红 }else{ //压倒性差距 defaultHandleFunc(newNode, 7, "#f00"); //红色 } turnInfo.appendChild(newNode); } }//for } } class MainApp extends MortalBase { constructor(){ //super(); init(); } static init(){ return true; } static run(){ MainApp.createCatalogUI(); } static stop(){ } static clean(){ } // static createCatalogUI() { const summaryEle = document.getElementsByClassName("kyoku-toc")[0]; //数据处理 let catalogUI = document.getElementById("catalogUI"); layui.use(function(){ var element = layui.element; var laytpl = layui.laytpl; var $ = layui.$; //收集数据1-对局 let strArray1 = []; let array = summaryEle.children[0].children; let length = summaryEle.children[0].children.length; for (let j = 0; j < length; j++) { const ele = array[j]; strArray1.push({ name: ele.children[0].innerText + " " + ele.children[1].innerText.trim(), href: ele.children[0].href.match(/#[\S\s]+$/)[0] }); } let data = { //模板数据 selector1: strArray1, //对局选择器 selector2: strArray2, //不一致选择器 selector3: strArray3, //恶手选择器 }; //使用模板进行解析 var compile = laytpl(catalogUITemplate); // 模板解析 compile.render(data, (htmlStr)=>{ $('#catalogUI').html(htmlStr); }); // 模板渲染 // 渲染导航组件 element.render('nav', 'selector-filter-nav'); /* 新增右置对局选择器和切换器(固定/可滑动呼出) */ let catalogUIBuf = document.getElementById("catalogUIBuf"); let selectorGroups = document.getElementById("selectorGroups"); let eleSection = document.getElementsByTagName("section")[0]; selectorGroups.style.height = (document.documentElement.clientHeight - 100 - catalogUIBuf.offsetHeight) + "px"; //滚动条 catalogUI.style.left = (eleSection.offsetLeft + eleSection.offsetWidth + 60) + "px"; //x位置 let vTop = (eleSection.offsetTop - catalogUI.offsetHeight); catalogUI.style.top = 60 + "px"; //y位置 document.getElementById("kyoku_prev").addEventListener("click", function(e){ let nextEle = document.getElementsByClassName("ui layui-this")[0].previousElementSibling; if(nextEle != null){ nextEle = nextEle.children[0]; setNewActivateEle([nextEle]); nextEle.click(); } }, false); document.getElementById("kyoku_next").addEventListener("click", function(e){ let nextEle = document.getElementsByClassName("ui layui-this")[0].nextElementSibling; if(nextEle != null){ nextEle = nextEle.children[0]; setNewActivateEle([nextEle]); nextEle.click(); } }, false); document.getElementById("diff_prev").addEventListener("click", function(e){ }, false); document.getElementById("diff_next").addEventListener("click", function(e){ }, false); }); } // static createSettingUI() { } } const app = new App(); app.yun(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址