Giter VIP home page Giter VIP logo

omi's Introduction

English | 简体中文

omi

Omi - Web Components Framework

import { render, signal, tag, Component, h } from 'omi'

const count = signal(0)

function add() {
  count.value++
}

function sub() {
  count.value--
}

@tag('counter-demo')
export class CounterDemo extends Component {
  static css = 'span { color: red; }'

  render() {
    return (
      <>
        <button onClick={sub}>-</button>
        <span>{count.value}</span>
        <button onClick={add}>+</button>
      </>
    )
  }
}

Use this component:

import { h } from 'omi'
import './counter-demo'

render(<counter-demo />, document.body)

// or 
import { CounterDemo, Other } from './counter-demo'
// Prevent tree Shaking when importing other things
render(<CounterDemo />, document.body)

// or
document.body.appendChild(document.createElement('counter-demo'))

Install

npm i omi

To quickly create an Omi + Vite + TS/JS project:

$ npx omi-cli init my-app    # or create js project by: npx omi-cli init-js my-app
$ cd my-app           
$ npm start           # develop
$ npm run build       # release

To quickly create an Omi + Router + Signal + Suspense + Tailwindcss + Vite + TS project:

$ npx omi-cli init-spa my-app  
$ cd my-app           
$ npm start           # develop
$ npm run build       # release

Packages

  • Core packages
    • omi - Implementation of omi framework.
    • omi-form - Powerful, simple and cross frameworks form solution.
    • lucide-omi - Lucide icon collection for omi.
    • omiu - Hope to create the best web components. For example, the powerful vchart and vtable
    • omi-router - Create SPA of omi framework.
    • omi-cli - To quickly create an Omi + Vite + TS/JS project.
  • Starter kits (not published to npm)
    • omi-elements - Tailwind Element Omi UI KIT.
    • omi-starter-spa - A starter repo for building single page app using Omi + OmiRouter + Tailwindcss + TypeScript + Vite + Prettier.
    • omi-starter-ts - A starter repo for building web app or reusable components using Omi in TypeScript base on Vite.
    • omi-starter-tailwind - A starter repo for building web app or reusable components using Omi + Tailwindcss + TypeScript + Vite.
    • omi-starter-js - A starter repo for building web app or reusable components using Omi in JavaScript base on Vite.
    • omi-vue - Vue SFC + Vite + OMI + OMI-WeUI.
  • Components
  • Directives
    • omi-transition - Applying animations when an component is entering and leaving the DOM.
    • omi-ripple - A lightweight component for adding ripple effects to user interface elements.
  • Examples (not published to npm)

If you want to help the project grow, start by simply sharing it with your peers!

Thank you!

Usage

TodoApp with reactivity functions

Data oriented programming

In data-oriented programming, the focus is on the data itself and the operations on the data, rather than the objects or data structures that hold the data. This programming paradigm emphasizes the change and flow of data, and how to respond to these changes. The TodoApp with reactivity functions is a good example of this, using the concepts of reactive programming, where the UI automatically updates to reflect changes in the data (i.e., the to-do list).

import { render, signal, computed, tag, Component, h } from 'omi'

const todos = signal([
  { text: 'Learn OMI', completed: true },
  { text: 'Learn Web Components', completed: false },
  { text: 'Learn JSX', completed: false },
  { text: 'Learn Signal', completed: false }
])

const completedCount = computed(() => {
  return todos.value.filter(todo => todo.completed).length
})

const newItem = signal('')

function addTodo() {
  // api a
  todos.value.push({ text: newItem.value, completed: false })
  todos.update() // Trigger UI auto update
  
  // api b, same as api a
  // todos.value = [...todos.value, { text: newItem.value, completed: false }]

  newItem.value = '' // Changing the value type can automatically update the UI
}

function removeTodo(index: number) {
  todos.value.splice(index, 1)
  todos.update() // Trigger UI auto update
}

@tag('todo-list')
class TodoList extends Component {
  onInput = (event: Event) => {
    const target = event.target as HTMLInputElement
    newItem.value = target.value
  }

