添加样式表

级联样式表是任何前端用户界面的重要组成部分。 默认启动器配置为导入可以编辑的 main.css 文件,但您可能更喜欢将样式表导入 JavaScript 文件,或者使用替代格式,例如 Syntactically Awesome Style Sheets,又名 SCSS。 本教程通过逐步构建联系人 dapp 来说明如何配置 webpack 以导入样式表。 如果您已经知道如何将级联样式表 (CSS) 添加到基于 webpack 的项目中,则可以跳过本教程。

本教程说明了使用 React 框架来管理前端的文档对象模型 (DOM)。 因为 React 有自己的自定义 DOM 语法,所以需要修改 webpack 配置来编译前端代码,前端代码是用 JSX 编写的。 有关学习使用 React 和 JSX 的更多信息,请参见 React 网站 上的Getting started

开始之前

在开始本教程之前,请验证以下内容:

  • 你已经为前端开发安装了 node.js,并且可以在你的项目中使用 npm install 来安装包。 有关为本地操作系统和包管理器安装节点的信息,请参阅Node 网站。

  • 您已按照下载并安装中的说明下载并安装了 {sdk-short-name} 包。

  • 如果您使用 Visual,您已按照链接中所述为 Motoko 安装 Visual Studio Code 插件:../../quickstart/local-quickstart.html#install-vscode[安装语言编辑器插件] Studio Code 作为您的 IDE。

  • 您已停止在本地运行的任何本地容器执行环境进程 计算机。

本教程要求您使用 {sdk-short-name} 版本 0.8.0 或更高版本。

创建一个新项目

为您的自定义前端 dapp 创建一个新项目目录:

  1. 如果您还没有打开一个终端外壳,请在您的本地计算机上打开一个终端外壳。

  2. 更改为您用于 Internet Computer 项目的文件夹(如果您正在使用一个)。

  3. 如有必要,请验证您是否在本地安装了 node.js

  4. 通过运行以下命令创建一个新项目:

    dfx new contacts
  5. 通过运行以下命令切换到您的项目目录:

    cd contacts

安装 React 框架

如果您以前从未使用过 React,您可能想探索Intro to React 教程或React website 在编辑前端代码之前。

要安装所需的框架模块:

  1. 通过运行以下命令安装 React 模块:

    npm install --save react react-dom
  2. 通过运行以下命令安装所需的 TypeScript 语言编译器加载程序:

    npm install --save-dev typescript ts-loader
  3. 通过运行以下命令安装所需的样式加载器:

    npm install --save-dev style-loader css-loader

    如果 npm install 命令报告了漏洞,您可能还需要运行 npm audit fix 命令来尝试修复报告的漏洞,然后再继续。

    作为安装这些模块的替代方法,您可以编辑默认的 package.json 文件来为您的项目添加依赖项。
    {
      "name": "contacts_assets",
      "version": "0.1.0",
      "description": "",
      "keywords": [],
      "scripts": {
        "build": "webpack"
      },
      "devDependencies": {
        "assert": "2.0.0",
        "buffer": "6.0.3",
        "css-loader": "^5.2.1",
        "events": "3.3.0",
        "html-webpack-plugin": "5.3.1",
        "process": "0.11.10",
        "stream-browserify": "3.0.0",
        "style-loader": "^2.0.0",
        "terser-webpack-plugin": "5.1.1",
        "ts-loader": "^8.1.0",
        "typescript": "^4.2.4",
        "util": "0.12.3",
        "webpack-cli": "4.5.0",
        "webpack": "5.24.4"
      },
      "dependencies": {
        "@dfinity/agent": "0.10.0",
        "@dfinity/candid": "0.10.0",
        "@dfinity/principal": "0.10.0",
        "react-dom": "^17.0.2",
        "react": "^17.0.2"
      }
    }

    此示例 package.json 文件中的 JavaScript 代理版本为 0.10.0。 但是,在大多数情况下,您会希望使用可用的最新版本的代理。 当您创建一个新项目时,dfx new 命令会自动为您检索最新版本的 JavaScript 代理。 您还可以在创建项目后通过运行 npm install --save @dfinity/agent 命令手动检索最新版本。

修改默认程序

对于本教程,您将使用允许您存储和查找联系信息的代码修改主程序。

修改默认程序:

  1. 在文本编辑器中打开 src/contacts/main.mo 文件并删除现有内容。

  2. 将以下示例代码复制并粘贴到文件中:

    import List "mo:base/List";
    import AssocList "mo:base/AssocList";
    
    actor Contact {
    
      var contacts : ContactsMap = List.nil();
    
      type Name = Text;
      type Phone = Nat;
    
      type Entry = {
        name : Name;
        address1 : Text;
        address2 : Text;
        email : Text;
        phone : Phone;
      };
    
      type ContactsMap = AssocList.AssocList<Name, Entry>;
    
      func nameEq(lhs : Name, rhs : Name) : Bool {
        return lhs == rhs;
      };
    
      public func insert(name : Name, address1 : Text, address2 : Text, email : Text, phone : Phone) : async () {
         let newEntry : Entry = {
           name;
           address1;
           address2;
           email;
           phone;
         };
    
         let (newContacts, _) = AssocList.replace(
           contacts,
           name,
           func(n: Name, m: Name) : Bool { n == m },
           ?newEntry
         );
         contacts := newContacts;
      };
    
      public query func lookup(name : Name) : async ?Entry {
        return AssocList.find(contacts, name, nameEq);
      };
    };
  3. 保存更改并关闭 main.mo 文件以继续。

