Anonymous
Я пытаюсь создать небольшой полезный js-фреймворк jsml, но застрял [закрыто]
Сообщение
Anonymous » 07 янв 2025, 03:40
Я создаю структуру js, называемую языком разметки JavaScript (JSML), но есть несколько проблем, с которыми я сталкиваюсь, особенно для элемента, который предназначен для циклического перебора массивов, он работает, но всегда перерисовывается при обновлении состояния.
Мне просто нужен хороший способ улучшить «за»
Это моя библиотека под названием JSML:
Код: Выделить всё
import {
mergeStringsWithSeparator,
stopUnwanted,
stringSplitter
} from './JSML/element.js';
import {
removeJSMLWrapper,
inheritParentStyles
} from './JSML/utils.js';
const JSML = (call) => {
let listeners = new Set();
let templates = new Map();
let keysMaps = new Map()
let componentElement = ['IF', 'ELSEIF', 'CLONEABLE', 'CLONE', 'FOR', 'AWAIT'];
const createDeepProxy = (target, callback) => {
return new Proxy(target, {
get(target, property) {
const value = target[property];
if (typeof value === 'object' && value !== null) {
return createDeepProxy(value, callback);
}
return value;
},
set(target, property, value) {
target[property] = value;
callback();
return true;
},
deleteProperty(target, property) {
delete target[property];
callback();
return true;
}
});
};
const state = createDeepProxy(call(), () => {
listeners.forEach(listener => listener());
});
const parsePlaceholders = (template, context) => {
return template.replace(/{{(.*?)}}/g, (_, expression) => {
try {
return new Function(...Object.keys(context), `return ${expression}`)(...Object.values(context));
} catch {
return ''; // Return empty string for invalid placeholders
}
});
};
const isValidPlaceholder = (value) => value !== undefined && value !== null && value !== '';
const directives = {
bind: (el, expression, nu, context = {}) => {
const evaluate = () => {
const processedExp = parsePlaceholders(expression, context);
// Check if the processed expression resolves in the current context
try {
const value = new Function("state", `return state.${processedExp}`)(state);
el.textContent = value; // Update the DOM with the current value
} catch (error) {
console.warn(`Failed to evaluate bind expression: ${expression}`, error);
}
};
//console.log(context,nu)
// Add a watcher to evaluate changes dynamically
const addDynamicBinding = () => {
const processedExp = parsePlaceholders(expression, context);
let value = new Function("state", `return state.${processedExp}`)(state);
Object.defineProperty(state, processedExp, {
set(newValue) {
value = newValue;
el.textContent = newValue; // Reflect changes in DOM
},
get() {
return value;
},
});
};
listeners.add(evaluate);
evaluate();
addDynamicBinding();
},
click: (el, expression, context = {}) => {
el.addEventListener('click', () => {
let processedExp = expression;
Object.entries(context).forEach(([key, value]) => {
const replacementValue = typeof value === 'number' ? value : `'${value}'`;
processedExp = processedExp.replace(new RegExp(`{{${key}}}`, 'g'), replacementValue);
});
new Function("state", `state.${processedExp}`)(state);
});
},
xclass: (el, exp, context) => {
const evaluate = () => {
// Parse the expression into an object
//console.log(exp)
const classMap = new Function("state", ` { return ${exp}; }`)(state);
//console.log(classMap)
// return
if (typeof classMap !== "object" || classMap === null) {
console.warn(`Invalid xclass value: Expected an object, got ${typeof classMap}`);
return;
}
// Loop through the classMap object
for (const [className, condition] of Object.entries(classMap)) {
if (condition) {
let newClass = stringSplitter.byMultipleDelimiters(className.toString(), [','])
newClass.forEach(nclass => {
el.classList.add(nclass)
})
//console.log(e)
} else {
let newClass = stringSplitter.byMultipleDelimiters(className.toString(), [','])
newClass.forEach(nclass => {
el.classList.remove(nclass)
})
}
}
};
// Re-evaluate whenever the state changes
listeners.add(evaluate);
evaluate();
},
xstyle: (el, expression, context = {}) => {
const evaluate = () => {
// Replace placeholders in the expression
let processedExp = parsePlaceholders(expression, context);
try {
// Evaluate the processed expression
const styles = new Function("state", `return ${processedExp}`)(state);
// Apply the evaluated styles to the element
Object.entries(styles).forEach(([key, value]) => {
el.style[key] = value;
});
} catch (error) {
console.error(`Error in xstyle directive: ${error.message}`);
}
};
evaluate();
listeners.add(evaluate);
},
model: (el, expression, context = {}) => {
const updateState = (value) => {
//console.log(value)
const processedExp = parsePlaceholders(expression, context);
//
if (Object.keys(context).length > 0) {
const split = stringSplitter.byMultipleDelimiters(processedExp, ['.']);
new Function("state", `return state.${context.arrayName}[${context.outerIndex}].${split[split.length -1]}=${value}`)(state)
//console.log(processedExp)
} else {
new Function("state", `state.${processedExp} = ${value}`)(state);
}
};
if (el.type === 'radio') {
el.addEventListener('click', () => {
const processedExp = parsePlaceholders(expression, context);
const split = stringSplitter.byMultipleDelimiters(processedExp, ['.']);
const splitLength = split.length
// console.log(processedExp,context)
let currentValue
if (Object.keys(context).length > 0) {
currentValue = new Function("state", `return state.${context.arrayName}[${context.outerIndex}].${split[splitLength -1]}`)(state)
} else {
currentValue = new Function("state", `return state.${processedExp}`)(state);
}
//console.log(currentValue)
updateState(!currentValue); // Toggle the value
});
} else {
el.addEventListener('input', (e) => {
const value = el.type === 'number' ? parseFloat(e.target.value) : e.target.value;
updateState(`'${value}'`);
});
}
const evaluate = () => {
const split = stringSplitter.byMultipleDelimiters(expression, ['.']);
const splitLength = split.length
const processedExp = parsePlaceholders(expression, context);
const merged = mergeStringsWithSeparator('.', `${context.arrayName}[${context.index}]`)
const select = stopUnwanted(merged, /undefined\[undefined\]/i)
if (select && Object.keys(context).length > 0) {
return
}
let value;
if (Object.keys(context).length > 0) {
value = new Function("state", `return state.${context.arrayName}[${context.outerIndex}].${split[splitLength -1]}`)(state)
} else {
if (split.length > 1) {
return
}
value = new Function("state", `return state.${processedExp}`)(state);
}
if (el.type === 'radio') {
el.checked = !!value; // Update the "checked" state
//el.style.backgroundColor = value ? 'blue' : 'red'; // Change style based on state
} else {
el.value = value !== undefined ? value : '';
}
};
evaluate();
listeners.add(evaluate);
}
};
const ElementCom = {
if: (el, context) => {
const expression = el.getAttribute('x');
const evaluate = () => {
const processedExp = parsePlaceholders(expression, context);
try {
const condition = context ? new Function(...Object.keys(context), `return ${processedExp}`)(...Object.values(context)) : new Function('state', `return ${processedExp}`)(state);
Array.from(el.children).forEach(child => {
child.style.display = condition ? '' : 'none';
});
// Handle ELSE sibling
const sibling = el.nextElementSibling;
if (sibling && sibling.tagName === 'ELSE') {
Array.from(sibling.children).forEach(child => {
child.style.display = condition ? 'none' : '';
});
}
} catch (error) {
console.error(`Error in if directive: ${error.message}`);
}
};
evaluate();
listeners.add(evaluate);
},
for: (el, context) => {
if (!templates.has(el)) {
templates.set(el, el.innerHTML);
}
if (!keysMaps.has(el.getAttribute('key'))) {
if (el.getAttribute('key')) {
keysMaps.set(el.getAttribute('key'), el)
}
} else {
console.log(keysMaps.get(el.getAttribute('key')))
console.log('esits')
forLoopUpdater(el, keysMaps)
}
//console.log(el)
const template = templates.get(el);
const [itemNames, , arrayName] = el.getAttribute('x').split(' ');
let splitloopIndex = stringSplitter.byMultipleDelimiters(itemNames, [','])
const itemName = splitloopIndex[0]
const hasInvalidPattern = (str) => {
// Check for the exact pattern '.[].'
const invalidPattern = /\[\]\./;
if (invalidPattern.test(str)) {
return true;
}
return false;
};
const evaluate = () => {
const processedExp = parsePlaceholders(arrayName, context);
if (hasInvalidPattern(processedExp)) {
return;
}
const array = new Function("state", `return state.${processedExp}`)(state);
if (!Array.isArray(array)) return;
el.innerHTML = '';
array.forEach((item, outerIndex) => {
const wrapper = document.createElement('div');
wrapper.innerHTML = template;
const processNode = (node) => {
if (node.nodeType === 3) { // Text node
const text = node.textContent;
const newText = text.replace(
new RegExp(`{{${itemName}}}`, 'g'),
item
).replace(
new RegExp(`{{${itemName}\\.(.+?)}}`, 'g'),
(_, prop) => item[prop]
).replace(
new RegExp(`{{index}}`, 'g'),
outerIndex // Outer index for the current loop
).replace(
new RegExp(`{{${splitloopIndex[1]}}}`, 'g'),
outerIndex // Outer index for the current loop
).replace(
new RegExp(`{{outerIndex}}`, 'g'),
outerIndex // Alias for outer index
);
node.textContent = newText;
} else if (node.attributes) {
Array.from(node.attributes).forEach(attr => {
const newValue = attr.value
.replace(new RegExp(`{{${itemName}}}`, 'g'), item)
.replace(new RegExp(`{{${itemName}\\.(.+?)}}`, 'g'),
(_, prop) => item[prop])
.replace(new RegExp(`{{index}}`, 'g'), outerIndex).replace(
new RegExp(`{{${splitloopIndex[1]}}}`, 'g'),
outerIndex // Outer index for the current loop
).replace(new RegExp(`{{outerIndex}}`, 'g'), outerIndex);
attr.value = newValue;
});
}
Array.from(node.childNodes).forEach(processNode);
};
Array.from(wrapper.childNodes).forEach(processNode);
const children = Array.from(wrapper.children);
children.forEach(child => {
const childContext = {
...context,
[itemName]: item,
outerIndex,
arrayName // Alias for outer index
};
if (child.tagName === 'FOR') {
const innerExp = child.getAttribute('x');
const [innerItemName, , innerArrayName] = innerExp.split(' ');
childContext[`${itemName}_index`] = outerIndex; // Preserve outer loop index
applyElement(child, 'for', childContext);
} else if (child.tagName === 'IF') {
const exp = child.getAttribute('x');
applyElement(child, 'if', childContext, exp);
} else {
attr.forEach(directive => {
const exp = child.getAttribute(directive);
if (exp) {
apply(child, directive, exp, childContext);
}
});
}
const nextAttriToAllChildren = Array.from(child.querySelectorAll('*'))
nextAttriToAllChildren.forEach(nextedChild => {
if (nextedChild.tagName === 'IF') {
return
} else if (nextedChild.tagName === 'FOR') {
}
attr.forEach(directive => {
const exp = nextedChild.getAttribute(directive);
if (exp) {
apply(nextedChild, directive, exp, childContext);
}
});
})
});
while (wrapper.firstChild) {
el.appendChild(wrapper.firstChild);
}
});
};
listeners.add(evaluate);
evaluate();
},
};
const forLoopUpdater = (el, mapskey) => {
const node = mapskey.get(el.getAttribute('key'))
const processNode = (node) => {
if (node.nodeType === 3) { // Text node
const text = node.textContent;
const newText = text.replace(
new RegExp(`{{${itemName}}}`, 'g'),
item
).replace(
new RegExp(`{{${itemName}\\.(.+?)}}`, 'g'),
(_, prop) => item[prop]
).replace(
new RegExp(`{{index}}`, 'g'),
outerIndex // Outer index for the current loop
).replace(
new RegExp(`{{${splitloopIndex[1]}}}`, 'g'),
outerIndex // Outer index for the current loop
).replace(
new RegExp(`{{outerIndex}}`, 'g'),
outerIndex // Alias for outer index
);
node.textContent = newText;
} else if (node.attributes) {
Array.from(node.attributes).forEach(attr => {
const newValue = attr.value
.replace(new RegExp(`{{${itemName}}}`, 'g'), item)
.replace(new RegExp(`{{${itemName}\\.(.+?)}}`, 'g'),
(_, prop) => item[prop])
.replace(new RegExp(`{{index}}`, 'g'), outerIndex).replace(
new RegExp(`{{${splitloopIndex[1]}}}`, 'g'),
outerIndex // Outer index for the current loop
).replace(new RegExp(`{{outerIndex}}`, 'g'), outerIndex);
attr.value = newValue;
});
}
Array.from(node.childNodes).forEach(processNode);
};
}
const applyElement = (el, Elements, context, expression) => {
if (ElementCom[Elements]) {
ElementCom[Elements](el, context, expression);
}
};
const attr = Object.keys(directives);
const apply = (el, directive, expression, context = {}) => {
if (directives[directive]) {
directives[directive](el, expression, context);
}
};
const render = () => {
const jhtmlElements = document.querySelectorAll('*');
jhtmlElements.forEach(el => {
const elements = Array.from(el.children);
elements.forEach(element => {
if (componentElement.includes(element.tagName)) {
componentElement.forEach(com => {
const AllComElement = document.querySelectorAll(com.toLowerCase());
AllComElement.forEach(el => {
applyElement(el, com.toLowerCase());
});
});
return;
}
attr.forEach(directive => {
const expression = element.getAttribute(directive);
if (expression) {
apply(element, directive, expression);
}
});
});
});
componentElement.forEach(jml => {
const jsml = document.querySelectorAll(jml)
jsml.forEach(el => {
inheritParentStyles(el)
})
})
};
render();
return {
state,
render
};
};
export default JSML;
Это HTML-код:
Это код text.js:
Код: Выделить всё
import JSML from './index.js';
const app = JSML(() => ({
items: ['1', '2', '3'],
itemIndex: 0,
isTrue: false,
data: true
}))
const carousel = () => {
return setInterval(() => {
app.state.itemIndex++
if (app.state.itemIndex >= 3) {
app.state.itemIndex = 0
clearInterval(carousel)
}
}, 4000)
}
carousel()
Из вышесказанного, пожалуйста, помогите мне сделать так, чтобы библиотека цикла for не выполняла повторную визуализацию, а вместо этого обновляла элемент for, потому что при повторной визуализации он устанавливается в новый dom и, таким образом, происходит переход. не работает, так что помогите в моей библиотеке
Я ожидаю, что циклу for подойдет надежный тип, такой как реагирование или vue и
Подробнее здесь:
https://stackoverflow.com/questions/793 ... -but-stuck
1736210412
Anonymous
Я создаю структуру js, называемую языком разметки JavaScript (JSML), но есть несколько проблем, с которыми я сталкиваюсь, особенно для элемента, который предназначен для циклического перебора массивов, он работает, но всегда перерисовывается при обновлении состояния. Мне просто нужен хороший способ улучшить «за» Это моя библиотека под названием JSML: [code]import { mergeStringsWithSeparator, stopUnwanted, stringSplitter } from './JSML/element.js'; import { removeJSMLWrapper, inheritParentStyles } from './JSML/utils.js'; const JSML = (call) => { let listeners = new Set(); let templates = new Map(); let keysMaps = new Map() let componentElement = ['IF', 'ELSEIF', 'CLONEABLE', 'CLONE', 'FOR', 'AWAIT']; const createDeepProxy = (target, callback) => { return new Proxy(target, { get(target, property) { const value = target[property]; if (typeof value === 'object' && value !== null) { return createDeepProxy(value, callback); } return value; }, set(target, property, value) { target[property] = value; callback(); return true; }, deleteProperty(target, property) { delete target[property]; callback(); return true; } }); }; const state = createDeepProxy(call(), () => { listeners.forEach(listener => listener()); }); const parsePlaceholders = (template, context) => { return template.replace(/{{(.*?)}}/g, (_, expression) => { try { return new Function(...Object.keys(context), `return ${expression}`)(...Object.values(context)); } catch { return ''; // Return empty string for invalid placeholders } }); }; const isValidPlaceholder = (value) => value !== undefined && value !== null && value !== ''; const directives = { bind: (el, expression, nu, context = {}) => { const evaluate = () => { const processedExp = parsePlaceholders(expression, context); // Check if the processed expression resolves in the current context try { const value = new Function("state", `return state.${processedExp}`)(state); el.textContent = value; // Update the DOM with the current value } catch (error) { console.warn(`Failed to evaluate bind expression: ${expression}`, error); } }; //console.log(context,nu) // Add a watcher to evaluate changes dynamically const addDynamicBinding = () => { const processedExp = parsePlaceholders(expression, context); let value = new Function("state", `return state.${processedExp}`)(state); Object.defineProperty(state, processedExp, { set(newValue) { value = newValue; el.textContent = newValue; // Reflect changes in DOM }, get() { return value; }, }); }; listeners.add(evaluate); evaluate(); addDynamicBinding(); }, click: (el, expression, context = {}) => { el.addEventListener('click', () => { let processedExp = expression; Object.entries(context).forEach(([key, value]) => { const replacementValue = typeof value === 'number' ? value : `'${value}'`; processedExp = processedExp.replace(new RegExp(`{{${key}}}`, 'g'), replacementValue); }); new Function("state", `state.${processedExp}`)(state); }); }, xclass: (el, exp, context) => { const evaluate = () => { // Parse the expression into an object //console.log(exp) const classMap = new Function("state", ` { return ${exp}; }`)(state); //console.log(classMap) // return if (typeof classMap !== "object" || classMap === null) { console.warn(`Invalid xclass value: Expected an object, got ${typeof classMap}`); return; } // Loop through the classMap object for (const [className, condition] of Object.entries(classMap)) { if (condition) { let newClass = stringSplitter.byMultipleDelimiters(className.toString(), [',']) newClass.forEach(nclass => { el.classList.add(nclass) }) //console.log(e) } else { let newClass = stringSplitter.byMultipleDelimiters(className.toString(), [',']) newClass.forEach(nclass => { el.classList.remove(nclass) }) } } }; // Re-evaluate whenever the state changes listeners.add(evaluate); evaluate(); }, xstyle: (el, expression, context = {}) => { const evaluate = () => { // Replace placeholders in the expression let processedExp = parsePlaceholders(expression, context); try { // Evaluate the processed expression const styles = new Function("state", `return ${processedExp}`)(state); // Apply the evaluated styles to the element Object.entries(styles).forEach(([key, value]) => { el.style[key] = value; }); } catch (error) { console.error(`Error in xstyle directive: ${error.message}`); } }; evaluate(); listeners.add(evaluate); }, model: (el, expression, context = {}) => { const updateState = (value) => { //console.log(value) const processedExp = parsePlaceholders(expression, context); // if (Object.keys(context).length > 0) { const split = stringSplitter.byMultipleDelimiters(processedExp, ['.']); new Function("state", `return state.${context.arrayName}[${context.outerIndex}].${split[split.length -1]}=${value}`)(state) //console.log(processedExp) } else { new Function("state", `state.${processedExp} = ${value}`)(state); } }; if (el.type === 'radio') { el.addEventListener('click', () => { const processedExp = parsePlaceholders(expression, context); const split = stringSplitter.byMultipleDelimiters(processedExp, ['.']); const splitLength = split.length // console.log(processedExp,context) let currentValue if (Object.keys(context).length > 0) { currentValue = new Function("state", `return state.${context.arrayName}[${context.outerIndex}].${split[splitLength -1]}`)(state) } else { currentValue = new Function("state", `return state.${processedExp}`)(state); } //console.log(currentValue) updateState(!currentValue); // Toggle the value }); } else { el.addEventListener('input', (e) => { const value = el.type === 'number' ? parseFloat(e.target.value) : e.target.value; updateState(`'${value}'`); }); } const evaluate = () => { const split = stringSplitter.byMultipleDelimiters(expression, ['.']); const splitLength = split.length const processedExp = parsePlaceholders(expression, context); const merged = mergeStringsWithSeparator('.', `${context.arrayName}[${context.index}]`) const select = stopUnwanted(merged, /undefined\[undefined\]/i) if (select && Object.keys(context).length > 0) { return } let value; if (Object.keys(context).length > 0) { value = new Function("state", `return state.${context.arrayName}[${context.outerIndex}].${split[splitLength -1]}`)(state) } else { if (split.length > 1) { return } value = new Function("state", `return state.${processedExp}`)(state); } if (el.type === 'radio') { el.checked = !!value; // Update the "checked" state //el.style.backgroundColor = value ? 'blue' : 'red'; // Change style based on state } else { el.value = value !== undefined ? value : ''; } }; evaluate(); listeners.add(evaluate); } }; const ElementCom = { if: (el, context) => { const expression = el.getAttribute('x'); const evaluate = () => { const processedExp = parsePlaceholders(expression, context); try { const condition = context ? new Function(...Object.keys(context), `return ${processedExp}`)(...Object.values(context)) : new Function('state', `return ${processedExp}`)(state); Array.from(el.children).forEach(child => { child.style.display = condition ? '' : 'none'; }); // Handle ELSE sibling const sibling = el.nextElementSibling; if (sibling && sibling.tagName === 'ELSE') { Array.from(sibling.children).forEach(child => { child.style.display = condition ? 'none' : ''; }); } } catch (error) { console.error(`Error in if directive: ${error.message}`); } }; evaluate(); listeners.add(evaluate); }, for: (el, context) => { if (!templates.has(el)) { templates.set(el, el.innerHTML); } if (!keysMaps.has(el.getAttribute('key'))) { if (el.getAttribute('key')) { keysMaps.set(el.getAttribute('key'), el) } } else { console.log(keysMaps.get(el.getAttribute('key'))) console.log('esits') forLoopUpdater(el, keysMaps) } //console.log(el) const template = templates.get(el); const [itemNames, , arrayName] = el.getAttribute('x').split(' '); let splitloopIndex = stringSplitter.byMultipleDelimiters(itemNames, [',']) const itemName = splitloopIndex[0] const hasInvalidPattern = (str) => { // Check for the exact pattern '.[].' const invalidPattern = /\[\]\./; if (invalidPattern.test(str)) { return true; } return false; }; const evaluate = () => { const processedExp = parsePlaceholders(arrayName, context); if (hasInvalidPattern(processedExp)) { return; } const array = new Function("state", `return state.${processedExp}`)(state); if (!Array.isArray(array)) return; el.innerHTML = ''; array.forEach((item, outerIndex) => { const wrapper = document.createElement('div'); wrapper.innerHTML = template; const processNode = (node) => { if (node.nodeType === 3) { // Text node const text = node.textContent; const newText = text.replace( new RegExp(`{{${itemName}}}`, 'g'), item ).replace( new RegExp(`{{${itemName}\\.(.+?)}}`, 'g'), (_, prop) => item[prop] ).replace( new RegExp(`{{index}}`, 'g'), outerIndex // Outer index for the current loop ).replace( new RegExp(`{{${splitloopIndex[1]}}}`, 'g'), outerIndex // Outer index for the current loop ).replace( new RegExp(`{{outerIndex}}`, 'g'), outerIndex // Alias for outer index ); node.textContent = newText; } else if (node.attributes) { Array.from(node.attributes).forEach(attr => { const newValue = attr.value .replace(new RegExp(`{{${itemName}}}`, 'g'), item) .replace(new RegExp(`{{${itemName}\\.(.+?)}}`, 'g'), (_, prop) => item[prop]) .replace(new RegExp(`{{index}}`, 'g'), outerIndex).replace( new RegExp(`{{${splitloopIndex[1]}}}`, 'g'), outerIndex // Outer index for the current loop ).replace(new RegExp(`{{outerIndex}}`, 'g'), outerIndex); attr.value = newValue; }); } Array.from(node.childNodes).forEach(processNode); }; Array.from(wrapper.childNodes).forEach(processNode); const children = Array.from(wrapper.children); children.forEach(child => { const childContext = { ...context, [itemName]: item, outerIndex, arrayName // Alias for outer index }; if (child.tagName === 'FOR') { const innerExp = child.getAttribute('x'); const [innerItemName, , innerArrayName] = innerExp.split(' '); childContext[`${itemName}_index`] = outerIndex; // Preserve outer loop index applyElement(child, 'for', childContext); } else if (child.tagName === 'IF') { const exp = child.getAttribute('x'); applyElement(child, 'if', childContext, exp); } else { attr.forEach(directive => { const exp = child.getAttribute(directive); if (exp) { apply(child, directive, exp, childContext); } }); } const nextAttriToAllChildren = Array.from(child.querySelectorAll('*')) nextAttriToAllChildren.forEach(nextedChild => { if (nextedChild.tagName === 'IF') { return } else if (nextedChild.tagName === 'FOR') { } attr.forEach(directive => { const exp = nextedChild.getAttribute(directive); if (exp) { apply(nextedChild, directive, exp, childContext); } }); }) }); while (wrapper.firstChild) { el.appendChild(wrapper.firstChild); } }); }; listeners.add(evaluate); evaluate(); }, }; const forLoopUpdater = (el, mapskey) => { const node = mapskey.get(el.getAttribute('key')) const processNode = (node) => { if (node.nodeType === 3) { // Text node const text = node.textContent; const newText = text.replace( new RegExp(`{{${itemName}}}`, 'g'), item ).replace( new RegExp(`{{${itemName}\\.(.+?)}}`, 'g'), (_, prop) => item[prop] ).replace( new RegExp(`{{index}}`, 'g'), outerIndex // Outer index for the current loop ).replace( new RegExp(`{{${splitloopIndex[1]}}}`, 'g'), outerIndex // Outer index for the current loop ).replace( new RegExp(`{{outerIndex}}`, 'g'), outerIndex // Alias for outer index ); node.textContent = newText; } else if (node.attributes) { Array.from(node.attributes).forEach(attr => { const newValue = attr.value .replace(new RegExp(`{{${itemName}}}`, 'g'), item) .replace(new RegExp(`{{${itemName}\\.(.+?)}}`, 'g'), (_, prop) => item[prop]) .replace(new RegExp(`{{index}}`, 'g'), outerIndex).replace( new RegExp(`{{${splitloopIndex[1]}}}`, 'g'), outerIndex // Outer index for the current loop ).replace(new RegExp(`{{outerIndex}}`, 'g'), outerIndex); attr.value = newValue; }); } Array.from(node.childNodes).forEach(processNode); }; } const applyElement = (el, Elements, context, expression) => { if (ElementCom[Elements]) { ElementCom[Elements](el, context, expression); } }; const attr = Object.keys(directives); const apply = (el, directive, expression, context = {}) => { if (directives[directive]) { directives[directive](el, expression, context); } }; const render = () => { const jhtmlElements = document.querySelectorAll('*'); jhtmlElements.forEach(el => { const elements = Array.from(el.children); elements.forEach(element => { if (componentElement.includes(element.tagName)) { componentElement.forEach(com => { const AllComElement = document.querySelectorAll(com.toLowerCase()); AllComElement.forEach(el => { applyElement(el, com.toLowerCase()); }); }); return; } attr.forEach(directive => { const expression = element.getAttribute(directive); if (expression) { apply(element, directive, expression); } }); }); }); componentElement.forEach(jml => { const jsml = document.querySelectorAll(jml) jsml.forEach(el => { inheritParentStyles(el) }) }) }; render(); return { state, render }; }; export default JSML; [/code] Это HTML-код: [code] JSML {{item}} istrue [/code] Это код text.js: [code]import JSML from './index.js'; const app = JSML(() => ({ items: ['1', '2', '3'], itemIndex: 0, isTrue: false, data: true })) const carousel = () => { return setInterval(() => { app.state.itemIndex++ if (app.state.itemIndex >= 3) { app.state.itemIndex = 0 clearInterval(carousel) } }, 4000) } carousel() [/code] Из вышесказанного, пожалуйста, помогите мне сделать так, чтобы библиотека цикла for не выполняла повторную визуализацию, а вместо этого обновляла элемент for, потому что при повторной визуализации он устанавливается в новый dom и, таким образом, происходит переход. не работает, так что помогите в моей библиотеке Я ожидаю, что циклу for подойдет надежный тип, такой как реагирование или vue и Подробнее здесь: [url]https://stackoverflow.com/questions/79334225/i-trying-build-a-small-useful-js-framework-jsml-but-stuck[/url]