  render() {
    return (
      <>
        <input type="text" value={newItem.value} onInput={this.onInput} />
        <button onClick={addTodo}>Add</button>
        <ul>
          {todos.value.map((todo, index) => {
            return (
              <li>
                <label>
                  <input
                    type="checkbox"
                    checked={todo.completed}
                    onInput={() => {
                      todo.completed = !todo.completed
                      todos.update() // Trigger UI auto update
                    }}
                  />
                  {todo.completed ? <s>{todo.text}</s> : todo.text}
                </label>
                {' '}
                <button onClick={() => removeTodo(index)}></button>
              </li>
            )
          })}
        </ul>
        <p>Completed count: {completedCount.value}</p>
      </>
    )
  }
}

render(<todo-list />, document.body)

TodoApp with Signal Class

Object oriented programming

In object-oriented programming, the focus is on the objects, which contain both data and methods to operate on the data. This programming paradigm emphasizes the interaction and cooperation between objects, and how to organize and manage code through object encapsulation, inheritance, and polymorphism. The TodoApp with reactivity functions can also be implemented in an object-oriented way, for example, by creating a TodoList class that contains the data of the to-do list and methods to operate on this data, as well as a update method to update the UI.

import { render, Signal, tag, Component, h, computed } from 'omi'

type Todo = { text: string, completed: boolean }

class TodoApp extends Signal<{ todos: Todo[], filter: string, newItem: string }> {
  completedCount: ReturnType<typeof computed>

  constructor(todos: Todo[] = []) {
    super({ todos, filter: 'all', newItem: '' })
    this.completedCount = computed(() => this.value.todos.filter(todo => todo.completed).length)
  }

  addTodo = () => {
    // api a
    this.value.todos.push({ text: this.value.newItem, completed: false })
    this.value.newItem = ''
    this.update()

    // api b, same as api a
    // this.update((value) => {
    //   value.todos.push({ text: value.newItem, completed: false })
    //   value.newItem = ''
    // })
  }

  toggleTodo = (index: number) => {
    const todo = this.value.todos[index]
    todo.completed = !todo.completed
    this.update()
  }

  removeTodo = (index: number) => {
    this.value.todos.splice(index, 1)
    this.update()
  }
}

const todoApp = new TodoApp([
  { text: 'Learn OMI', completed: true },
  { text: 'Learn Web Components', completed: false },
  { text: 'Learn JSX', completed: false },
  { text: 'Learn Signal', completed: false }
])

@tag('todo-list')
class TodoList extends Component {
  onInput = (event: Event) => {
    const target = event.target as HTMLInputElement
    todoApp.value.newItem = target.value
  }

  render() {
    const { todos } = todoApp.value
    const { completedCount, toggleTodo, addTodo, removeTodo } = todoApp
    return (
      <>
        <input type="text" value={todoApp.value.newItem} onInput={this.onInput} />
        <button onClick={addTodo}>Add</button>
        <ul>
          {todos.map((todo, index) => {
            return (
              <li>
                <label>
                  <input
                    type="checkbox"
                    checked={todo.completed}
                    onInput={() => toggleTodo(index)}
                  />
                  {todo.completed ? <s>{todo.text}</s> : todo.text}
                </label>
                {' '}
                <button onClick={() => removeTodo(index)}></button>
              </li>
            )
          })}
        </ul>
        <p>Completed count: {completedCount.value}</p>
      </>
    )
  }
}

render(<todo-list />, document.body)

We won't discuss which method is good or bad here. You can choose either method using omi.

Auto Import h

vite.config.js:

import { defineConfig } from 'vite'

export default defineConfig({
  esbuild: {
    jsxInject: "import { h } from 'omi'",
    jsxFactory: "h",
    jsxFragment: "h.f"
  }
})

You can inject code during construction, so you don't have to manually export h.

Define Cross Framework Component

The case of using Omi component in Vue is as follows:

my-counter.tsx:

import { tag, Component, h, bind } from 'omi'

