sciter案例 TodoList 带你入门 sciter 组件化编程

Posted усил

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sciter案例 TodoList 带你入门 sciter 组件化编程相关的知识,希望对你有一定的参考价值。

案例 TodoList 带你入门 sciter 组件化编程

下诉案例已基本覆盖 sciter 组件化编程所涉及到的内容,及注意细节

1、效果图




2、技术要点

  • JSX 组件化编程(类组件)
  • 组件间如何通信
  • 组件生命周期
  • 组件如何绑定事件
  • 如何处理组件中 this 指向
  • 模块化 CSS

3、如何使用

<div class="container"></div>
<script type="module">
    import  TodoList  from './component/index.js';
    document.$(`.container`).content(<TodoList />);
</script>

4、组件 TodoList 源码

export class TodoList extends Element 
    value;
    list = [];
    constructor(props) 
        super(); // 必写
    

    // 组件挂载
    componentDidMount()  
    
    // 组件销毁前
    componentWillUnmount()  
    
    componentUpdate(newdata) 
        if (typeof newdata == "object") 
            Object.assign(this, newdata);
        
        this.post(() => this.patch(this.render()));
    

    render() 
        return (
            <div styleset=__DIR__ + "index.css#todolist">
                <div class="header">
                    <div class="info">To-Do List</div>
                </div>
                <div class="title">~Today I need to ~</div>
                <div class="form">
                    <div class="form-input">
                        <input type="text" placeholder="Add new todo..." value=this.value onchange=(event) => this.value = event.target.value />
                        <button onclick=this.submit><span class="submit">Submit</span></button>
                    </div>
                </div>
                this.list.length == 0 && (
                    <div class="empty-todos">
                        <svg class="icon" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="clipboard-check" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" data-v-132cabf7=""><path class="" fill="currentColor" d="M336 64h-80c0-35.3-28.7-64-64-64s-64 28.7-64 64H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM192 40c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm121.2 231.8l-143 141.8c-4.7 4.7-12.3 4.6-17-.1l-82.6-83.3c-4.7-4.7-4.6-12.3.1-17L99.1 285c4.7-4.7 12.3-4.6 17 .1l46 46.4 106-105.2c4.7-4.7 12.3-4.6 17 .1l28.2 28.4c4.7 4.8 4.6 12.3-.1 17z"></path></svg>
                        <span class="todos-text">Congrat, you have no more tasks to do</span>
                    </div>
                )
                this.list.length != 0 && (
                    <List data=this.list
                        finshed=this.finshed
                        del=this.del
                    />
                )
            </div>
        );
    

    // 提交
    submit = (event) => 
        const value = this.value.trim();
        if (value.length != 0) 

            this.list.unshift(
                id: Math.random(),
                text: value,
                state: false
            );

            this.componentUpdate(
                value: "",
                list: this.list
            );
        

    

    // 完成
    finshed = (data) => 
        const i = this.list.findIndex(item => item.id == data.id);
        if (i != -1) this.list[i].state = true;

        this.componentUpdate( list: this.list );
    

    // 删除
    del = (data) => 
        data.forEach(item1 => 
            const i = this.list.findIndex(item2 => item2.id == item1.id);
            this.list.splice(i, 1);
        );
        this.componentUpdate( list: this.list );
    

5、List 组件源码

