Riot/JS如何动态创建标准HTML元素(如OL/UL)以避免代码重复
Great question! Duplicating template code is never fun, and Riot.js has some built-in features that let you solve this cleanly without touching innerHTML. Here are two approaches that fit your needs:
1. Extract Repeating Content into a Nested Component
First, eliminate the duplicate <li> code by moving it into a reusable sub-component. This keeps your main list template clean and makes maintenance easier.
Create a new tag file my-list-item.tag:
<my-list-item> <li> <!-- Your extensive inner code goes here --> <!-- You can pass props from the parent if needed, e.g.: --> <span>{this.props.item.content}</span> <button onclick={this.props.handleDelete}>Delete</button> <!-- Add all your existing inner elements, event handlers, etc. --> </li> <script> // Optional: Add component logic here if needed </script> </my-list-item>
Then update your my-list.tag to use this component instead of duplicating code:
<my-list> <ol if="{this.opts.isOrdered}"> <my-list-item each={item in this.opts.items} item={item} handleDelete={this.deleteItem} /> </ol> <ul if="{!this.opts.isOrdered}"> <my-list-item each={item in this.opts.items} item={item} handleDelete={this.deleteItem} /> </ul> <script> this.deleteItem = (e) => { // Your delete logic here }; </script> </my-list>
This way, you only write the inner <li> code once, and reuse it across both list types.
2. Handle Dynamic Wrapper Elements (Beyond ol/ul)
For cases where you need dynamic, non-predefined wrapper elements, Riot.js supports dynamic tag names using curly braces. This lets you render any valid HTML tag without manual DOM manipulation.
Update my-list.tag to use a dynamic wrapper, with optional fallback and validation:
<my-list> <script> this.on('before-mount', () => { // Use custom wrapperTag if provided, else fall back to ol/ul based on isOrdered this.wrapperTag = this.opts.wrapperTag || (this.opts.isOrdered ? 'ol' : 'ul'); // Optional: Validate the tag is allowed (prevent invalid HTML) const allowedTags = ['ol', 'ul', 'div', 'nav', 'section']; if (!allowedTags.includes(this.wrapperTag)) { console.warn(`Wrapper tag "${this.wrapperTag}" is not allowed. Falling back to ul.`); this.wrapperTag = 'ul'; } }); this.deleteItem = (e) => { // Your delete logic here }; </script> <!-- Render the dynamic wrapper tag --> <{this.wrapperTag}> <my-list-item each={item in this.opts.items} item={item} handleDelete={this.deleteItem} /> </{this.wrapperTag}> </my-list>
Now you can use your component with any valid wrapper tag:
<!-- Ordered list --> <my-list is-ordered items="{myItems}" /> <!-- Unordered list --> <my-list items="{myItems}" /> <!-- Custom wrapper like div --> <my-list wrapper-tag="div" items="{myItems}" />
Key Benefits
- No manual
innerHTMLmanipulation—all rendering uses Riot's native template system. - DRY code: Reuse the inner list item logic across all wrapper types.
- Flexible: Supports both predefined (ol/ul) and dynamic wrapper elements.
- Maintainable: Changes to the inner list item only need to be made once.
内容的提问来源于stack exchange,提问作者Remirror