@tag('my-counter')
class MyCounter extends Component {
  static props = {
    count: {
      type: Number,
      default: 0,
      changed(newValue, oldValue) {
        this.state.count = newValue
        this.update()
      }
    }
  }

  state = {
    count: null
  }

  install() {
    this.state.count = this.props.count
  }

  @bind
  sub() {
    this.state.count--
    this.update()
    this.fire('change', this.state.count)
  }

  @bind
  add() {
    this.state.count++
    this.update()
    this.fire('change', this.state.count)
  }

  render() {
    return (
      <>
        <button onClick={this.sub}>-</button>
        <span>{this.state.count}</span>
        <button onClick={this.add}>+</button>
      </>
    )
  }
}

Using in Vue3

<script setup>
import { ref } from 'vue'
// import omi component
import './my-counter'

defineProps({
  msg: String,
})

const count = ref(0)

const change = (e) => {
  count.value = e.detail
}

</script>

<template>
  <h1>{{ msg }}</h1>

  <my-counter @change="change" :count="count" />
  <p>
    【Omi】 
  </p>

  <div class="card">
    <button type="button" @click="count++">count is {{ count }}</button>
    <p>
     【Vue】 
    </p>
  </div>

</template>

If you fire the count-change in an Omi component:

this.fire('count-change', this.state.count)

To use the component and listen for events in Vue:

<my-counter @count-change="change" :count="count" />

Using in React

import { useState, useRef, useEffect } from 'react'
import useEventListener from '@use-it/event-listener'
import './my-counter'

function App() {
  const [count, setCount] = useState(100)
  const myCounterRef = useRef(null)

  useEffect(() => {
    const counter = myCounterRef.current
    if (counter) {
      const handleChange = (evt) => {
        setCount(evt.detail)
      }
      counter.addEventListener('change', handleChange)
      return () => {
        counter.removeEventListener('change', handleChange)
      }
    }
  }, [])

  return (
    <>
      <h1>Omi + React</h1>
      <my-counter count={count} ref={myCounterRef}></my-counter>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
      </div>
    </>
  )
}

export default App

Contributors

License

MIT © Tencent

omi's People

Contributors

dntzhang avatar zhy0216 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

omi's Issues

关于o-repeat写法改进

现在ng2和ng4,vue2都换成for-of写法了。
可以统一一下,切换成本。
建议改成o-for="item of items"这样的写法。

ie8 怎么兼容?

我已经在index页面上引入了es5-shim.js

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Omi</title>
    <script src="js/es5-shim.min.js"></script>
    <link rel="stylesheet" href="css/index-ef14a72eca.css">
</head>
<body>

    <script src="js/vendor.9da31384.js"></script>

    <script src="js/omi.27cdf71e.js"></script>

    <script src="js/index.25f7b79d.js"></script>

</body>
</html>

但是在运行的时候还是出现了错误。

错误如下:
网页错误详细信息

用户代理: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.2)
时间戳: Thu, 30 Mar 2017 07:39:28 UTC

消息: 对象不支持此操作
行: 1059
字符: 2
代码: 0
URI: file:///D:/screwspace/webfront/omi/test/dist/js/omi.27cdf71e.js

消息: 对象不支持此属性或方法
行: 1
字符: 1
代码: 0
URI: file:///D:/screwspace/webfront/omi/test/dist/js/omi.27cdf71e.js

消息: 缺少标识符、字符串或数字
行: 16
字符: 79
代码: 0
URI: file:///D:/screwspace/webfront/omi/test/dist/js/index.25f7b79d.js

应该还是兼容性的问题。

请教自定义标签

假设有三个自定义标签A,B,C,使用结构如下:
<A> <B> <C>...</C> <A>...</A> <A>...</A> </B> </A>
我想将A标签包含的内容全部渲染到A中,B包含的内容渲染到B中,不知道我应该怎样解决
这个问题的难点在于三个标签可以互相包含,如果通过传入data,那样代码的可读性就太差了

