Node.js-构建模板

构建HTML模板

之前我们通过Node.js制作了一个API,然后获取了JSON数据,那这些JSON数据如何展示在页面中呢,这时候就制作一个HTML模板,来将这些数据展示在页面中

产品页模板

  • 首先我们简单创建一个模板,然后给一点样式,清除内外边距,盒模型集成
vue 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Megrim|Nunito+Sans:400,900" rel="stylesheet" />
    <link rel="icon"
        href="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/240/apple/155/ear-of-maize_1f33d.png">
    <title>新鲜牛油果 🥑 /// 节点农场</title>
    <style>
        *,
        *::before,
        *::after {
            margin: 0;
            padding: 0;
            box-sizing: inherit;
        }
    </style>
</head>

<body>

</body>

</html>
  • 写一点根样式
js 复制代码
     html {
            font-size: 62.5%;
            box-sizing: border-box;
        }

然后根元素的字体设置为浏览器默认字体大小的62.5%,这样响应式更加的优雅;然后设置盒模型,这个盒模型会让内容区的宽高更加可控

  • 继续填充HTML代码
vue 复制代码
<body>
    <div class="container">
        <h1>🌽 节点农场 🥦</h1>
        <figure class="product">
            <div class="product__organic">
                <h5>有机</h5>
            </div>
            <a href="#" class="product__back">
                <span class="emoji-left">👈</span>返回
            </a>
            <div class="product__hero">
                <span class="product__emoji product__emoji--1">🥑</span>
                <span class="product__emoji product__emoji--2">🥑</span>
                <span class="product__emoji product__emoji--3">🥑</span>
                <span class="product__emoji product__emoji--4">🥑</span>
                <span class="product__emoji product__emoji--5">🥑</span>
                <span class="product__emoji product__emoji--6">🥑</span>
                <span class="product__emoji product__emoji--7">🥑</span>
                <span class="product__emoji product__emoji--8">🥑</span>
                <span class="product__emoji product__emoji--9">🥑</span>
            </div>
            <h2 class="product__name">{%PRODUCTNAME%}</h2>
            。。。。。。

注:这里的{%PRODUCTNAME%}是EJS的常用标签,是为了用来执行JavaScript代码,但是不输出,常用的标签还有如下

标签写法 作用 是否输出 是否转义 HTML
<%= variable %> 输出转义后的内容 (安全防 XSS)
<%- variable %> 输出原始 HTML(不转义) (需谨慎使用)
<% code %> 执行 JavaScript 代码,不输出 ---
<%# 注释 %> 模板注释,不会出现在输出中 ---
  • 继续给一点CSS标签
