Giter Site home page Giter Site logo

joe-sky / nornj Goto Github PK

View Code? Open in Web Editor NEW
101.0 13.0 15.0 18.6 MB

More exciting JS/JSX based on Template Engine, support control flow tags, custom directives, two-way binding, filters and custom operators.

Home Page: https://joe-sky.github.io/nornj

License: MIT License

JavaScript 42.26% TypeScript 57.74%
react template-engine nornj jsx babel-plugin

nornj's Introduction

NornJ

NPM Version License Travis CI Status Codecov NPM Downloads Minzipped Size

English | 简体中文

Introduction

NornJ(pronounced [ˌnɔ:nˈdʒeɪ],abbreviated as nj) is a JS/JSX extension solution based on Template Engine.

Documents

Packages

Package Badges
nornj NPM Version NPM Downloads Minzipped Size
nornj-react NPM Version NPM Downloads Minzipped Size
nornj-loader NPM Version NPM Downloads
babel-plugin-nornj-in-jsx NPM Version NPM Downloads
babel-preset-nornj-with-antd NPM Version NPM Downloads

Overview

In React development, the JSX can use almost all the syntax of javascript and it's very flexible. But if we use NornJ with React and JSX, we can do better, because it can gives JSX new features:

  • Support control statements:
<each of={[1, 2, 3]}>
  <i>{item}</i>
</each>
  • Support directives:
<img n-show={false} />
  • Support filters:
<button>{n`foo | upperFirst`}</button>
  • Support custom operators:
<input value={n`(1 .. 100).join('-')`} />

NornJ presets the above JSX enhancement syntaxs, and also supports custom extensions of more syntaxs. It provides two kinds of similar API: JSX and Tagged templates, can adapt to the preferences of different users 😉.

Basic

class App extends Component {
  addTodo = e => {
    const { todos = [] } = this.state;
    this.setState({ todos: todos.concat(`Item ${todos.length}`) });
  };

  render({ page }, { todos = [] }) {
    return (
      <div className="app">
        <style jsx>`
          .app {
            padding: 20px;
            font-size: .75rem;
          }
        `</style>
        <ul>
          <each of={todos} item="todo">
            <if condition={index > 5}>
              <li>{todo * 2}</li>
              <elseif condition={index > 10}>
                <li>{todo * 3}</li>
              </elseif>
            </if>
          </each>
        </ul>
        <button n-show={todos.length > 0} onClick={this.addTodo}>Add Todo</button>
      </div>
    );
  }
}

For above example, combining with the Babel plugin provided by NornJ, it is possible to write various new enhancement syntaxs in JSX.

  • Use NornJ tagged templates syntaxs(with styled-components, the Template Engine documents are being sorted out and released recently):
const template = html`
  <Container>
    <ul>
      <each of="{todos}">
        <if condition="{@index > 5}">
          <li>{@item * 2}</li>
          <elseif condition="{@index > 10}">
            <li>{@item * 3}</li>
          </elseif>
        </if>
      </each>
    </ul>
    <button n-show="{todos.length > 0}" :onClick="addTodo">Add Todo</button>
  </Container>
`;

const Container = styled.div`
  padding: 20px;
  font-size: 0.75rem;
`;

class App extends Component {
  addTodo = e => {
    const { todos = [] } = this.state;
    this.setState({ todos: todos.concat(`Item ${todos.length}`) });
  };

  render() {
    return template({ components: { Container } }, this.state, this);
  }
}

In the above example, a template function was created using tagged templates API of NornJ. In this way, the template can be separated from the component logic code, and it also supports more concise writing than NornJ JSX API.

Playground

Install

npm install babel-plugin-nornj-in-jsx  #or yarn add babel-plugin-nornj-in-jsx

Next, add nornj-in-jsx to plugins in your babel configuration:

{
  "plugins": [
    "nornj-in-jsx"
  ]
}

Boilerplate projects

Syntax highlight

License

MIT

nornj's People

Contributors

dzh0317 avatar fanyj20 avatar joe-sky avatar saraxue 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

nornj's Issues

mobxFormData中使用each的问题

使用以下方式定义formData时

@observer
export class UserListPage extends React.Component {
  @observable
  userList = ["test"]
  @observable
  formData

  constructor(props) {
    super(props)
    this.formData = (
      <mobxFormData>
        <mobxFieldData name="region_id"/>
        <each of={this.userList}>
          <mobxFieldData name={item}/>
        </each>
      </mobxFormData>
    ).formData
  }
}

