Re: 將製作ejcees(中國象棋打譜程式)
改進:
如果this.container的textContent不為空的話,則將它的值在實例化時用importExportedText()方法導入。
只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
如果this.container的textContent不為空的話,則將它的值在實例化時用importExportedText()方法導入。
只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
- 附件
-
ejceesobj202604271544.js- (277.64 KiB) 已下载 45 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
gemini pro 挺好用:
代码: 全选
Here are the necessary modifications to the `constructor` of the `Ejcees` class.
You need to capture the `textContent` of the container **before** it gets overwritten by `this.renderDOM()`, and then call `this.importExportedText()` after the initial game setup is complete.
```javascript
class Ejcees {
constructor(container, mode) {
this.container = container;
this.mode = mode;
// Capture the initial text content before renderDOM() overwrites the container's innerHTML
const initialTextContent = this.container.textContent ? this.container.textContent.trim() : '';
this.INITIAL_FEN = 'rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1';
/* ... [Keep all other existing property initializations intact] ... */
// --- Boot the App ---
this.injectCSS();
this.renderDOM();
if (this.mode === 'ejceesmini') {
this.cacheDOM().then(() => {
this.bindEvents();
this.initGame();
// Import the initial text content if it exists
if (initialTextContent) {
this.importExportedText(initialTextContent);
}
});
} else {
this.cacheDOM();
this.bindEvents();
this.initGame();
// Import the initial text content if it exists
if (initialTextContent) {
this.importExportedText(initialTextContent);
}
}
}
/* ... [Keep the rest of the class methods intact] ... */
}
```https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
改進:
在bindEvents() {if (this.mode === 'ejceesmini') {}},加入以下功能:
1.當ejceesstepminus、ejceesstepdrop、ejceesstepplus點擊時,object中的棋子位置將發生改變,ejceesoutput的數字也會發生改變。
2.實現btn-autoplay功能,即點擊時它將自動播放,再點擊則停止。
3.實現分支選擇和切換功能(已有相關代碼)。
4.實現顯示評論功能(已有相關代碼)。
5.注意在ejceesmini模式時,ejceessvg的元素已經是在一個object中,要用其content來讀到棋子元素。
只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
在bindEvents() {if (this.mode === 'ejceesmini') {}},加入以下功能:
1.當ejceesstepminus、ejceesstepdrop、ejceesstepplus點擊時,object中的棋子位置將發生改變,ejceesoutput的數字也會發生改變。
2.實現btn-autoplay功能,即點擊時它將自動播放,再點擊則停止。
3.實現分支選擇和切換功能(已有相關代碼)。
4.實現顯示評論功能(已有相關代碼)。
5.注意在ejceesmini模式時,ejceessvg的元素已經是在一個object中,要用其content來讀到棋子元素。
只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
gemini pro到4:52又能用了:
代码: 全选
Here are the necessary modifications to the `bindEvents()` method. You only need to replace the `if (this.mode === 'ejceesmini') { ... }` block at the beginning of the function.
This implements the step controls, autoplay toggle, invokes existing branch/comment logic, and safely monkey-patches `applyLastMoveVisuals` for `ejceesmini` mode so that it queries pieces within the `<object>`'s `contentDocument` (referenced by `this.svgElement`).
```javascript
bindEvents() {
if (this.mode === 'ejceesmini') {
// 2. Implement btn-autoplay functionality (Toggle Auto Play)
const autoBtn = this.container.querySelector('#btn-autoplay');
if (autoBtn) {
autoBtn.addEventListener('click', () => {
if (this.isAutoPlaying) {
this.stopAutoPlay();
} else {
this.startAutoPlay();
}
});
}
// 5. In ejceesmini mode, SVG elements are inside an <object>.
// We must override applyLastMoveVisuals so it queries piece elements
// and the start dot using this.svgElement (the object's contentDocument).
this.applyLastMoveVisuals = (lastMove) => {
const pieces = this.etboard.querySelectorAll('use');
pieces.forEach(el => {
if (el.getAttribute('currentmove') === '1') {
el.removeAttribute('currentmove');
if (!el.getAttribute('pickup')) {
el.setAttribute('stroke', 'none');
el.removeAttribute('stroke-width');
}
}
});
// Use this.svgElement to query inside the <object> content
const dot = this.svgElement.querySelector('#ejceesstartdot');
if (!lastMove) {
if (dot) {
dot.setAttribute('cx', this.initialDotCx);
dot.setAttribute('cy', this.initialDotCy);
}
return;
}
const pieceId = this.tileMap.get(`${lastMove.endX},${lastMove.endY}`);
if (pieceId) {
const pieceEl = this.svgElement.querySelector('#' + pieceId); // Accessing piece from SVG content
if (pieceEl) {
pieceEl.setAttribute('currentmove', '1');
if (!pieceEl.getAttribute('pickup')) {
pieceEl.setAttribute('stroke', 'lightgreen');
pieceEl.setAttribute('stroke-width', '2');
}
}
}
if (dot) {
const visStart = this.getVisualCoords(lastMove.startX, lastMove.startY);
dot.setAttribute('cx', visStart.x * 48 + 24);
dot.setAttribute('cy', visStart.y * 48 + 24);
}
};
// 1, 3, 4. Step controls (minus, drop/slider, plus) to change piece positions,
// update ejceesoutput, update branch menus (3) and show comments (4).
// jumpToStep natively triggers renderRecordUI and renderNoteUI to handle branches and comments.
this.stepSlider.addEventListener('input', (e) => {
if (this.isAutoPlaying) {
e.preventDefault();
e.target.value = this.currentStepIndex;
return;
}
this.jumpToStep(parseInt(e.target.value, 10));
this.renderRecordUI();
});
const btnMinus = this.container.querySelector('.ejceesstepminus');
if (btnMinus) {
btnMinus.addEventListener('click', () => {
if (this.isAutoPlaying) return;
this.jumpToStep(this.currentStepIndex - 1);
this.renderRecordUI();
});
}
const btnPlus = this.container.querySelector('.ejceesstepplus');
if (btnPlus) {
btnPlus.addEventListener('click', () => {
if (this.isAutoPlaying) return;
this.jumpToStep(this.currentStepIndex + 1);
this.renderRecordUI();
});
}
return;
}
// Click listener for entering edit mode
// ... [Keep the rest of the existing bindEvents method unchanged below this point] ...
```https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
改進:
在this.mode === 'ejceesmini'時:
為ejceesoutput加上一個表示「設置」的svg背景,寫到css中。當點擊時,將在右上角出現三個滑動條設置,分別為「背景透明度(0~1,默認0.7)、字體顏色透明度(0~1,默認1)、字體大小(12px~24px,默認14px)」。
左上角的「分支」換成一個svg圖標,其長寬是字體大小的兩倍,背景色、stroke顏色透明度跟前面設置的一致。重寫「showMiniBranch」方法,不必有list序號及delete-icon刪除,只需要有move-link內容。當點擊切換後,菜單將消失。其背景透明度、字體顏色透明度、字體大小跟前面設置的一致。
只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
在this.mode === 'ejceesmini'時:
為ejceesoutput加上一個表示「設置」的svg背景,寫到css中。當點擊時,將在右上角出現三個滑動條設置,分別為「背景透明度(0~1,默認0.7)、字體顏色透明度(0~1,默認1)、字體大小(12px~24px,默認14px)」。
左上角的「分支」換成一個svg圖標,其長寬是字體大小的兩倍,背景色、stroke顏色透明度跟前面設置的一致。重寫「showMiniBranch」方法,不必有list序號及delete-icon刪除,只需要有move-link內容。當點擊切換後,菜單將消失。其背景透明度、字體顏色透明度、字體大小跟前面設置的一致。
只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
- 附件
-
ejceesobj202604271649.js- (281.35 KiB) 已下载 55 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
gemini pro第二次才肯吃:
代码: 全选
Here are the modifications required for your feature request. The code has been rewritten to add the settings slider logic, CSS bindings, SVG icons, and the new clean branch menu for `ejceesmini` mode.
### 1. Add Default Settings to `constructor`
Add the initial state variables for the settings in the `constructor`:
```javascript
// Inside constructor(), e.g. after `this.isExportTextMode = false;`
this.miniBgOpacity = 0.7;
this.miniTextOpacity = 1;
this.miniFontSize = 14;
```
### 2. Update CSS in `injectCSS`
Modify the `if (this.mode === 'ejceessingle' || this.mode === 'ejceesmini')` block to include CSS variables, the SVG background for the settings icon, the settings panel layout, and the new branch menu styling.
```javascript
// Replace the ejceesmini specific elements in the `afterContainerCSS` variable:
afterContainerCSS = `
/* ... (Keep your existing @container rules) ... */
/* ejceesmini specific elements */
.ejcees-inner.ejceesmini-mode {
--mini-bg-op: 0.7;
--mini-text-op: 1;
--mini-fz: 14px;
}
.ejceesmini-output-settings {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23ccc" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>');
background-repeat: no-repeat;
background-position: center right 4px;
background-size: 16px 16px;
cursor: pointer;
padding-right: 20px !important;
}
.ejceesmini-settings-panel {
position: absolute;
top: 8px;
right: 8px;
background-color: rgba(0, 0, 0, 0.85);
color: #fff;
padding: 12px;
border-radius: 6px;
z-index: 100;
display: flex;
flex-direction: column;
gap: 10px;
font-size: 12px;
min-width: 160px;
}
.ejceesmini-settings-panel label {
display: flex;
flex-direction: column;
gap: 4px;
}
.ejceesmini-settings-panel input[type="range"] {
width: 100%;
}
.ejceesmini-branch-menu {
position: absolute;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, var(--mini-bg-op));
color: rgba(255, 255, 255, var(--mini-text-op));
padding: 4px;
cursor: pointer;
z-index: 20;
display: flex;
justify-content: center;
align-items: center;
border-bottom-right-radius: 4px;
}
.ejceesmini-branch-menu svg {
width: calc(var(--mini-fz) * 2);
height: calc(var(--mini-fz) * 2);
stroke: rgba(255, 255, 255, var(--mini-text-op));
fill: none;
}
.ejceesmini-comment {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background-color: rgba(0, 0, 0, var(--mini-bg-op));
color: rgba(255, 255, 255, var(--mini-text-op));
padding: 8px;
font-size: var(--mini-fz);
z-index: 20;
box-sizing: border-box;
white-space: pre-wrap;
word-break: break-all;
}
.mini-branch-dropdown {
position: absolute;
background-color: rgba(0, 0, 0, var(--mini-bg-op));
color: rgba(255, 255, 255, var(--mini-text-op));
font-size: var(--mini-fz);
z-index: 777;
border-radius: 4px;
padding: 4px 0;
min-width: 100px;
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
white-space: nowrap;
}
.mini-branch-dropdown .branch-move-link {
display: block;
padding: 8px 12px;
cursor: pointer;
}
.mini-branch-dropdown .branch-move-link:hover {
background-color: rgba(255, 255, 255, 0.2);
}
.mini-branch-dropdown .branch-move-link.active {
font-weight: bold;
background-color: rgba(255, 255, 255, 0.3);
}
.ejceessvg > object {
width: 100%;
height: auto;
}
`;
```
### 3. Update DOM in `renderDOM`
Update the string generated for `ejceesmini` mode to include the settings panel and the SVG branch icon container.
```javascript
if (this.mode === 'ejceesmini') {
this.container.innerHTML = `
<div class="ejcees-inner ejceesmini-mode" style="--mini-bg-op: ${this.miniBgOpacity}; --mini-text-op: ${this.miniTextOpacity}; --mini-fz: ${this.miniFontSize}px;">
<div class="ejceessvg" style="position: relative;">
<div id="mini-branch-container" class="ejceesmini-branch-menu" style="display: none;">
<svg viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="6" y1="3" x2="6" y2="15"></line><circle cx="18" cy="6" r="3"></circle><circle cx="6" cy="18" r="3"></circle><path d="M18 9a9 9 0 0 1-9 9"></path></svg>
</div>
<div id="mini-comment-container" class="ejceesmini-comment" style="display: none;"></div>
<div id="mini-settings-panel" class="ejceesmini-settings-panel" style="display: none;">
<label>BG Opacity: <input type="range" id="mini-bg-op-slider" min="0" max="1" step="0.1" value="${this.miniBgOpacity}"></label>
<label>Text Opacity: <input type="range" id="mini-text-op-slider" min="0" max="1" step="0.1" value="${this.miniTextOpacity}"></label>
<label>Font Size (px): <input type="range" id="mini-fz-slider" min="12" max="24" step="1" value="${this.miniFontSize}"></label>
</div>
</div>
<div class="ejceesctrl" style="flex: 0 0 auto; min-height: unset; height: 48px;">
<div class="ejceesstep">
<div class="ejceesoutput ejceesmini-output-settings" style="width: 64px; height: 36px; display: flex; align-items: center; justify-content: center; font-size: 12px; padding: 0;">0/0</div>
<div class="ejceesstepminus">-</div>
<input type="range" class="ejceesstepdrop" min="0" max="0" value="0" />
<div class="ejceesstepplus">+</div>
<div class="note-btn" id="btn-autoplay" title="Auto Play" style="width: 36px; height: 36px; cursor: pointer; display: flex; align-items: center; justify-content: center; background-color: transparent;">
<svg viewBox="0 0 24 24" style="width: 20px; height: 20px; fill: #ccc;"><path d="M8 5v14l11-7z"/></svg>
</div>
</div>
</div>
<input type="file" id="file-input" style="display: none" />
</div>`;
}
```
### 4. Bind Settings and Sliders in `bindEvents`
Add the event handlers for the newly created settings overlay and sliders within `if (this.mode === 'ejceesmini') {`.
```javascript
if (this.mode === 'ejceesmini') {
// -- Bind Settings UI --
const outputEl = this.container.querySelector('.ejceesoutput');
const settingsPanel = this.container.querySelector('#mini-settings-panel');
const innerWrapper = this.container.querySelector('.ejcees-inner');
if (outputEl && settingsPanel) {
outputEl.addEventListener('click', () => {
settingsPanel.style.display = settingsPanel.style.display === 'none' ? 'flex' : 'none';
});
}
const bgSlider = this.container.querySelector('#mini-bg-op-slider');
const textSlider = this.container.querySelector('#mini-text-op-slider');
const fzSlider = this.container.querySelector('#mini-fz-slider');
if (bgSlider) {
bgSlider.addEventListener('input', (e) => {
this.miniBgOpacity = e.target.value;
innerWrapper.style.setProperty('--mini-bg-op', this.miniBgOpacity);
});
}
if (textSlider) {
textSlider.addEventListener('input', (e) => {
this.miniTextOpacity = e.target.value;
innerWrapper.style.setProperty('--mini-text-op', this.miniTextOpacity);
});
}
if (fzSlider) {
fzSlider.addEventListener('input', (e) => {
this.miniFontSize = e.target.value;
innerWrapper.style.setProperty('--mini-fz', this.miniFontSize + 'px');
});
}
// 2. Implement btn-autoplay functionality (Toggle Auto Play)
// ... (Keep the rest of your original bindEvents logic here)
```
### 5. Update Branch Rendering in `renderRecordUI`
Modify the `renderRecordUI` code block dedicated to `ejceesmini` to handle the SVG menu toggling.
```javascript
renderRecordUI() {
if (this.mode === 'ejceesmini') {
const totalDepth = this.getPathDepth(this.historyFEN, this.currentBranch);
this.stepSlider.max = Math.max(0, totalDepth - 1);
const branchContainer = this.container.querySelector('#mini-branch-container');
const parentNode = this.getNodeAtStep(this.currentStepIndex - 1);
if (parentNode && parentNode.v && parentNode.v.length > 1) {
branchContainer.style.display = 'flex'; // Use flex for proper SVG centering
let forkIndex = -1;
let tempNode = this.historyFEN;
for (let j = 0; j < this.currentStepIndex - 1; j++) {
if (tempNode.v && tempNode.v.length > 1) forkIndex++;
const choice = tempNode.v && tempNode.v.length > 1 ? this.currentBranch[forkIndex] || 0 : 0;
tempNode = tempNode.v[choice];
}
forkIndex++;
branchContainer.onclick = e => {
e.stopPropagation();
this.showMiniBranchMenu(branchContainer, parentNode, forkIndex, this.currentStepIndex);
};
} else {
branchContainer.style.display = 'none';
}
this.updateToolHighlights();
return;
}
// ... (Keep the rest of renderRecordUI)
```
### 6. Create `showMiniBranchMenu` Method
Add the custom branch dropdown builder as a new class method inside the `Ejcees` class block.
```javascript
/**
* Dedicated branch menu constructor for ejceesmini.
* Simple UI containing ONLY move links that vanishes automatically on click.
*/
showMiniBranchMenu(anchor, parentNode, forkIndex, stepIndex) {
const existingMenu = this.container.querySelector('.mini-branch-dropdown');
if (existingMenu) {
existingMenu.remove();
return;
}
const menu = document.createElement('div');
menu.className = 'mini-branch-dropdown';
parentNode.v.forEach((child, idx) => {
const moveLink = document.createElement('div');
moveLink.className = 'branch-move-link';
if (this.currentBranch[forkIndex] === idx) {
moveLink.classList.add('active');
}
moveLink.innerText = this.NotationConverter.toChinese(child.move);
moveLink.onclick = (e) => {
e.stopPropagation();
this.updateBranchPath(forkIndex, idx);
this.jumpToStep(stepIndex);
this.renderRecordUI();
menu.remove();
this.saveStateToUndo();
this.updateToolHighlights();
};
menu.appendChild(moveLink);
});
anchor.appendChild(menu);
// Ensure it's visually aligned under the anchor
menu.style.top = `${anchor.offsetHeight}px`;
menu.style.left = `0px`;
// Close menu when clicking elsewhere
const closeMenu = e => {
if (!menu.contains(e.target) && e.target !== anchor) {
menu.remove();
this.container.removeEventListener('click', closeMenu);
}
};
setTimeout(() => this.container.addEventListener('click', closeMenu), 10);
}
```https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
<svg viewBox="0 0 24 24" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><line x1="6" y1="3" x2="6" y2="15"></line><circle cx="18" cy="6" r="3"></circle><circle cx="6" cy="18" r="3"></circle><path d="M18 9a9 9 0 0 1-9 9"></path></svg>
gemini fast:
代码: 全选
當然可以!以下是三種不同風格的「分支」圖標方案,供您參考:
### 方案一:強調「融合」與「合併」的風格
這款圖標更側重於多個分支最終匯聚到一起的概念。它使用三個點和兩條弧線,巧妙地展示了從不同起點出發,最後融合為同一個終點的過程。它看起來像是一個向上的箭頭,象徵著團結和進步。
```javascript
<svg viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<circle cx="6" cy="18" r="1.5" stroke="currentColor" fill="none" />
<circle cx="18" cy="18" r="1.5" stroke="currentColor" fill="none" />
<circle cx="12" cy="6" r="1.5" stroke="currentColor" fill="none" />
<path d="M6 16.5C6 12 12 12 12 8" stroke="currentColor" fill="none" />
<path d="M18 16.5C18 12 12 12 12 8" stroke="currentColor" fill="none" />
</svg>
```
### 方案二:強調「分叉」與「選擇」的風格
這款圖標使用了更為常見的「樹狀」結構,強調從一個主幹中分化出兩個不同的方向。它簡潔明了,能夠讓人一眼就認出是「分支」的含義。它在底部的分叉處使用了一個小圓點,增加了整體的精緻感。
```javascript
<svg viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 19V12" stroke="currentColor" fill="none" />
<path d="M12 12L6 6" stroke="currentColor" fill="none" />
<path d="M12 12L18 6" stroke="currentColor" fill="none" />
<circle cx="12" cy="12" r="1" stroke="currentColor" fill="none" />
</svg>
```
### 方案三:強調「層級」與「結構」的風格
這款圖標使用了橫向的佈局,更加強調不同層級之間的關係。它從左側的一個點出發,分化出右側的兩個點。它使用了虛線和實線的結合,讓整個圖標更具動感和層次感。它非常適合用於展示複雜的組織架構或工作流程。
```javascript
<svg viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<circle cx="6" cy="12" r="1" stroke="currentColor" fill="none" />
<path d="M8 12H16" stroke="currentColor" fill="none" />
<path d="M16 12V6" stroke="currentColor" fill="none" stroke-dasharray="2 2" />
<path d="M16 12V18" stroke="currentColor" fill="none" stroke-dasharray="2 2" />
<circle cx="18" cy="6" r="1.5" stroke="currentColor" fill="none" />
<circle cx="18" cy="18" r="1.5" stroke="currentColor" fill="none" />
</svg>
```
希望這三種方案能夠滿足您的需求!基於「分叉與選擇」的風格,再給出三種方案。stroke-width都要是1。
gemini thinking:
代码: 全选
當然可以,這裏是基於「分叉與選擇」風格,且 `stroke-width` 皆為 1 的三種方案:
### 方案一:幾何對稱選擇
這款圖標使用三個點和兩條對稱的線段,強調從一個起點精確地分岔出兩個對等的選項。圓點增加了整體的精緻感和節點感。
```javascript
<svg viewBox="0 0 24 24" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="19" r="1" stroke="currentColor" fill="none" />
<line x1="12" y1="18" x2="12" y2="12" stroke="currentColor" fill="none" />
<circle cx="12" cy="12" r="1" stroke="currentColor" fill="none" />
<line x1="11.5" y1="11.5" x2="6" y2="6" stroke="currentColor" fill="none" />
<circle cx="6" cy="6" r="1" stroke="currentColor" fill="none" />
<line x1="12.5" y1="11.5" x2="18" y2="6" stroke="currentColor" fill="none" />
<circle cx="18" cy="6" r="1" stroke="currentColor" fill="none" />
</svg>
```
### 方案二:不對稱路徑選擇
這款圖標模擬了一個主路徑(直行)和一個次要的分叉路徑(彎曲),使用圓弧,強調選擇的多樣性。它比方案一更具有動感。
```javascript
<svg viewBox="0 0 24 24" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
<line x1="6" y1="18" x2="6" y2="6" stroke="currentColor" fill="none"></line>
<path d="M6 12a6 6 0 0 1 12 0" stroke="currentColor" fill="none"></path>
<circle cx="6" cy="18" r="1.5" stroke="currentColor" fill="none"></circle>
<circle cx="6" cy="6" r="1.5" stroke="currentColor" fill="none"></circle>
<circle cx="18" cy="12" r="1.5" stroke="currentColor" fill="none"></circle>
</svg>
```
### 方案三:並行與轉向選擇
這款圖標從一個主幹分叉出一個轉向的分支,最終形成兩個並行的終點。它強調選擇後的不同路徑和並行性,適合用於表示復雜的決策過程。
```javascript
<svg viewBox="0 0 24 24" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
<line x1="6" y1="18" x2="6" y2="6" stroke="currentColor" fill="none"></line>
<path d="M6 12c0 0 12 0 12-6" stroke="currentColor" fill="none"></path>
<circle cx="6" cy="18" r="1.5" stroke="currentColor" fill="none"></circle>
<circle cx="6" cy="6" r="1.5" stroke="currentColor" fill="none"></circle>
<circle cx="18" cy="6" r="1.5" stroke="currentColor" fill="none"></circle>
</svg>
```
這三種方案都保留了分支與選擇的核心概念,但通過不同的視覺構圖、圓圈尺寸和線條類型的組合,呈現出多樣的風格。您可以根據您的項目需求選擇最合適的一款。https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
mini模式右上角的設置中,再加上兩個:this.moveInterval和this.moveSpeed。
滑塊的左邊應當顯示當前的值。
只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
gemini pro:
滑塊的左邊應當顯示當前的值。
只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
gemini pro:
代码: 全选
### 1. Update Default Settings in `constructor`
Add the default values for `moveInterval` and `moveSpeed` if they do not exist yet (adjust the default values as needed based on your existing logic):
```javascript
// Inside constructor()
this.miniBgOpacity = 0.7;
this.miniTextOpacity = 1;
this.miniFontSize = 14;
this.moveInterval = 1000; // Example: 1000ms
this.moveSpeed = 500; // Example: 500ms
```
---
### 2. Update CSS in `injectCSS`
Modify the settings panel CSS to use a flex layout that correctly aligns the label, the current value, and the slider. Replace the previous `.ejceesmini-settings-panel label` and `input[type="range"]` styles with the following:
```javascript
/* Inside injectCSS, replace the previous .ejceesmini-settings-panel styles */
.ejceesmini-settings-panel {
position: absolute;
top: 8px;
right: 8px;
background-color: rgba(0, 0, 0, 0.85);
color: #fff;
padding: 12px;
border-radius: 6px;
z-index: 100;
display: flex;
flex-direction: column;
gap: 10px;
font-size: 12px;
min-width: 240px;
}
.ejceesmini-settings-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.ejceesmini-settings-label {
flex: 0 0 85px;
white-space: nowrap;
}
.ejceesmini-settings-value {
flex: 0 0 30px;
text-align: right;
font-variant-numeric: tabular-nums;
color: #aaa;
}
.ejceesmini-settings-panel input[type="range"] {
flex: 1;
width: 100%;
}
```
---
### 3. Update DOM in `renderDOM`
Replace the HTML inside `<div id="mini-settings-panel">` to include the new rows with the labels, the value spans on the left of the sliders, and the new interval/speed settings.
```javascript
// Inside renderDOM() for 'ejceesmini' mode
<div id="mini-settings-panel" class="ejceesmini-settings-panel" style="display: none;">
<div class="ejceesmini-settings-row">
<span class="ejceesmini-settings-label">BG Opacity:</span>
<span class="ejceesmini-settings-value" id="val-bg-op">${this.miniBgOpacity}</span>
<input type="range" id="mini-bg-op-slider" min="0" max="1" step="0.1" value="${this.miniBgOpacity}">
</div>
<div class="ejceesmini-settings-row">
<span class="ejceesmini-settings-label">Text Opacity:</span>
<span class="ejceesmini-settings-value" id="val-text-op">${this.miniTextOpacity}</span>
<input type="range" id="mini-text-op-slider" min="0" max="1" step="0.1" value="${this.miniTextOpacity}">
</div>
<div class="ejceesmini-settings-row">
<span class="ejceesmini-settings-label">Font Size:</span>
<span class="ejceesmini-settings-value" id="val-fz">${this.miniFontSize}</span>
<input type="range" id="mini-fz-slider" min="12" max="24" step="1" value="${this.miniFontSize}">
</div>
<div class="ejceesmini-settings-row">
<span class="ejceesmini-settings-label">Interval (ms):</span>
<span class="ejceesmini-settings-value" id="val-interval">${this.moveInterval}</span>
<input type="range" id="mini-interval-slider" min="100" max="3000" step="100" value="${this.moveInterval}">
</div>
<div class="ejceesmini-settings-row">
<span class="ejceesmini-settings-label">Speed (ms):</span>
<span class="ejceesmini-settings-value" id="val-speed">${this.moveSpeed}</span>
<input type="range" id="mini-speed-slider" min="100" max="2000" step="100" value="${this.moveSpeed}">
</div>
</div>
```
---
### 4. Update Event Bindings in `bindEvents`
Update the slider logic in `bindEvents` to map the input values to the respective value spans, and to bind the new variables.
```javascript
// Inside bindEvents() for 'ejceesmini' mode
const bgSlider = this.container.querySelector('#mini-bg-op-slider');
const bgVal = this.container.querySelector('#val-bg-op');
if (bgSlider && bgVal) {
bgSlider.addEventListener('input', (e) => {
this.miniBgOpacity = e.target.value;
bgVal.textContent = this.miniBgOpacity;
innerWrapper.style.setProperty('--mini-bg-op', this.miniBgOpacity);
});
}
const textSlider = this.container.querySelector('#mini-text-op-slider');
const textVal = this.container.querySelector('#val-text-op');
if (textSlider && textVal) {
textSlider.addEventListener('input', (e) => {
this.miniTextOpacity = e.target.value;
textVal.textContent = this.miniTextOpacity;
innerWrapper.style.setProperty('--mini-text-op', this.miniTextOpacity);
});
}
const fzSlider = this.container.querySelector('#mini-fz-slider');
const fzVal = this.container.querySelector('#val-fz');
if (fzSlider && fzVal) {
fzSlider.addEventListener('input', (e) => {
this.miniFontSize = e.target.value;
fzVal.textContent = this.miniFontSize;
innerWrapper.style.setProperty('--mini-fz', this.miniFontSize + 'px');
});
}
const intervalSlider = this.container.querySelector('#mini-interval-slider');
const intervalVal = this.container.querySelector('#val-interval');
if (intervalSlider && intervalVal) {
intervalSlider.addEventListener('input', (e) => {
this.moveInterval = parseInt(e.target.value, 10);
intervalVal.textContent = this.moveInterval;
});
}
const speedSlider = this.container.querySelector('#mini-speed-slider');
const speedVal = this.container.querySelector('#val-speed');
if (speedSlider && speedVal) {
speedSlider.addEventListener('input', (e) => {
this.moveSpeed = parseInt(e.target.value, 10);
speedVal.textContent = this.moveSpeed;
});
}
```https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
ejceesobj202604272025
基本完成了mini對象化的功能。
後續剩餘工作:mini模式增加導出文本功能,當一個mini實例的任何一個元素處於選中狀態時,將能按鍵盤的上下左右,左右是step前後移動,上下是當存在分支時的切換分支。
基本完成了mini對象化的功能。
後續剩餘工作:mini模式增加導出文本功能,當一個mini實例的任何一個元素處於選中狀態時,將能按鍵盤的上下左右,左右是step前後移動,上下是當存在分支時的切換分支。
- 附件
-
ejceesobj202604272025.js- (289.17 KiB) 已下载 41 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
改進:
當mini模式時,增加鍵盤按鍵功能。當一個mini實例的任意元素被點擊而激活後,按左右鍵,它的step將能前後走,按上下鍵,將能切換最近的分支(相當於其它模式的ctrl+上下)。
同時增加導出文本功能。當mini模式點擊設置時,將增加一個導出文本功能,當點擊導出按鈕時,整個.ejcees-inner將被一個textarea覆蓋,內容是this.container.textContent,文字被選中,其右上角有關閉按鈕。
只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
當mini模式時,增加鍵盤按鍵功能。當一個mini實例的任意元素被點擊而激活後,按左右鍵,它的step將能前後走,按上下鍵,將能切換最近的分支(相當於其它模式的ctrl+上下)。
同時增加導出文本功能。當mini模式點擊設置時,將增加一個導出文本功能,當點擊導出按鈕時,整個.ejcees-inner將被一個textarea覆蓋,內容是this.container.textContent,文字被選中,其右上角有關閉按鈕。
只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
<div id="mini-settings-panel" class="mini-settings-panel" style="display: flex;">
<div class="mini-settings-row">
<span class="mini-settings-label">BG Opacity:</span>
<span class="mini-settings-value" id="val-bg-op">0.6</span>
<input type="range" id="mini-bg-op-slider" min="0" max="1" step="0.1" value="0.6">
</div>
<div class="mini-settings-row">
<span class="mini-settings-label">Text Opacity:</span>
<span class="mini-settings-value" id="val-text-op">1</span>
<input type="range" id="mini-text-op-slider" min="0" max="1" step="0.1" value="1">
</div>
</div>
<style>
.mini-settings-panel {
position: absolute;
top: 8px;
right: 8px;
background-color: rgba(0, 0, 0, 0.6);
color: rgba(255, 255, 255, 1);
padding: 12px;
border-radius: 6px;
z-index: 100;
display: flex;
flex-direction: column;
gap: 10px;
font-size: 12px;
min-width: 240px;
}
.mini-settings-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
</style>
在前面html+css的基礎上,增加一行mini-settings-row,其內部是一個button.mini-exp-txt[type=button]{export text}。參照前面風格定制它的css。
當點擊時,將在this.container中加上一個div.mini-exp-txt-panel,絕對定位,其寬高都是100%,內含textarea.mini-exp-txt-textarea和一個關閉按鈕.mini-exp-txt-close。
textarea的內容是this.container.textContent,字體大小是14px。當打開時內容將被選中。絕對定位,其寬高都是100%。
關閉按鈕是一個打叉的svg圖標,絕對定位至右上角,寬高都是36px。當點擊時,銷毀div.mini-exp-txt-panel。
給出具體的html+css+js,所有的代碼和注釋都要是英文。
<div class="mini-settings-row">
<span class="mini-settings-label">BG Opacity:</span>
<span class="mini-settings-value" id="val-bg-op">0.6</span>
<input type="range" id="mini-bg-op-slider" min="0" max="1" step="0.1" value="0.6">
</div>
<div class="mini-settings-row">
<span class="mini-settings-label">Text Opacity:</span>
<span class="mini-settings-value" id="val-text-op">1</span>
<input type="range" id="mini-text-op-slider" min="0" max="1" step="0.1" value="1">
</div>
</div>
<style>
.mini-settings-panel {
position: absolute;
top: 8px;
right: 8px;
background-color: rgba(0, 0, 0, 0.6);
color: rgba(255, 255, 255, 1);
padding: 12px;
border-radius: 6px;
z-index: 100;
display: flex;
flex-direction: column;
gap: 10px;
font-size: 12px;
min-width: 240px;
}
.mini-settings-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
</style>
在前面html+css的基礎上,增加一行mini-settings-row,其內部是一個button.mini-exp-txt[type=button]{export text}。參照前面風格定制它的css。
當點擊時,將在this.container中加上一個div.mini-exp-txt-panel,絕對定位,其寬高都是100%,內含textarea.mini-exp-txt-textarea和一個關閉按鈕.mini-exp-txt-close。
textarea的內容是this.container.textContent,字體大小是14px。當打開時內容將被選中。絕對定位,其寬高都是100%。
關閉按鈕是一個打叉的svg圖標,絕對定位至右上角,寬高都是36px。當點擊時,銷毀div.mini-exp-txt-panel。
給出具體的html+css+js,所有的代碼和注釋都要是英文。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
gemini fast:
代码: 全选
To implement this feature, I have added the "Export Text" row to your settings panel and handled the dynamic creation and removal of the overlay panel using JavaScript.
### HTML Structure
Add this row inside your `mini-settings-panel` div:
```html
<div class="mini-settings-row">
<span class="mini-settings-label">Actions:</span>
<button type="button" class="mini-exp-txt" id="mini-exp-btn">Export Text</button>
</div>
```
---
### CSS Styles
Add these styles to your `<style>` block to handle the button and the overlay panel:
```css
/* Button styling matching the dark theme */
.mini-exp-txt {
background-color: rgba(255, 255, 255, 0.2);
color: white;
border: 1px solid rgba(255, 255, 255, 0.3);
padding: 4px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
transition: background-color 0.2s;
}
.mini-exp-txt:hover {
background-color: rgba(255, 255, 255, 0.3);
}
/* Full-screen overlay panel */
.mini-exp-txt-panel {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.85);
z-index: 200;
display: flex;
flex-direction: column;
}
/* Textarea styling */
.mini-exp-txt-textarea {
width: 100%;
height: 100%;
background: transparent;
color: #eee;
border: none;
padding: 40px 15px 15px 15px;
box-sizing: border-box;
font-size: 14px;
font-family: monospace;
resize: none;
outline: none;
}
/* Close button positioning and styling */
.mini-exp-txt-close {
position: absolute;
top: 5px;
right: 5px;
width: 36px;
height: 36px;
background: none;
border: none;
cursor: pointer;
color: white;
display: flex;
align-items: center;
justify-content: center;
z-index: 210;
}
.mini-exp-txt-close:hover {
color: #ff4444;
}
```
---
### JavaScript Logic
Assuming this code runs within a class or scope where `this.container` is defined:
```javascript
// Function to initialize the Export feature
const initExportFeature = () => {
const exportBtn = document.getElementById('mini-exp-btn');
exportBtn.addEventListener('click', () => {
// 1. Create the panel element
const panel = document.createElement('div');
panel.className = 'mini-exp-txt-panel';
// 2. Create the Close Button (SVG icon)
const closeBtn = document.createElement('button');
closeBtn.className = 'mini-exp-txt-close';
closeBtn.innerHTML = `
<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
`;
// 3. Create the Textarea
const textarea = document.createElement('textarea');
textarea.className = 'mini-exp-txt-textarea';
// Use textContent from the container as requested
textarea.value = this.container.textContent.trim();
// 4. Close logic: Remove the panel from DOM
closeBtn.onclick = () => panel.remove();
// 5. Assemble and append
panel.appendChild(closeBtn);
panel.appendChild(textarea);
this.container.appendChild(panel);
// 6. Focus and Select text automatically
textarea.focus();
textarea.select();
});
};
// Execute initialization
initExportFeature();
```
> **Note:** Ensure `this.container` is correctly bound to your parent element before calling the script. The absolute positioning assumes `this.container` has `position: relative` or `position: absolute` set.https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
檢查激活:
代码: 全选
const container = document.querySelector('.container');
// 檢查當前活動元素是否在 container 內部
function hasActiveChild() {
return container.contains(document.activeElement);
}
// 監聽點擊事件
document.addEventListener('click', () => {
if (hasActiveChild()) {
console.log("A child is currently active/focused!");
}
});https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
ejceesobj202604280131
mini能導出文本,有前後上下home、end等快捷鍵。
mini能導出文本,有前後上下home、end等快捷鍵。
- 附件
-
ejceesobj202604280131.js- (296.57 KiB) 已下载 42 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
在wordpress中,php如何拿到某個文章中的a[class=ejcees]的鏈接?
gemini fast:
在wordpresss中的多個short_code中,都要引用同一個js,如何確保這個js只引用一次?
gemini fast:
代码: 全选
在 WordPress 中,要從文章內容(`post_content`)中精準提取帶有特定類名(例如 `class="ejcees"`)的 `<a>` 標籤鏈接,最穩健的方法是使用 PHP 的 **DOMDocument**。
雖然正則表達式(Regex)看似簡單,但處理 HTML 屬性順序或嵌套時容易出錯。以下是推薦的解決方案:
---
### 方法一:使用 DOMDocument (最推薦)
這種方法會將 HTML 解析為物件,能精確定位屬性。
```php
function get_specific_links_from_post($post_id) {
$post = get_post($post_id);
if (!$post) return [];
$content = $post->post_content;
if (empty($content)) return [];
// 建立 DOM 解析器
$dom = new DOMDocument();
// 抑制 HTML5 標籤可能產生的警告,並處理 UTF-8 編碼
libxml_use_internal_errors(true);
$dom->loadHTML('<?xml encoding="UTF-8">' . $content);
libxml_clear_errors();
$links = [];
$xpath = new DOMXPath($dom);
// 使用 XPath 尋找 class 包含 ejcees 的 a 標籤
// contains 處理 class="foo ejcees bar" 的情況
$nodes = $xpath->query("//a[contains(concat(' ', normalize-space(@class), ' '), ' ejcees ')]");
foreach ($nodes as $node) {
$links[] = $node->getAttribute('href');
}
return $links;
}
// 使用範例:
$post_id = 123; // 替換為你的文章 ID
$ejcees_links = get_specific_links_from_post($post_id);
foreach ($ejcees_links as $link) {
echo $link . '<br>';
}
```
---
### 方法二:使用正則表達式 (快速但不夠嚴謹)
如果你確定 `class` 的寫法非常固定(例如永遠是 `class="ejcees"`),可以使用這個方法。但請注意,如果 class 順序改變或有空格,這可能會失效。
```php
function get_links_by_regex($post_id) {
$post = get_post($post_id);
$content = $post->post_content;
// 匹配 class 為 ejcees 的 href 內容
// 注意:這對於複雜的 HTML 結構較脆弱
preg_match_all('/<a[^>]+class=["\'](?:[^"\s]+\s+)*ejcees(?:\s+[^"\s]+)*["\'][^>]+href=["\']([^"\']+)["\']/', $content, $matches);
return !empty($matches[1]) ? $matches[1] : [];
}
```
---
### 關鍵點說明
1. **為什麼用 XPath?**
在 `DOMDocument` 中使用 `xpath->query` 可以處理一個標籤擁有多個 class 的情況(例如 `<a class="btn ejcees active">`)。上面的 XPath 表達式能精準匹配包含 `ejcees` 的節點,而不會誤抓到名為 `ejceestest` 的類名。
2. **處理編碼:**
WordPress 內容通常包含中文字符,`loadHTML` 有時會出現亂碼。加入 `<?xml encoding="UTF-8">` 是為了解決 PHP 解析 HTML 時的編碼識別問題。
3. **效能考量:**
如果你是在一個循環(Loop)中大量執行此操作,建議將結果緩存到 **Post Meta** 中,避免每次讀取頁面都重新解析 HTML 內容。
### 您是想在後台存檔時自動抓取,還是在前台顯示時動態抓取?
* 如果是**存檔時**:可以掛載在 `save_post` 鉤子。
* 如果是**顯示時**:可以寫在 `single.php` 或透過 `the_content` 過濾器。代码: 全选
在 WordPress 開發中,確保多個相同的 Shortcode 僅載入一次 JavaScript 的標準做法是使用 **`wp_enqueue_script()`**。
WordPress 的腳本管理系統天生就具備「去重(De-duplication)」功能。只要你給予該腳本一個唯一的 **Handle(句柄名稱)**,無論你在頁面中調用多少次 `wp_enqueue_script`,WordPress 只會在 HTML 中輸出一次該標籤。
以下是三種常見的實現場景:
---
### 1. 標準做法:在 Shortcode 函式中載入
這是最直接的方法。當 Shortcode 被執行時,才觸發腳本載入。
```php
function my_custom_shortcode_handler($atts) {
// 註冊並排隊腳本
// 參數 1: 'my-unique-js' 是 Handle,WordPress 靠它判斷是否重複
// 參數 2: 檔案 URL
// 參數 3: 依賴項 (如 array('jquery'))
// 參數 4: 版本號
// 參數 5: 是否放進 footer (建議設為 true)
wp_enqueue_script('my-unique-js', get_template_directory_uri() . '/js/myscript.js', array(), '1.0', true);
return '<div class="ejcees">這是 Shortcode 內容</div>';
}
add_shortcode('my_shortcode', 'my_custom_shortcode_handler');
```
**原理:** WordPress 會在渲染頁面(尤其是 Footer)之前收集所有的 `enqueue` 請求,並根據 Handle 自動過濾掉重複項。
---
### 2. 優化做法:先註冊、後掛載
如果你的腳本有許多配置參數,建議先在 `wp_enqueue_scripts` 鉤子中**註冊(Register)**,而在 Shortcode 中僅執行**掛載(Enqueue)**。
```php
// 1. 先在全域註冊腳本(此時還不會在 HTML 輸出)
add_action('wp_enqueue_scripts', function() {
wp_register_script('my-shared-js', get_template_directory_uri() . '/js/shared.js', array(), '1.1', true);
});
// 2. 在 Shortcode 裡呼叫
function my_shortcode_a() {
wp_enqueue_script('my-shared-js'); // 只需寫 Handle
return 'Shortcode A';
}
add_shortcode('shortcode_a', 'my_shortcode_a');
function my_shortcode_b() {
wp_enqueue_script('my-shared-js'); // 即使這裡也呼叫,依然只會出現一次
return 'Shortcode B';
}
add_shortcode('shortcode_b', 'my_shortcode_b');
```
---
### 3. 進階:傳遞資料給 JS (wp_localize_script)
如果你需要傳遞 PHP 變數給 JS,且要確保資料也只定義一次,可以這樣寫:
```php
function my_shortcode_with_data() {
wp_enqueue_script('my-data-js', get_template_directory_uri() . '/js/data.js', array(), '1.0', true);
// 傳遞資料,同樣會因為 Handle 相同而只輸出一次
wp_localize_script('my-data-js', 'myDataObj', array(
'ajax_url' => admin_url('admin-ajax.php'),
));
return '<div class="ejcees">帶資料的 Shortcode</div>';
}
```
---
### 關鍵注意事項 💡
* **Handle 名稱必須一致:** 這是去重的關鍵。如果你在 Shortcode A 用 `my-js`,在 Shortcode B 用 `my-js-v2`,WordPress 會認為這是兩個不同的檔案而全部載入。
* **載入位置:** 由於 Shortcode 是在文章內容解析時才執行的,此時 `<head>` 通常已經輸出完畢。因此,`wp_enqueue_script` 的第五個參數務必設為 **`true`**(放在 Footer),否則腳本可能無法成功載入。
* **不要手寫 `<script>` 標籤:** 絕對避免在 Shortcode 的 `return` 字串中直接寫 `<script src="...">`,這會導致頁面出現多個標籤,且難以維護。
您的 Shortcode 是否需要根據不同的參數傳遞不同的 JS 設定?https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
在线用户
正浏览此版面之用户: 没有注册用户 和 1 访客
