#html #template #rsx #jsx #web

cercis

Rust中的HTML模板引擎

19个版本 (4个稳定版)

1.2.0 2024年6月5日
1.1.0 2024年5月27日
0.3.1 2024年5月12日
0.2.3 2024年5月5日
0.1.10 2024年5月3日

#108 in 模板引擎


2 crate 中使用

MIT 许可证

21KB
285

cercis-preview

Rust中的HTML模板引擎

cargo add cercis

使用示例

格式化

使用 format!() 宏将数据格式化为字符串

所有数据都通过引用传递到模板中

use cercis::prelude::*;

fn main() {
  let name = "Boris";
  
  let page = rsx!(h1 { "Hello {name}!" });

  // output: <h1>Hello Boris!</h1>
  println!("{}", page.render())
}

属性

属性以 tag: value 的形式写在标签内容之前

use cercis::prelude::*;

fn main() {
  let text_id = "paragraph";
  let text = "Lorem ipsum";

  let page = rsx!(div {
    class: "container",

    h1 { "Hello World!" }
    p {
      id: "{text_id}",
    
      "{text}"
    }
  });

  // output: <div class='container'><h1>Hello World!</h1><p id='paragraph'>Lorem ipsum</p></div>
  println!("{}", page.render())
}

如果需要分支

使用Rust的常规if语法,可以创建分支

use cercis::prelude::*;

fn main() {
  let num = 8;

  let page = rsx!(div {
    if num == 9 {
      span { "Num is 9" }
    }
    if num == 8 {
      span { "Num is 8" }
    }
  });

  // output: <div><span>Num is 8</span></div>
  println!("{}", page.render())
}

循环

使用Rust的常规 for in 语法可以创建循环

use cercis::prelude::*;

fn main() {
  let names = vec!["Boris", "Polina", "Igor"];

  let page = rsx!(ol {
    for name in names {
      li { "{name}" }
    }
  });

  // output: <ol><li>Boris</li><li>Polina</li><li>Igor</li></ol>
  println!("{}", page.render())
}

带有参数的组件

参数声明为常规函数参数

use cercis::prelude::*;

fn main() {
  let text = "Lorem ipsum";

  let page = rsx!(div {
    MyComponent {
        text: text
    }
  });

  // output: <div><p>Lorem ipsum</p></div>
  println!("{}", page.render())
}

#[component]
fn MyComponent<'a>(text: &'a str) -> Element {
    rsx!(p { "{text}" })
}

带有可选参数的组件

如果参数是可选的,则调用组件时可以省略它

use cercis::prelude::*;

fn main() {
  let text = "Lorem ipsum";

  let page = rsx!(div {
    MyComponent {}
    MyComponent {
        text: text
    }
  });

  // output: <div><p>empty</p><p>Lorem ipsum</p></div>
  println!("{}", page.render())
}

#[component]
fn MyComponent<'a>(text: Option<&'a str>) -> Element {
    let text = text.unwrap_or("empty");

    rsx!(p { "{text}" })
}

带有子组件的组件

组件可以接受元素 example: Element<'a> 和子组件,如果变量名为 children: Element<'a>

所有 Element 类型都是可选的

use cercis::prelude::*;

fn main() {
    let text = "Lorem ipsum";

    let page = rsx!(div {
      MyComponent { span { "children" } }
      MyComponent {
          text: rsx!(p { "{text}" }),

          span { "children" }
      }
      MyComponent { text: rsx!(p { "my text" }) }
    });

    /* output(formatted):
    <div>
        <div class='container'>
            <div></div>
            <span>children</span>
        </div>
        <div class='container'>
            <div><p>Lorem ipsum</p></div>
            <span>children</span>
        </div>
        <div class='container'>
            <div><p>my text</p></div>
        </div>
    </div>
    */
    println!("{}", page.render())
}

#[component]
fn MyComponent<'a>(text: Element<'a>, children: Element<'a>) -> Element {
    rsx!(div {
        class: "container",

        div { text }
        children
    })
}

完整页面

use cercis::prelude::*;

fn main() {
    // declarate people names
    let names = vec!["Boris", "Polina", "Igor", "Nikita"];

    // create peoples ordered list
    let peoples = rsx!(ol {
        for name in names {
            li { "{name}" }
        }
    });

    // create full page using our Page component
    let page = rsx!(Page {
        title: "Cercis",

        h1 { "Peoples:" }
        // insert element from peoples variable
        peoples
    });

    // render our page to string
    println!("{}", page.render())
}

#[component]
pub fn Page<'a>(title: Option<&'a str>, head: Element<'a>, children: Element<'a>) -> Element {
    const META_CONTENT: &str = "witdh=device-width, initial-scale=1.0";

    rsx!(
        // turn into: <!DOCTYPE html>
        doctype {}
        html {
            head {
                meta { charset: "UTF-8" }
                meta {
                    name: "viewport",
                    // interpolate META_CONTENT const into value like format!() macro
                    content: "{META_CONTENT}",
                }
                head
                // declarate title if exists
                if let Some(title) = title {
                    title { "{title}" }
                }
            }
            body { children }
        }

    )
}

如果您有任何问题 创建问题

依赖关系

~0.5–1MB
~22K SLoC