会报错
image
即each标签的同级不能有其他的mobxFieldData字段。目前只能通过先定义formData再调用this.formData.add()绕开该该问题

大小写问题

nj init 选择 Y-Dept/template-saas模板生成项目
里面有一些大小写问题,若在服务器端配置自动发布的话会找不到文件。
比如routes-web.js中第二行的bundle应为Bundle
src/web/pages/page4_1/page4_1.js中第九行应为datePicker

Why are there few people supporting

When I first saw the tool, it felt like it was basically complete, with some basic documentation and some appeal (operator expansion, etc.), but why not many users? Is it because React's design principles jsx don't expect too many complicated usages? If possible, are there more users?

模板中写行内样式带color属性会引起模板出错

在升级nornj版本之后。在nj模板中写入如下代码:

nj`<table width="410" height="210" class="${styles.explainTable}">
              <tr>
                <td class="${styles.explainTableTd1}">A<br />AAA</td>
                <td class="${styles.explainTableTd2}">B<br />BBB</td>
              </tr>
              <tr>
                <td class="border-bottom: 1px dashed #ccc;">C<br />CCC</td>
                <td>D<br />DDD</td>
              </tr>
 </table>`()

控制台打印出错:
我是图片

目前的解决方案如下:
1、JS中nj模板尽量换成JSX语法
2、将行内style全部换成class

是否支持嵌套的数据格式?

例如,数据结构如下

{
  "goods": {
    "price": 1
  },
  "activity": {
    "start_time": "2020-01-20"
  }
}

formData定义

formData = (<mobxFormData>
  <mobxFieldData name="goods.price" type="number"/>
  <mobxFieldData name="activity.start_time"/>
</mobxFormData>).formData

form中使用

<Form>
  <FormItem label="商品价格" mobxField={formData["goods.price"]}>
    <Input/>
  </FormItem>
  <FormItem label="活动开始时间" mobxField={formData["activity.start_time"]}>
    <Input/>
  </FormItem>
</Form>

在使用过程中发现这个功能还是挺有必要,但是在文档中没有看到相关的介绍。如果未支持,是否考虑在以后的版本中添加该功能?

【讨论】使NornJ更好地结合JSX运行,开发babel-plugin-nornj-in-jsx

为了更好地服务于React用户,参考了下jsx-control-statementsstyled-jsx
等项目,目前已经实现了以JSX标签的形式在JSX中使用nornj的部分扩展标签,代码和文档在这里

if标签

//转换前:
class TestComponent extends Component {
  render() {
    const a = { b: 1 };

    return (
      <div>
        <if condition={a.b == 1}>
          <i>ifBlock</i>
          <else>
            <i>elseBlock</i>
          </else>
        </if>
      </div>
    );
  }
}

//转换后:
class TestComponent extends Component {
  render() {
    const a = { b: 1 };

    return (
      <div>
        {nj`
          <#if ${a.b == 1}>
            ${<i>ifBlock</i>}
            <#else>
              ${<i>elseBlock</i>}
            </#else>
          </#if>
        `()}
      </div>
    );
  }
}

其中condition参数可以传任意JSX中支持的表达式,但有一种特殊就是es6模板字符串:

class TestComponent extends Component {
  render() {
    const a = { b: 1, c: 'abc' };

    return (
      <div>
        <if condition={`${a}.b.trim() == 1`}>
          ddddd
          <i>aaaaa</i>
          <elseif condition={a.b == 2}>
            <i>ffffff</i>
            <div className="las2">
              <i>888888</i>
            </div>
          </elseif>
          <elseif condition={`${a}.b == 2`}>
            <i>gggggg</i>
          </elseif>

          <else>
            ccccc
            <if condition={!true}>
              <i>bbbbb</i>
              <elseif condition={`${a}.c.substr(${1}) == 'bc'`}>
                <i>ffffff</i>
              </elseif>
              <else>
                <i>eeeee</i>
              </else>
            </if>
          </else>

        </if>
      </div>
    );
  }
}

如上,condition参数传模板字符串时则可以使用nornj内部的表达式与过滤器语法。

each标签

//转换前:
class TestComponent extends Component {
  render() {
    return (
      <div>
        <each of={`1 .. 10`} item="item" index="index" context="ctx">
          <i>{item}</i>
          <i>{index}</i>
          <empty>
            <i>no data</i>
          </empty>
        </each>
      </div>
    );
  }
}