关于无限嵌套的问题,子组件如何和父组件或者兄弟组件进行通讯?

我实验了一下声明事无限嵌套的demo,感觉很好。可是我想到另一个问题。就是组件之间如何通信?
比如最上层有一个app组件,app组件里面有两个组件,组件A和组件B,组件A的点击事件或者方法里面,如何更改组件B的内容呢?为此我写了一个demo。代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>特殊标志符</title>
<script type="text/javascript" src="js/jquery-1.11.3.js"></script>
<script type="text/javascript" src="js/nuclear.js"></script>
<script type="text/javascript" src="js/template.js"></script>
</head>
<body>
<div id="demo"></div>
<script type="text/javascript">
//第三方模板的替换
Nuclear.render = function(tpl, data){
    return template.compile(tpl)(data);
};


//子组件
var SubCompement = Nuclear.create({

    render:function(){
        return '<div>{{title}}</div>';
    }


    ,installed:function(){
        var _this = this;
        // console.log(_this)
        // var parent = _this.option.parent;
        // parent.option.text = "11111111";
    }
});


var SubButton = Nuclear.create({
    changeParentTitle:function(){
        console.log(this)
        //这个方法中如何修改SpecialMark组件里面的option?
        console.log(this.node.parentNode);
    },
    render:function(){
        return '<button onclick="changeParentTitle(event)">{{buttonText}}</button>';
    }
});

var SpecialMark = Nuclear.create({
    install: function () {
        var _this = this;
        // debugger;
        this.childrenOptions = [{title: "Todo"},{buttonText:"改变父组件的内容"}];
    }
    //改变title的方法
    ,changeTitle:function(){
        var _this = this;
        //此方法用来修改SubCompement组件的内容,也就是改变子组件的内容
        this.title.option.title = "Todo changed";
    }
    ,render:function(){
        return '\
        <div class="demo">\
            <child nc-constructor="SubCompement" nc-name="title"></child>\
            <child nc-constructor="SubButton" nc-name="subButton"></child>\
            <div>\
                <div>{{title}}</div>\
                <input type="text" nc-id="inputDom" value="{{text}}" />\
                <input type="checkbox" nc-class="chechbox" />\
                <input type="checkbox" nc-class="chechbox" />\
                <button onclick="changeTitle(event)">changeTitle</button>\
            </div>\
        </div>\
        ';
    }

    ,installed:function(){
        var _this = this;
        //在任何一个方法中可以通过this.inputDom获取到这个input的dom节点,返回的是原声的dom节点,可以通过jquery包装后继续使用
        var text = this.inputDom.value;
        //nc-class也是特殊标识符,标志之后,可以通过this.class内容获取到一个数组,但是只能获取衡等于chechbox的内容,如果有额外样式的就获取不到了。
        var chechboxDoms = this.chechbox;
    }
});

new SpecialMark({
    title:'父组件的内容',
    text:'这是一个demo'

},$("#demo").get(0));

</script>
</body>
</html>

上面的例子中,我想用SubButton组件的click事件来更改父组件的title值,但是不知道用什么方法能修改。

omi 的模板换成artTemplate后在IE8 运行不了

omi 的模板换成artTemplate后在IE8 运行不了。
我在入口文件更换了模板

import artTemplate from "artTemplate";
Omi.template = function(tpl, data){
    return artTemplate.compile(tpl)(data);
}

之后在组件中使用artTemplate语法
如下:

import Omi from "omi";

const stylecss = require('./style.css');
// const tpl = require('./index.html');
// console.log(tpl)
class Header extends Omi.Component {
    constructor (data) {
        super(data);
        this.data.name = "header louis";
        this.data.items = [{
            id:'1'
            ,name:'louis'
        },{
            id:'2'
            ,name:'wq'
        },{
            id:'3'
            ,name:'shirley'
        }];
    }
    handleDelClick(dom,evt,index){
        this.data.items.splice(index,1);
        this.update();
    }
    style () {
        return stylecss;
    }
    render () {
        return `
        <div class="header-css">
            {{name}}
            <ul>
                {{each items as item index}}
                    <li>{{index}} - {{item.name}} <a href="javascript:void(0)" onclick="handleDelClick(this,event,{{index}})">x</a></li>
                {{/each}}
            </ul>
        </div>
        `;
    }
}
export default Header;

