Я пытаюсь создать небольшой полезный js-фреймворк jsml, но застрялHtml

Программисты Html
Ответить
Anonymous
 Я пытаюсь создать небольшой полезный js-фреймворк jsml, но застрял

Сообщение Anonymous »

Проблема в том, что элемент for при его повторной визуализации и создании нового элемента dom означает, что если элемент в элементе for не может выполнить переход при изменении состояния

Код: Выделить всё


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;

This my library called JSML











JSML







class="h-[35vh] transition-all

transition duration-300 ease-in-out overflow-hidden bg-red-600 flex items-center justify-center"

xstyle="{

width: state.itemIndex === 0 ? '100vw' : '0px',

transform: state.itemIndex === 0 ? 'scale(1)' : 'scale(0)',

backgroundColor: state.itemIndex === 0 ? 'blue' : 'red'

}"

>









{{item}}







istrue

















That is the html 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()

Это код text.js.
Из вышесказанного, пожалуйста, помогите мне сделать так, чтобы библиотека for не перерисовывалась, а вместо этого обновляла for element, потому что при повторной визуализации он устанавливается в новый dom, и поэтому переход не работает, так что помогите в моей библиотеке
Я ожидаю, что цикл for будет иметь надежный тип например, реакция или vue и

Подробнее здесь: https://stackoverflow.com/questions/793 ... -but-stuck
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Html»