class List extends Element 
    id; // 组件 id
    Dom; // 组件 DOM

    data = [];
    
    finshed; // 回调 
    del; // 回调

    key = 'All';

    constructor(props) 
        super();
        // 生成唯一 id
        this.id = `list-$Math.ceil(Math.random() * 100)`;

        this.data = props.data;
        this.finshed = props.finshed;
        this.del = props.del;
    

    // 挂载前
    componentDidMount() 
        // 保存 list 组件的 Dom 元素
        this.Dom = document.querySelector(`#$this.id`);
    

    componentUpdate(newData) 
        if (typeof newdata == "object") 
            this.data = newData.data;
            this.key = newData.key;
        
        this.post(() => this.patch(this.render()));
    

    render(props, kids) 
        const activeLen = this.data.filter(item => item.state).length;
        const state = this.data.some(item => item.state);
        const len = this.data.length;
        return (
            <div styleset=__DIR__ + "index.css#list" id=this.id>
                <ul class="list">
                    this.data.map(item => 
                        return (
                            /* key=Math.random() 使其重新渲染 */
                            <li class=item.state ? 'item active' : 'item' onclick=this.itemFinshed.bind(this, item) tag=item.id key=Math.random()>
                                <i class='state-icon'></i>
                                <span class='text'>item.text </span>
                                <i class='close-icon' onclick=() => this.itemDel(item)></i>
                            </li>
                        )
                    )
                </ul>
                <div class="detail">
                    <span>len item left</span>
                    <span class=this.key == 'All' ? 'state-active' : '' onclick=this.itemFilter.bind(this, 'All')>All</span>
                    <span class=this.key == 'Active' ? 'state-active' : '' style=(state && activeLen != len) ? '' : 'display: none' onclick=this.itemFilter.bind(this, 'Active')>Active</span>
                    <span class=this.key == 'Completed' ? 'state-active' : '' style=(state && activeLen != len) ? '' : 'display: none' onclick=this.itemFilter.bind(this, 'Completed')>Completed</span>
                    <span class=this.key == 'Clear completed' ? 'state-active' : '' style=state ? '' : 'display: none' onclick=this.clearCompleted.bind(this)>Clear completed</span>
                </div>
            </div>
        )
    

    // 完成
    itemFinshed = (item, event) => 
        if (!event.target.classList.contains('close-icon')) 
            this.finshed && this.finshed(item);
        
    

    // 删除
    itemDel = (item) => 
        this.del && this.del([item]);
    

    // 清除完成
    clearCompleted = () => 
        const completedList = this.data.filter(item => item.state);
        this.del && this.del(completedList);
     

    // 过滤
    itemFilter = (key) => 
        const children = this.Dom.querySelector(`.list`).children;
        const stateList = this.Dom.querySelector(`.detail`).children;

        Array.from(stateList).forEach(item =>  item.classList.remove('state-active') );

        const activeList = this.data.filter(item => !item.state);
        const completedList = this.data.filter(item => item.state);

        // 手动操作 DOM
        Array.from(children).forEach(item => 
            const id = item.getAttribute('tag');

            if (key == 'All') 
                stateList[1].classList.add('state-active');
                Object.assign(item.style,  display: 'block' );
            

            if (key == 'Active') 
                stateList[2].classList.add('state-active');
                const i = activeList.findIndex(activeItem => activeItem.id == id);
                const style = i != -1 ?  display: 'block'  :  display: 'none' ;
                Object.assign(item.style, style);
            

            if (key == 'Completed') 
                stateList[3].classList.add('state-active');
                const i = completedList.findIndex(activeItem => activeItem.id == id);
                const style = i != -1 ?  display: 'block'  :  display: 'none' ;
                Object.assign(item.style, style);
            
        );
    

6、模块化 CSS

以下 CSS代码 为 TodoList 的 CSS 样式,可以结合 TodoList 中 render() 渲染方法中的 DOM 结构

/* 模块化 css */