vue 复制代码
 body {
            padding: 5rem 5rem 10rem;
            line-height: 1.7;
            font-family: 'Nunito Sans', sans-serif;
            color: #555;
            min-height: 100vh;
            background: linear-gradient(to bottom right, #9be15d, #00e3ae);
        }

        h1 {
            font-family: 'Megrim', sans-serif;
            font-size: 6rem;
            color: white;
            transform: skewY(-5deg);
            text-align: center;
            position: relative;
            word-spacing: 3px;
        }

        h1::before {
            content: '';
            display: block;
            height: 65%;
            width: 49%;
            position: absolute;
            top: 105%;
            left: 50%;
            background: linear-gradient(to bottom, #9be15d, #00e3ae);
            opacity: 0.8;
            z-index: -1;
            transform: skewY(370deg) translate(-50%, -50%);
        }

        .container {
            width: 95rem;
            margin: 0 auto;
        }

        .product {
            width: 60rem;
            margin: 0 auto;
            margin-top: 9rem;
            background: white;
            box-shadow: 0 3rem 6rem 1rem rgba(0, 0, 0, 0.2);
            position: relative;
        }

        .product__hero {
            position: relative;
            height: 22rem;
            overflow: hidden;
        }

        .product__hero::before {
            content: '';
            display: block;
            height: 100%;
            width: 100%;
            position: absolute;
            top: 0;
            left: 0;
            background-image: linear-gradient(to left bottom, #9be15d, #00e3ae);
            opacity: 0.5;
            z-index: 100;
        }

        .product__emoji {
            font-size: 15rem;
            position: absolute;
        }

        .product__emoji--1 {
            top: -4rem;
            left: -2rem;
            z-index: 10;
        }

        .product__emoji--2 {
            top: -6rem;
            left: 9rem;
        }

        .product__emoji--3 {
            top: -4rem;
            right: 15rem;
        }

        .product__emoji--4 {
            top: -5rem;
            right: 2rem;
            z-index: 10;
        }

        .product__emoji--5 {
            bottom: -9rem;
            left: 18rem;
        }

        .product__emoji--6 {
            bottom: -8rem;
            left: 5rem;
        }

        .product__emoji--7 {
            bottom: -12rem;
            right: 14rem;
        }

        .product__emoji--8 {
            bottom: -8rem;
            right: -2rem;
        }

        .product__emoji--9 {
            top: -7rem;
            left: 19rem;
        }

        .product__organic {
            position: absolute;
            top: -4rem;
            right: -4rem;
            z-index: 1000;
            height: 11rem;
            width: 11rem;
            background-image: linear-gradient(to bottom, #9be15d, #00e3ae);
            border-radius: 50%;
            transform: rotate(15deg);
            box-shadow: 0 2rem 4rem rgba(0, 0, 0, 0.4);
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .product__organic h5 {
            font-weight: 900;
            text-transform: uppercase;
            font-size: 1.8rem;
            color: white;
        }

        .product__back:link,
        .product__back:visited {
            position: absolute;
            top: 2rem;
            left: 2rem;
            font-size: 1.5rem;
            font-weight: 700;
            text-transform: uppercase;
            text-decoration: none;
            z-index: 1000;
            color: #555;
            background-color: white;
            box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.3);
            border-radius: 100rem;
            padding: 0 2rem;
            transition: all 0.3s;
            display: flex;
            align-items: center;
        }

        .product__back:hover,
        .product__back:active {
            background-color: #79e17b;
        }

        .product__name {
            background: linear-gradient(to bottom, #9be15d, #00e3ae);
            padding: 1rem;
            font-family: 'Megrim', sans-serif;
            font-size: 4rem;
            color: white;
            text-align: center;
            word-spacing: 2px;
        }
  • 继续渲染一些信息
vue 复制代码
            <h2 class="product__name">{%PRODUCTNAME%}</h2>
            <div class="product__details">
                <p><span class="emoji-left">🌍</span>来自{%FROM%}</p>
                <p><span class="emoji-left">❤️</span>{%NUTRIENTS%}</p>
                <p><span class="emoji-left">📦</span>{%QUANTITY%}</p>
                <p><span class="emoji-left">🏷</span>{%PRICE%}€</p>
            </div>
  • 添加一些样式
vue 复制代码
       .product__details {
            background-color: #eee;
            padding: 4rem 6rem;
            font-size: 1.9rem;
            display: grid;
            grid-template-columns: 1fr 1fr;
            grid-gap: 1.5rem;
        }
  • 继续添加产品链接和描述
js 复制代码
            <a href="#" class="product__link">
                <span class="emoji-left">🛒</span>
                <span> 添加到购物卡 ({%PRICE%}€)</span>
            </a>
            <p class="product__description">
                {%DESCRIPTION%}
            </p>
  • 添加样式
vue 复制代码
 .product__description {
            padding: 5rem 6rem;
            font-size: 1.6rem;
            line-height: 1.8;
        }

        .product__link:link,
        .product__link:visited {
            display: block;
            background-color: #79e17b;
            color: white;
            font: 1.6rem;
            font-weight: 700;
            text-transform: uppercase;
            text-decoration: none;
            padding: 1.5rem;
            text-align: center;
            transform: scale(1.07) skewX(-20deg);
            box-shadow: 0 2rem 6rem rgba(0, 0, 0, 0.2);
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s;
        }

        .product__link:hover,
        .product__link:active {
            background-color: #9be15d;
            transform: scale(1.1) skewX(-20deg);
        }

        .product__link span {
            transform: skewX(20deg);
        }

        .emoji-left {
            font-size: 2rem;
            margin-right: 1rem;
        }

        .emoji-right {
            font-size: 2rem;
            margin-left: 1rem;
        }

        .not-organic {
            display: none;
        }
  • 其中图片也需要进行替换
js 复制代码
<span class="product__emoji product__emoji--1">{%IMAGE%}</span>
                <span class="product__emoji product__emoji--2">{%IMAGE%}</span>
                <span class="product__emoji product__emoji--3">{%IMAGE%}</span>
                <span class="product__emoji product__emoji--4">{%IMAGE%}</span>
                <span class="product__emoji product__emoji--5">{%IMAGE%}</span>
                <span class="product__emoji product__emoji--6">{%IMAGE%}</span>
                <span class="product__emoji product__emoji--7">{%IMAGE%}</span>
                <span class="product__emoji product__emoji--8">{%IMAGE%}</span>
                <span class="product__emoji product__emoji--9">{%IMAGE%}</span>
  • 标题也需要动态的替换
js 复制代码
    <title>{%PRODUCTNAME%} {%%IMAGE} /// 节点农场</title>
  • 上面的CSS中,有个not-organic,这个作用是当这个食物是有机的话,就显示,如果不是的话就不显示
js 复制代码
            <div class="product__organic {%NOT_ORGANIC%}">
                <h5>有机</h5>
            </div>

概述页模板

  • 这个不作详细解释了,直接把HTML展现出来
vue 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <link href="https://fonts.googleapis.com/css?family=Megrim|Nunito+Sans:400,900" rel="stylesheet" />
  <link rel="icon"
    href="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/240/apple/155/ear-of-maize_1f33d.png" />

  <title>节点农场</title>

  <style>
    *,
    *::before,
    *::after {
      margin: 0;
      padding: 0;
      box-sizing: inherit;
    }

    html {
      font-size: 62.5%;
      box-sizing: border-box;
    }

    body {
      padding: 5rem 5rem 10rem;
      line-height: 1.7;
      font-family: 'Nunito Sans', sans-serif;
      color: #555;
      min-height: 100vh;
      background: linear-gradient(to bottom right, #9be15d, #00e3ae);
    }

    h1 {
      font-family: 'Megrim', sans-serif;
      font-size: 6rem;
      color: white;
      transform: skewY(-5deg);
      text-align: center;
      position: relative;
      word-spacing: 3px;
    }

    h1::before {
      content: '';
      display: block;
      height: 65%;
      width: 49%;
      position: absolute;
      top: 105%;
      left: 50%;
      background: linear-gradient(to bottom, #9be15d, #00e3ae);
      opacity: 0.8;
      z-index: -1;
      transform: skewY(370deg) translate(-50%, -50%);
    }

    .container {
      width: 95rem;
      margin: 0 auto;
    }

    .cards-container {
      margin-top: 8rem;
    }

    .card {
      background: white;
      box-shadow: 0 2rem 6rem 1rem rgba(0, 0, 0, 0.15);
      margin-bottom: 5rem;
      transform: skewX(-20deg);
      display: flex;
      transition: all 0.5s;
    }

    .card__emoji {
      font-size: 5.5rem;
      line-height: 1.2;
      padding: 1.5rem 6rem 0.5rem 1.5rem;
      letter-spacing: -4rem;
      transform: skewX(20deg);
    }

    .card__title-box {
      background: linear-gradient(to bottom, #9be15d, #00e3ae);
      margin-right: auto;
      display: flex;
      align-items: center;
      padding: 0 3rem;
    }

    .card__title {
      font-family: 'Megrim', sans-serif;
      color: white;
      font-size: 3.25rem;
      transform: skewX(20deg);
    }

    .card__details {
      display: flex;
    }

    .card__detail-box {
      align-self: stretch;
      border-right: 1px solid #ddd;
      display: flex;
      align-items: center;
    }

    .card__detail-box:last-child {
      border: none;
    }

    .card__detail {
      font-weight: 400;
      font-size: 1.8rem;
      transform: skewX(20deg);
      padding: 1.75rem;
    }

    .card__detail--organic {
      font-weight: 900;
      text-transform: uppercase;
      font-size: 1.9rem;
      background-image: linear-gradient(to right, #9be15d, #00e3ae);
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;
    }

    .card__detail--price {
      font-weight: 900;
      font-size: 1.9rem;
    }

    .card__link:link,
    .card__link:visited {
      flex: 0 0 auto;
      background-color: #79e17b;
      color: white;
      font-size: 1.6rem;
      font-weight: 900;
      text-transform: uppercase;
      text-decoration: none;
      padding: 2.5rem;
      text-align: center;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: all 0.3s;
    }

    .card__link:hover,
    .card__link:active {
      background-color: #9be15d;
    }

    .card__link span {
      transform: skewX(20deg);
    }

    .card:hover {
      transform: skewX(-20deg) scale(1.08);
      box-shadow: 0 3rem 8rem 2rem rgba(0, 0, 0, 0.15);
    }

    .emoji-left {
      font-size: 2rem;
      margin-right: 1rem;
    }

    .emoji-right {
      font-size: 2rem;
      margin-left: 1rem;
    }

    .not-organic {
      display: none;
    }
  </style>
</head>

<body>
  <div class="container">
    <h1>🌽 节点农场 🥦</h1>

    <div class="cards-container">
      <figure class="card">
        <div class="card__emoji">🥑🥑</div>

        <div class="card__title-box">
          <h2 class="card__title">新鲜牛油果</h2>
        </div>

        <div class="card__details">
          <div class="card__detail-box">
            <h6 class="card__detail card__detail--organic">有机</h6>
          </div>

          <div class="card__detail-box">
            <h6 class="card__detail">每📦 4 🥑</h6>
          </div>

          <div class="card__detail-box">
            <h6 class="card__detail card__detail--price">6.50€</h6>
          </div>
        </div>

        <a class="card__link" href="#">
          <span>Detail <i class="emoji-right">👉</i></span>
        </a>
      </figure>

      <figure class="card">
        <div class="card__emoji">🧀🧀</div>
        <div class="card__title-box">
          <h2 class="card__title">山羊奶酪与绵羊奶酪</h2>
        </div>

        <div class="card__details">
          <div class="card__detail-box">
            <h6 class="card__detail">250g / 📦</h6>
          </div>

          <div class="card__detail-box">
            <h6 class="card__detail card__detail--price">5.00€</h6>
          </div>
        </div>

        <a class="card__link" href="#">
          <span>详情 <i class="emoji-right">👉</i></span>
        </a>
      </figure>

      <figure class="card">
        <div class="card__emoji">🥦🥦</div>
        <div class="card__title-box">
          <h2 class="card__title">阿波罗西兰花</h2>
        </div>

        <div class="card__details">
          <div class="card__detail-box">
            <h6 class="card__detail card__detail--organic">有机</h6>
          </div>

          <div class="card__detail-box">
            <h6 class="card__detail"> 每📦 3 🥦</h6>
          </div>

          <div class="card__detail-box">
            <h6 class="card__detail card__detail--price">5.50€</h6>
          </div>
        </div>

        <a class="card__link" href="#">
          <span>详情 <i class="emoji-right">👉</i></span>
        </a>
      </figure>

      <figure class="card">
        <div class="card__emoji">🥕🥕</div>
        <div class="card__title-box">
          <h2 class="card__title">小胡萝卜</h2>
        </div>

        <div class="card__details">
          <div class="card__detail-box">
            <h6 class="card__detail card__detail--organic">有机</h6>
          </div>

          <div class="card__detail-box">
            <h6 class="card__detail">每📦 20 🥕</h6>
          </div>

          <div class="card__detail-box">
            <h6 class="card__detail card__detail--price">3.00€</h6>
          </div>
        </div>

        <a class="card__link" href="#">
          <span>详情 <i class="emoji-right">👉</i></span>
        </a>
      </figure>

      <figure class="card">
        <div class="card__emoji">🌽🌽</div>
        <div class="card__title-box">
          <h2 class="card__title">甜玉米棒s</h2>
        </div>

        <div class="card__details">
          <div class="card__detail-box">
            <h6 class="card__detail">每📦 2 🌽</h6>
          </div>

          <div class="card__detail-box">
            <h6 class="card__detail card__detail--price">2.00€</h6>
          </div>
        </div>

        <a class="card__link" href="#">
          <span>详情 <i class="emoji-right">👉</i></span>
        </a>
      </figure>
    </div>
  </div>
</body>

</html>
  • 这个模板有个问题,就是他每个产品都是一个卡片,但是多个卡片我是不能确定的,有可能json里面就2个数据,有可能10个数据,所以我们需要把卡片提取出来
js 复制代码
<body>
  <div class="container">
    <h1>🌽 节点农场 🥦</h1>

    <div class="cards-container">
      {{%PRODUCT_CARDS%}}
    </div>
  </div>
</body>
js 复制代码
<figure class="card">
    <div class="card__emoji">{%IMAGE%}{%IMAGE%}</div>

    <div class="card__title-box">
        <h2 class="card__title">{%PRODUCTNAME%}</h2>
    </div>

    <div class="card__details">
        <div class="card__detail-box" {%NOT_ORGANIC%}>
            <h6 class="card__detail">每📦{%QUANTITY%}</h6>
        </div>
        <div class="card__detail-box">
            <h6 class="card__detail card__detail--price">{%PRICE%}€</h6>
        </div>
    </div>

    <a class="card__link" href="/product?id={%id%}">
        <span>详情 <i class="emoji-right">👉</i></span>
    </a>
</figure>

这样我们的模板就制作好了,下次我们将学习如果将这些模板逻辑渲染到页面中;

相关推荐
Python私教10 分钟前
把开源 Agent 打包成"解压双击即用"的 Windows 便携包:一条命令的完整实现
node.js
没事别瞎琢磨2 小时前
十一、审计与 Run Session——每一步操作都被记录
人工智能·node.js
没事别瞎琢磨2 小时前
十六、AgentSandbox——把所有模块串起来的编排类
人工智能·node.js
没事别瞎琢磨3 小时前
十二、网络代理与白名单规则引擎
人工智能·node.js
没事别瞎琢磨3 小时前
十四、Git Worktree 隔离执行
人工智能·node.js
没事别瞎琢磨4 小时前
十、统一 Runner 入口——能力检测与模式回退
人工智能·node.js
没事别瞎琢磨4 小时前
八、环境隔离——构建安全的子进程环境
人工智能·node.js
没事别瞎琢磨5 小时前
六、输出捕获与截断
人工智能·node.js
没事别瞎琢磨5 小时前
七、敏感路径预检——Protected Paths
人工智能·node.js
没事别瞎琢磨5 小时前
五、进程执行——spawn、超时与进程树清理
人工智能·node.js