上面的代码在chrome上没有问题,但是在IE8上面直接显示的是
{Template Error}

先说说我为什么想改模板,因为自带的模板在循环时无法获取索引,在删除时比较困难。

建议支持TypeScript

请问有计划支持TypeScript语言吗?

虽然ES6的使用解决了很多问题,但是随着组件化和模块化的前端开发模式,以及业务量的增大,ES6急需增强以便辅助开发者专心开发业务,TypeScript就是为此而生的。

TypeScript可以为JS添加类型和智能分析,可以帮助开发者构建大型的、强壮的软件。
TypeScript也不会为开发者增加很大的学习成本,TS≈Type+ES。
现在三大流行前端库或者框架(React、Vue和Angular 2)都可以使用TypeScript来编码。

子组件在初始化时使用父组件的option时,内存溢出异常

为了更好联动关系,我写了三个组件,App、ItemList以及ListTitle
其中ItemList和ListTitle都属于App的子组件。ListTitle动态显示列表的数量。为了当ItemList发生变化,及时的更新到ListTitle上,我用了一个比较慵懒的方法,就是共享App的option。代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>组件的嵌套</title>
<script type="text/javascript" src="js/jquery-1.11.3.js"></script>
<script type="text/javascript" src="js/nuclear.js"></script>
<script type="text/javascript" src="js/template.js"></script>
</head>
<body>
<div id="demo"></div>
<script type="text/javascript">
//第三方模板的替换
    Nuclear.render = function (tpl, data) {
        return template.compile(tpl)(data);
    };

    var ListTitle = Nuclear.create({
        render:function(){
            return '<div>List num {{users.length}}</div>'
        }
    });

    var ItemList = Nuclear.create({
        deleteEvent: function (index) {
            this.option.users.splice(index, 1);
        },
        add: function () {
            this.option.users.push({ "name": "333" });
        },
        render: function () {
            return '\
        <ul>\
            {{each users as item index}}\
            <li>{{item.name}} <a onclick="deleteEvent({{index}})" href="javascript:void(0)">delete</a></li>\
            {{/each}}\
        </ul>\
        ';
        }
    });
    var App = Nuclear.create({
        install: function () {
            var _this = this;
            // var listData = _this.pureOption.users;
            // this.childrenOptions = [
            //     _this.pureOption
            //     ,_this.pureOption
            // ];

            this.childrenOptions = [
                {users:_this.pureOption.users}
                ,{users:_this.pureOption.users}
            ];
        },
        add: function () {
            this.itemList.option.users.push({ name: 'aaa' });
        },
        clear: function () {
            this.itemList.option.users = [];
        },
        render: function () {
            return '\
            <div nc-id="app">\
                <child nc-constructor="ListTitle" nc-name="listTitle"></child>\
                <child nc-constructor="ItemList" nc-name="itemList"></child>\
                <div><a onclick="add()" href="javascript:void(0)">添加</a></div>\
                <div><a onclick="clear()" href="javascript:void(0)">清空</a></div>\
            </div>\
        ';
        }
    });
    var app = new App({
        users: [{
            name: 'item1'
        }, {
            name: 'item2'
        }, {
            name: 'item3'
        }]
    }, "#demo");


</script>
</body>
</html>

可是上述代码在运行时直接就报错了。内容如下:
nuclear.js:1453 Uncaught SyntaxError: Invalid regular expression: /\bforEach\b/: Stack overflow(…)

问题在于下面的这个代码
this.listTitle = new ListTitle(this.option);
this.itemList = new ItemList(this.option);

只要我注释其中一条就可以了,只要是有两个初始化则就报错。

使用 Jekyll 或 Hexo 写文档?