@set todolist 
    :root 
        padding: 30px 40px 20px;
        text-align: center;
        width: 440px;
        max-width: 100%;
        margin: 0 auto;
        border-radius: 15px;
        background: #f2f2f2;
    

    :root .header 
        height: 88px;
        width: 240px;
        margin: auto;
        flow: horizontal;
    

    :root .header::before 
        content: "";
        dispaly: inline-block;
        width: 88px;
        height: 88px;
        background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTkuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiCgkgdmlld0JveD0iMCAwIDUxMiA1MTIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUxMiA1MTI7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHBhdGggc3R5bGU9ImZpbGw6I0YyOUMxRjsiIGQ9Ik0yODkuNjU1LDQyMC4xOTNsMjE2LjI3Ni0yMTYuMjc2YzcuOTQ1LTcuOTQ1LDcuOTQ1LTIyLjA2OSwwLTMwLjAxNGwtMTYuNzcyLTE2Ljc3MgoJYy05LjcxLTkuNzEtMjUuNi05LjcxLTM1LjMxLDBMMjQwLjIyMSwzNzAuNzU5TDI4OS42NTUsNDIwLjE5M3oiLz4KPHBhdGggc3R5bGU9ImZpbGw6I0NDQjM3NTsiIGQ9Ik0yODkuNjU1LDQyMC4xOTNsLTQ5LjQzNC00OS40MzRsMTQ4LjMwMy0xNDguMzAzVjM1LjMxYzAtOS43MS03Ljk0NS0xNy42NTUtMTcuNjU1LTE3LjY1NUgyNjQuOTM4CglWOC44MjhjMC01LjI5Ny0zLjUzMS04LjgyOC04LjgyOC04LjgyOEgxMzIuNTI0Yy01LjI5NywwLTguODI4LDMuNTMxLTguODI4LDguODI4djguODI4SDE3Ljc2NkM4LjA1NSwxNy42NTUsMC4xMSwyNS42LDAuMTEsMzUuMzEKCXY0NTkuMDM0YzAsOS43MSw3Ljk0NSwxNy42NTUsMTcuNjU1LDE3LjY1NWgzNTMuMTAzYzkuNzEsMCwxNy42NTUtNy45NDUsMTcuNjU1LTE3LjY1NVYzMjIuMjA3TDI4OS42NTUsNDIwLjE5M3oiLz4KPHBhdGggc3R5bGU9ImZpbGw6I0VDRjBGMTsiIGQ9Ik0yODkuNjU1LDQyMC4xOTNsLTQ5LjQzNC00OS40MzRsMTEyLjk5My0xMTIuOTkzVjYxLjc5M2MwLTUuMjk3LTMuNTMxLTguODI4LTguODI4LTguODI4aC03OS40NDgKCXY4LjgyOGMwLDUuMjk3LTMuNTMxLDguODI4LTguODI4LDguODI4SDEzMi41MjRjLTUuMjk3LDAtOC44MjgtMy41MzEtOC44MjgtOC44Mjh2LTguODI4SDQ0LjI0OGMtNS4yOTcsMC04LjgyOCwzLjUzMS04LjgyOCw4LjgyOAoJdjQwNi4wNjljMCw1LjI5NywzLjUzMSw4LjgyOCw4LjgyOCw4LjgyOGgzMDAuMTM4YzUuMjk3LDAsOC44MjgtMy41MzEsOC44MjgtOC44MjhWMzU3LjUxN0wyODkuNjU1LDQyMC4xOTN6Ii8+CjxwYXRoIHN0eWxlPSJmaWxsOiNBRjk3NjI7IiBkPSJNMjU2LjExLDcwLjYyMUgxMzIuNTI0Yy01LjI5NywwLTguODI4LTMuNTMxLTguODI4LTguODI4VjguODI4YzAtNS4yOTcsMy41MzEtOC44MjgsOC44MjgtOC44MjgKCUgyNTYuMTFjNS4yOTcsMCw4LjgyOCwzLjUzMSw4LjgyOCw4LjgyOHY1Mi45NjZDMjY0LjkzOCw2Ny4wOSwyNjEuNDA3LDcwLjYyMSwyNTYuMTEsNzAuNjIxIi8+Cjxwb2x5Z29uIHN0eWxlPSJmaWxsOiNFNkU3RTg7IiBwb2ludHM9IjQ4My44NjIsMjI2Ljg2OSA0NDUuOTAzLDI2NC44MjggMzk2LjQ2OSwyMTQuNTEgNDMzLjU0NSwxNzcuNDM0ICIvPgo8cGF0aCBzdHlsZT0iZmlsbDojRUVEREM4OyIgZD0iTTI0Mi44NjksNDM4LjczMWw0Ni43ODYtMTcuNjU1bC00OS40MzQtNTAuMzE3bC0xNy42NTUsNDYuNzg2CglDMjE3LjI2OSw0MzAuNzg2LDIyOS42MjgsNDQ0LjAyOCwyNDIuODY5LDQzOC43MzEiLz4KPGc+Cgk8cGF0aCBzdHlsZT0iZmlsbDojNzk2ODNCOyIgZD0iTTIzOC40NTUsMTQxLjI0MWgtODguMjc2Yy01LjI5NywwLTguODI4LTMuNTMxLTguODI4LTguODI4YzAtNS4yOTcsMy41MzEtOC44MjgsOC44MjgtOC44MjhoODguMjc2CgkJYzUuMjk3LDAsOC44MjgsMy41MzEsOC44MjgsOC44MjhDMjQ3LjI4MywxMzcuNzEsMjQzLjc1MiwxNDEuMjQxLDIzOC40NTUsMTQxLjI0MXoiLz4KCTxwYXRoIHN0eWxlPSJmaWxsOiM3OTY4M0I7IiBkPSJNMzAwLjI0OCwxOTQuMjA3aC01Mi45NjVjLTUuMjk3LDAtOC44MjgtMy41MzEtOC44MjgtOC44MjhzMy41MzEtOC44MjgsOC44MjgtOC44MjhoNTIuOTY1CgkJYzUuMjk3LDAsOC44MjgsMy41MzEsOC44MjgsOC44MjhTMzA1LjU0NSwxOTQuMjA3LDMwMC4yNDgsMTk0LjIwN3oiLz4KCTxwYXRoIHN0eWxlPSJmaWxsOiM3OTY4M0I7IiBkPSJNMjExLjk3MiwxOTQuMjA3SDg4LjM4NmMtNS4yOTcsMC04LjgyOC0zLjUzMS04LjgyOC04LjgyOHMzLjUzMS04LjgyOCw4LjgyOC04LjgyOGgxMjMuNTg2CgkJYzUuMjk3LDAsOC44MjgsMy41MzEsOC44MjgsOC44MjhTMjE3LjI2OSwxOTQuMjA3LDIxMS45NzIsMTk0LjIwN3oiLz4KCTxwYXRoIHN0eWxlPSJmaWxsOiM3OTY4M0I7IiBkPSJNMzAwLjI0OCwyMjkuNTE3aC0yNi40ODNjLTUuMjk3LDAtOC44MjgtMy41MzEtOC44MjgtOC44MjhzMy41MzEtOC44MjgsOC44MjgtOC44MjhoMjYuNDgzCgkJYzUuMjk3LDAsOC44MjgsMy41MzEsOC44MjgsOC44MjhTMzA1LjU0NSwyMjkuNTE3LDMwMC4yNDgsMjI5LjUxN3oiLz4KCTxwYXRoIHN0eWxlPSJmaWxsOiM3OTY4M0I7IiBkPSJNMjM4LjQ1NSwyMjkuNTE3aC03MC42MjFjLTUuMjk3LDAtOC44Mjgt

以上是关于sciter案例 TodoList 带你入门 sciter 组件化编程的主要内容,如果未能解决你的问题,请参考以下文章

React 入门学习-- TodoList 案例

React 入门学习-- TodoList 案例

入门嵌入式HTML/CSS/脚本引擎 sciter(问题篇)

入门嵌入式HTML/CSS/脚本引擎 sciter

2 个案例带你迅速入门 Python Flask 框架

Python实战案例汇总,带你轻松从入门到实战