//转换后:
class TestComponent extends Component {
  render() {
    return (
      <div>
        {nj`
          <#each {1 .. 10}>
            #${({ item: item, index: index }) => {
              return [
                <i key={0}>{item}</i>
                <i key={1}>{index}</i>
              ];
            }}
            <empty>
              ${<i>no data</i>}
            </empty>
          </#each>
        `()}
      </div>
    );
  }
}

如上,of参数为要遍历的数组,参数格式和上面if的condition是一样的。item、index、context参数都可以不写,默认值就是例子中的那几个。context参数的文档请看这里

另外还有遍历对象功能:

//转换前:
class TestComponent extends Component {
  render() {
    const obj = { a: 1, b: 2 };

    return (
      <div>
        <each of={obj} key="key" value="value">
          <i>{key}</i>
          <i>{value}</i>
          <i>{index}</i>
        </each>
      </div>
    );
  }
}

switch标签

nornj中switch标签的文档在这里

//转换前:
class TestComponent extends Component {
  render() {
    const a = { b: 1 };

    return (
      <div>
        <switch value={a.b}>
          <case value={1}>
            <i>1</i>
          </case>
          <case value={2}>
            <i>2</i>
          </case>
          <default>
            <i>3</i>
          </default>
        </switch>
      </div>
    );
  }
}

//转换后:
class TestComponent extends Component {
  render() {
    const a = { b: 1 };

    return (
      <div>
        {nj`
          <#switch {{${a.b}}}>
            <#case {{${1}}}>
              ${<i>1</i>}
            </#case>
            <#case {{${2}}}>
              ${<i>2</i>}
            </#case>
            <#default>
              ${<i>3</i>}
            </#default>
          </#switch>
        `()}
      </div>
    );
  }
}

for标签(暂未实现)

nornj中for标签的文档在这里

with标签(预计近期实现)

nornj中with标签的文档在这里

//转换前:
class TestComponent extends Component {
  render() {
    const a = { b: 1, c: { d: 2 } };

    return (
      <div>
        <with v1={a.b} v2={a.c.d}>
          <i>{v1 + v2}</i>
        </with>
      </div>
    );
  }
}

//转换后:
class TestComponent extends Component {
  render() {
    const a = { b: 1, c: { d: 2 } };

    return (
      <div>
        {nj`
          <#with v1={{${a.b}}} v2={{${a.c.d}}}>
            #${({ data: [{ v1, v2 }] }) => {
              return <i>{v1 + v2}</i>;
            }}
          </#with>
        `()}
      </div>
    );
  }
}

template标签(暂决定不实现此功能)

上面的流程控制块主要参考自jsx-control-statements语法,而template主要参考自styled-jsx语法。在JSX中直接运行nornj模板:

//转换前:
class TestComponent extends Component {
  state = {
    a: 1,
    b: 2
  };

  render() {
    return (
      <div>
        <template render={[this, this.state]}>{`
          <input type="text"><br>
          <#if {a > 1}>{b}</#if>
          ${<i>test</i>}
        `}</template>
      </div>
    );
  }
}

//转换后:
class TestComponent extends Component {
  state = {
    a: 1,
    b: 2
  };

  render() {
    return (
      <div>
        ${nj`
          <input type="text"><br>
          <#if {a > 1}>{b}</#if>
          ${<i>test</i>}
        `(this, this.state)}
      </div>
    );
  }
}

还可以在render外创建模板函数:

//转换前:
const tmplFn = <template nj>{`
  <input type="text"><br>
  <#if {a > 1}>{b}</#if>
`}</template>;

class TestComponent extends Component {
  state = {
    a: 1,
    b: 2
  };

  render() {
    return (
      <div>
        {tmplFn(this, this.state)}
      </div>
    );
  }
}

//转换后:
const tmplFn = nj`
  <input type="text"><br>
  <#if {a > 1}>{b}</#if>
`;

class TestComponent extends Component {
  state = {
    a: 1,
    b: 2
  };

  render() {
    return (
      <div>
        {tmplFn(this, this.state)}
      </div>
    );
  }
}

另外,还想过使用<nj-if><nj-else>这样的前缀作为标签名,但是考虑到可读性和会多写了一些字所以先不加了。但就是怕有些编辑器不能支持不带前缀的<if><else>,目前我测了web storm和vscode都没问题。

以上除了if标签外都还没有实现,暂时计划开发以上这些内容,日后再考虑把mobx-model等功能也加进去。

麻烦大家帮忙看看以上是否合理,也给提些意见,好让这插件更好地在JSX中服务于用户:open_mouth:

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.