修改前端文件

您现在已准备好为您的程序创建一个新的前端。

  1. 在文本编辑器中打开 webpack 配置文件(webpack.config.js)。

  2. 修改前端入口,将默认的 index.html 替换为 index.jsx。

    entry: {
      // The frontend.entrypoint points to the HTML file for this build, so we need
      // to replace the extension to `.js`.
      index: path.join(__dirname, asset_entry).replace(/\.html$/, ".jsx"),
    },
  3. plugins 部分上方找到 module 键的注释示例,然后取消注释以下行:

    module: {
      rules: [
        { test: /\.(js|ts)x?$/, loader: "ts-loader" },
        { test: /\.css$/, use: ['style-loader','css-loader'] }
      ]
    },
  4. 这些设置使您的程序能够使用 ts-loader 编译器并导入 CSS 文件。

    如果你想添加对 .scss.sass 文件的支持,你应该安装 sass-loader :
    npm install --save react react-dom

    然后在 +webpack.config.js 中的 `+css-loader url 下面添加这个附加规则:

    module: {
      rules: [
        // ...
        {
          test: /\.s[ac]ss$/i,
          use: [
            // Creates `style` nodes from JS strings
            "style-loader",
            // Translates CSS into CommonJS
            "css-loader",
            // Compiles Sass to CSS
            "sass-loader",
          ],
        },
      ]
    },
  5. 保存更改并关闭 webpack.config.js 文件以继续。

  6. 在项目的根目录中创建一个名为 tsconfig.json 的新文件。

  7. 在文本编辑器中打开 tsconfig.json 文件,然后将以下内容复制并粘贴到文件中:

    {
        "compilerOptions": {
          "target": "es2018",        /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
          "lib": ["ES2018", "DOM"],  /* Specify library files to be included in the compilation. */
          "allowJs": true,           /* Allow javascript files to be compiled. */
          "jsx": "react",            /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
        },
        "include": ["src/**/*"],
    }
  8. 保存更改并关闭 tsconfig.json 文件以继续。

为您的项目添加样式表

您现在已准备好创建一个新的级联样式表并将其添加到您的项目中。

添加样式表:

  1. 切换到 src/contacts_assets/assets 目录。

    cd src/contacts_assets/assets/
  2. 在文本编辑器中打开 main.css 文件并删除现有内容。

  3. 为前端定义一些样式属性。

    例如,将以下示例样式复制并粘贴到文件中:

    html {
        background-color: bisque;
    }
    
    body {
        font-family: Arial, Helvetica, sans-serif;
        display: block;
        margin: 10px;
    }
    
    h1 {
        color: darkblue;
        font-size: 32px;
    }
    
    div.new-entry {
        margin: 30px 20px 30px 20px;
    }
    
    .new-entry > div {
        margin-bottom: 15px;
    }
    
    table {
        margin-top: 12px;
        border-top: 1px solid darkblue;
        border-bottom: 1px solid darkblue;
    }
    
    #form {
        margin: 30px 0 30px 20px;
    }
    
    button {
        line-height: 20px;
    }
    
    #lookupName {
        margin-right: 12px;
    }
  4. 保存更改并关闭 +main.css 文件以继续。

  5. 切换到 +src/contacts assets/src 目录。

    cd ../src
  6. 在文本编辑器中打开默认的 index.js 文件并删除现有内容。

  7. 将以下示例代码复制并粘贴到 index.js 文件中:

    import * as React from "react";
    import { render } from "react-dom";
    import { contacts } from "../../declarations/contacts";
    import "../assets/mycontacts.css";
    
    const Contact = () => {
      async function doInsert() {
        let name = document.getElementById("newEntryName").value;
        let add1 = document.getElementById("newEntryAddress1").value;
        let add2 = document.getElementById("newEntryAddress2").value;
        let email = document.getElementById("newEntryEmail").value;
        let phone = document.getElementById("newEntryPhone").value;
        contacts.insert(name, add1, add2, email, parseInt(phone, 10));
      }
    
      async function lookup() {
        let name = document.getElementById("lookupName").value;
        contacts.lookup(name).then((opt_entry) => {
          let entry;
    
          if (opt_entry.length == 0) {
            entry = { name: "", description: "", phone: "" };
          } else {
            entry = opt_entry[0];
          }
    
          document.getElementById("newEntryName").value = entry.name;
          document.getElementById("newEntryAddress1").value = entry.address1;
          document.getElementById("newEntryAddress2").value = entry.address2;
          document.getElementById("newEntryEmail").value = entry.email;
          document.getElementById("newEntryPhone").value = entry.phone.toString();
        });
      }
    
      return (
        <div className="new-entry">
          <h1>My Contacts</h1>
          <div>
            Add or update contact information:
            <form id="contact">
              <table>
                <tbody>
                  <tr>
                    <td>Name:</td>
                    <td>
                      <input id="newEntryName"></input>
                    </td>
                  </tr>
                  <tr>
                    <td>Address 1 (street):</td>
                    <td>
                      <input id="newEntryAddress1"></input>
                    </td>
                  </tr>
                  <tr>
                    <td>Address 2 (city and state):</td>
                    <td>
                      <input id="newEntryAddress2"></input>
                    </td>
                  </tr>
                  <tr>
                    <td>Email:</td>
                    <td>
                      <input id="newEntryEmail"></input>
                    </td>
                  </tr>
                  <tr>
                    <td>Phone:</td>
                    <td>
                      <input id="newEntryPhone" type="number"></input>
                    </td>
                  </tr>
                </tbody>
              </table>
            </form>
          </div>
          <div>
            <button onClick={() => doInsert()}>Add Contact</button>
          </div>
          <div>
            Lookup name:{" "}
            <input id="lookupName" style={{ lineHeight: "20px" }}></input>
            <button onClick={() => lookup()}>Lookup</button>
          </div>
        </div>
      );
    };
    
    document.title = "DFINITY CONTACT EXAMPLE";
    
    render(<Contact />, document.getElementById("contacts"));
  8. 通过运行以下命令将修改后的 index.js 文件重命名为 index.jsx:

    mv index.js index.jsx
  9. 在文本编辑器中打开默认的 src/contacts_assets/src/index.html 文件,然后删除 main.css 链接并使用 <div id="contacts"></div> 更新 `body 内容 `。

    例如:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width" />
        <title>contacts</title>
        <base href="/" />
      </head>
      <body>
        <main>
          <div id="contacts"></div>
        </main>
      </body>
    </html>
  10. 返回项目根目录,如:

cd ../../..

启动本地网络

在构建 contacts 项目之前,您需要连接到本地容器执行环境。

在本地启动环境:

  1. 在本地计算机上打开一个新的终端窗口或选项卡。

  2. 通过运行以下命令在本地计算机上启动本地容器执行环境:

    dfx start --background

    环境完成启动操作后,您可以继续下一步。

注册、构建和部署 dapp

在开发环境中连接到本地容器执行环境后,您可以注册、构建和部署 dapp 以进行测试。

部署 dapp:

  1. 如果需要,请检查您是否仍在项目的根目录中。

  2. 通过运行以下命令注册、构建和部署您的 dapp:

    dfx deploy

    dfx deploy 命令输出显示有关它执行的操作的信息。

    请记住,因为您在本地运行容器执行环境,所以当您运行 dfx deploy 命令时显示的标识符仅在您的计算机上有效。

    要在 Internet Computer platform 上部署容器,您必须使用 --network 命令行选项指定要部署到 Internet Computer 而不是本地环境:

    dfx deploy --network=ic
  3. 启动 Webpack 开发服务器:

    npm start

查看前端

您现在可以访问 contacts dapp 的前端。

查看前端:

  1. 打开浏览器访问“http://localhost:8080”。

  2. 验证是否使用 My Contacts 表单提示您。

    例如:

    Sample front-end

  3. 通过在姓名、地址和电子邮件输入字段中输入文本并在电话输入字段中输入数字,然后单击*添加联系人*,创建一个或多个测试记录。

  4. 清除表单字段并在查找姓名字段中键入联系人姓名,然后单击*查找*以查看存储的联系人信息。

    请记住,您键入的 查找名称 必须与您添加的联系人姓名完全匹配。

修改样式表并测试您的更改

查看联系人 dapp 后,您可能需要进行一些更改。

要更改样式表属性:

在文本编辑器中打开 src/contacts_assets/assets/mycontacts.css 文件并修改其样式设置。

+ 例如,您可能想要更改输入表单的背景颜色或样式。

+ 您应该会在打开的浏览器窗口中立即看到更改更新。

修改前端或后端代码

如果您想进一步探索,您可能需要尝试修改本教程的前端或后端代码。 例如,您可能想尝试修改教程以执行以下操作:

  • 更改前端代码以在添加新联系人后清除输入字段,例如,作为 onClick 事件的一部分。

  • 将 Motoko 程序函数更改为在 Name 字段上进行部分而不是精确的字符串匹配。 (您需要运行 dfx deploy 来测试您在本地环境中所做的更改)

  • 更改 Motoko 程序以允许基于不同字段的查找。

停止本地容器执行环境

完成对程序的试验后,您可以停止本地环境,使其不会继续在后台运行。

停止本地开发环境:

通过运行以下命令停止 Internet Computer 网络:

+

dfx stop