只是一个提议,感觉 Jekyll 或 Hexo 更适合做这种静态的文档网站。

React 是在主项目中使用 Jekyll 生成文档。
Vue 是另开了一个项目,使用的 Hexo。

md2site—预览或生成网站报错

js目录添加的vendor.js中没有Omi全局对象上也没有useStore方法

// docs_main_cn.js
import Omi from 'omi';
import Frame from '../component/frame.js';
import AppStore from './app-store.js'

var store = new AppStore({lan:'cn'})
Omi.useStore(store,true);

Omi.render(new Frame(),'body',true);

浏览器控制台报错:

docs-cn.js:22 Uncaught TypeError: _omi2.default.useStore is not a function

Omi的测试项目的vendor.js【132KB】和md2site的vendor.js【177KB】不一样,没懂为什么
AppStore继承Omi.Store且添加了实例方法来将Markdown进行转化,应该不会增加md2site的vendor.js的文件体积.

Omi Conf 深圳站 - 前端开发者的盛会

议题1 - Omi 的前世今生 (会议时间预期在 10000 star 的时候举行)

  • Omi 的故事
  • Omi 核心成员
  • Omi 架构设计
  • Omi 路线图
  • Omi 生态
  • Omi 未来

议题2 - Omip 小程序开发、小程序云开发

议题3 - Omim 跨框架跨主题组件库

议题4 - Mps 增强原生小程序

议题5 - Omix 小程序状态管理

议题6 - Omis 服务端渲染

议题7 - omi-mvvm

  • MVVM 发展史
  • 前端对 MVVM 的误解
  • omi-mvvm 架构
  • mappingjs
  • 前端架构未来展望

议题8 - omi-mp 小程序无边界 Web 开发

  • omi-mp 起源
  • omi-mp 架构设计
  • omi-mp 原理
  • omi-mp 案例

议题9 - cax

  • cax 起源
  • cax 架构设计
  • cax 原理
  • cax 案例

  • 期望的地点(不出意外在深圳举行,除非投票出现较大的偏向)
  • 期待的内容(尽量和前端相关,Omi相关, Web Components相关,小程序、小游戏相关,可视化相关,组件化相关,Web 标准相关,工具效率相关,如果想听后台、云相关的也可以说明具体方向,我来邀请相关领域的专家)
  • 期望的价格(不赚钱,只是交个朋友,如果没有外地的讲师全是腾讯本地讲师的话很可能:+1:免费 👍 ,留言的 Github 昵称入场便可)
  • 期望的时间(大概定在12月份左右)
  • 期待出现的人(除了跨国巨星,我们会尽量邀请)
  • 期待的节目(除了传统的技术分享外,还想看看 小品?歌舞?现场编码?算法对拼?)

多谢大家献计献策,留言的 Github 昵称是入场凭证之一,如果人数够了留言顺序分先后!
🥇 抽奖也从留言名单里抽取 🥇

  • Expected location (no accident will be held in Shenzhen unless there is a larger bias in voting).
  • Expected content (as far as possible related to the front end, Omi related, Web Components related, component related, Web standards related, tool efficiency related, if you want to listen to background, visualization, games, small programs, cloud related can also be specific direction, I invite experts in related fields)
  • Expected price (no money, just make a friend, if not all the lecturers outside Tencent are local lecturers, it's likely 👍 Free 👍 , Github nickname of the message will be admitted)
  • Expected time (around December).
  • Expected Superstar(except for transnational stars, we will try to invite).
  • Expect programs (apart from traditional technology sharing, do you want to see sketches?) Singing and dancing? Live coding? Algorithm for spelling?

Thank you for your advice. Github's nickname is one of the admission vouchers. If there are enough people left, the order of the messages will be different.

omi-router可以使用嵌套路由吗?

参照官方教程,明白了路由的使用。
现在我需要使用嵌套路由。
即路由默认进入home页面(将home组件放置于#views区域)后,我的home页面也有一个路由插座(#home-sub),我如何把其它组件放到home-sub对应的页面中呢?

下面是代码

import OmiRouter from 'omi-router'

class HomeChild extends Omi.Component {
  render() {
    return `
      	 <p>child</p>
  		`;
  }
}
Omi.tag('HomeChild', HomeChild)
class Home extends Omi.Component {
  install(){
    OmiRouter.init({
      routes:[
        {path:'/home/sub1',component:HomeChild},// TODO demo
        {path:'/home/sub2',component:HomeChild},
        {path:'/home/sub3',component:HomeChild}
      ],
      renderTo:'#home-sub',
      defaultRoute:'/home/sub1'
    })
  }
  render() {
    return `
      	<div >Home</div>
        <ul>
      	    <li><a omi-router to="/home/sub1" >yanagao</a></li>
            <li><a omi-router to="/home/sub2" >vorshen</a></li>
            <li><a omi-router to="/home/sub3" >dntzhang</a></li>
        </ul>
        <div id="home-sub"> </div>
  		`
  }
}

Omi.tag('Home', Home)

export default Home

这是代码的截图:
nest

这是仿照官方omi-router/example/simple/main.js写的路由相关内容。
因为已经在main.js里install一次了,运行到它时会报错,如下:

index.js:41 Uncaught TypeError: Cannot read property 'onInstalled' of undefined
    at Object.OmiRouter.init (index.js:41)
    at Home.install (home.js:14)
    at Object.Omi.render (omi.js:369)
    at render (index.js:100)
    at index.js:42
    at omi.js:1266
    at Array.forEach (<anonymous>)
    at App._execInstalledHandlers (omi.js:1265)
    at Object.Omi.render (omi.js:373)
    at Object.<anonymous> (index.js:39)

请问正确的使用方式是什么样?

website 和 todomvc 的用途?

docs/, tutorial/, website/, todomvc/, md2site/ 这几个目录感觉功能重复,对新人不友好。
不知道可否整理一下?感觉眼花缭乱的。。。

Native defining of omi component in browser

Could there rise any problems when defining Omi component with native browser implementation ?

For example i would use customElements.define('like-button', LikeButton)
instead of define('like-button', LikeButton) method and just use regular HTML tag instead of render(h('like-button'), 'body').

I can understand that there might come issues with browser compatibility, but could any other problem rise?

Here's example for my question.
https://jsbin.com/zumiday/edit?html,output

关于omi的两个小疑问?

  1. 看源码使用了morphdom.js,但是放在src里面,而没有放到package.json的require里面?这样没法正常更新morphdom.js
  2. 部分兼容代码放在单独的模块会不会好点,现在看起来src/omi.js有点乱,另外有出处就更好了。
...
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
...

关于第一个问题:我看了下,貌似是对文件进行修改,增加了插槽。

textarea 问题等

  • html 模板里有 textarea,而 textarea 是可以被拖拽的,导致在数据更新之后,textarea 又被重置为初始状态
  • 点击 add 之后,textarea 没有清空,再次点击,新建了一个空的 todo
  • 内联事件?

playground

组件嵌套传值得疑问

请看我写的demo,代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>组件的嵌套</title>
<script type="text/javascript" src="js/jquery-1.11.3.js"></script>
<script type="text/javascript" src="js/nuclear.js"></script>
<script type="text/javascript" src="js/template.js"></script>
</head>
<body>
<div id="demo"></div>
<script type="text/javascript">
//第三方模板的替换
Nuclear.render = function(tpl, data){
    return template.compile(tpl)(data);
};

var ItemList = Nuclear.create({
    deleteEvent:function(index){
        var _this = this;
    },
    add:function(){
        this.option.users.push({"name":"333"});
    },
    render:function(){
        return '\
        <ul>\
            {{each users as item index}}\
            <li>{{item.name}} <a onclick="deleteEvent({{index}})" href="javascript:void(0)">delete</a></li>\
            {{/each}}\
        </ul>\
        ';
    }
});

var App = Nuclear.create({
    install: function () {
        var _this = this;
        var listData = _this.option.users;
        // console.log(listData)
        this.childrenOptions = [{users:listData}];
    },
    add:function(){
        this.itemList.option.users.push({name:'aaa'});
    },
    clear:function(){
        this.itemList.option.users = [];
    },
    render:function(){
        return '\
            <div nc-id="app">\
                <child nc-constructor="ItemList" nc-name="itemList"></child>\
                <div><a onclick="add()" href="javascript:void(0)">添加</a></div>\
                <div><a onclick="clear()" href="javascript:void(0)">清空</a></div>\
            </div>\
        ';
    }
});

var app = new App({
    users:[{
        name:'item1'
    },{
        name:'item2'
    },{
        name:'item3'
    }]
},$("#demo").get(0));


</script>
</body>
</html>


在App的install方法中初始化ItenList组件,在初始化的时候,我给ItemList组件的users初始值是App的option.users。之后问题就来了,执行的add方法添加数据时没有效果。。。

如果我讲ItemList初始化中的users赋值成[],即:this.childrenOptions = [{users:[]];,add方法就好使。

再者就是我执行清空之后,将this.itemList.option.users = [];赋成一个新数组后,add方法也好使了。

类似我这样的写法应该是很正常的,通过给App初始化的数据给各个组件初始化。

注意:开发者关于项目后续开发的维护问题

  • 问题1:随着后续开发的进行项目会变得复杂多变,后期能否平滑的过渡升级
  • 问题2:打包编译后,是否还需要加载编译部分的模块,如art-template 等等
  • 问题3:组件的更新能否提供默认的更新策略,并提供策略的更新配置是否开启或关闭默认的更新
  • 问题4:路由是否支持嵌套使用,使用参数的和路由检测的策略会有哪些变化
  • 问题5:目前能否实现模块的延迟加载
  • 问题6:是否有打算实现ssr这部分功能

Use Preact as a Dependency?

Hi there!

Omi looks really neat! I'm wondering you think it would be possible to use Preact as an upstream dependency rather than inlining it? There are some "hooks" in the source that might be useful for this (options.vnode, options.event, etc).

The advantage of doing so would be that when Preact is updated, Omi would be updated without having to write any code 🍰

Cheers!
-jason

store没有模块的概念?

store没有模块的概念?
对于一个复杂的项目来说,这个store写起来会很累吧。

除非我自己影响的把data划分成模块。
而且对于方法我还得使用各个模块的前缀进行划分。
比如下面的代码


export default {
    data: {
        manager:{//manager模块用到的data
          items:[]
      }
       ,userprofile:{
          id:'1',
          name:'louis'
       }
    },
    methods: {//对于方法为了模块化,所以要定义namespace
        ["manager/add"]: function (value) {//manager模块下的add方法
           
        },
 
        ["userprofile/update"]:function(){//userprofile模块下的update方法
        
       }
    }
}

为了区分模块,似乎只能用上面的方式吗?

有考虑实现模板嵌套吗?

就像 React 那样:

LikeButton = React.create({...})
CommentBox = React.create({
  render: function () {
    return (
      ...
      <LikeButton/>
    );
  }
})

为什么render会执行两次?nuclear v0.5.0

如题。
我的代码如下,非常简单的helloworld:

var data = {
    name:'louis'
};
var helloWorld = Nuclear.create({
    render:function(){
        console.log("render")
        return ''+
            '<div>hello,{{name}}</div>';
    }
});

new helloWorld( data, document.body);

用chrome调试时发现控制台中输出了两个render,既然走了两次render,那么言外之意也会走两次onfresh。这样对于一个ui庞大的SPA应用,会严重影响性能的。

当然,我不知道这是bug,还是我那个地方写的有问题。

提几点小小的建议

  1. 是否可以将中英文文档分离;
  2. 应该要增加AlloyTeamEslint风格检查(代码风格实在有点飘逸。。。);
  3. 是否可以将 plugins 从项目中分离?
  4. 项目结构是否可以整理一下?。。。
  5. PR Welcome?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.