快速开始
要创建项目,请确保已安装 Node.js 16.x 或更高版本,并运行
npm create "@enhance" ./enhance-demo -y
安装完成后,运行以下命令安装依赖,并启动本地开发服务器
cd enhance-demo
npm install
npm start
应用启动后,导航到http://localhost:3333
VSCode 插件
如果安装了 Babel JavaScript 插件需要禁用才能使语法突出显示正常工作
TypeScript 类型定义
添加对应的 TypeScript 类型提示
自定义元素
/**
* @type {import('@enhance/types').EnhanceElemFn}
*/
API
/** @type {import('@enhance/types').EnhanceApiFn} */
HTML head
/** @type {import('@enhance/types').EnhanceHeadFn} */
export default function Head(state) {
//...
}
解决 eslint 的 Parsing error: Unexpected token 错误
缺乏对应的类型声明时编辑器的提示不够友好,存在标红提示,所以需要
安装后不在有标红提示,如果没有生效,需要刷新下窗口才会更新
crtl+shift+p 打开面板然后输入reload window
目录结构
app
├── api ............... data routes
│ └── index.mjs
├── elements .......... custom element pure functions
│ └── my-header.mjs
└── pages ............. file based routing
└── index.html
pages 页面
基于文件的路由
pages
页面文件夹启用基于文件的路由。要添加路由,只需添加一个 HTML 文件。
比如:添加app/pages/about.html
即添加了/about
路由
<main>
this is the "/about" page
</main>
项目路由如下:
:::info
app/pages/index.html → https://yoursite.com/
app/pages/about.html → https://yoursite.com/about
:::
elements 自定义元素
elements
目录下创建可重用的定制元素,相当于添加Web Components
,方便组件复用。
:::info
app/elements/my-message.mjs
<my-message></my-message>
app/elements/my-link
→ <my-link></my-link>
:::
划分目录
:::info
app/elements/blog/comment → <blog-comment></blog-comment>
app/elements/blog/comment-form → <blog-comment-form></blog-comment-form>
:::
在 app
下创建elements
目录,添加basic-layout.msj
/**
* @type {import('@enhance/types').EnhanceElemFn}
*/
export default function BasicLayout({ html, state }) {
const { attrs } = state;
const headTitle = attrs?.headtitle || "Default System Title";
return html`
<div class="basic-layout">
<header class="header-wrap">
<main class="header-content">
${headTitle}
<slot name="headNav"></slot>
</main>
</header>
<main>
<slot name="main"></slot>
</main>
<slot name="footer"></slot>
</div>
<style>
.basic-layout {
width: 100vw;
height: 100vh;
overflow: auto;
background-color: #fff;
}
.header-wrap {
width: 100%;
min-width: 12rem;
margin: 0;
padding: 0;
position: sticky;
top: 0;
background: rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
z-index: 100;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
max-width: 75rem;
min-height: 4rem;
overflow: hidden;
margin: auto;
padding: 0 2rem;
}
::slotted([slot="footer"]) {
background: #f3f3f3;
}
</style>
`;
}
about.html
<basic-layout headTitle="my-enhance-app">
<main slot="main">
<div class="about">
this is the "/about" page
</div>
</main>
</basic-layout>
<style>
.about {
height: 1000px;
}
</style>
html
html是一个纯函数,这意味着给定相同的输入,它们每次都返回相同的输出,最终返回 html 模板字符串。
state
state 下包含 attrs 和 store 两个参数,attrs 包含了在自定义元素上设置的 html 属性
attrs
在自定义元素上设置属性
在自定义元素内可以通过 attrs 获取到
多设置几个属性
打印查看
可以发现 attrs 是一个包含了自定义元素的 html 属性的一个对象。
store
映射到当前页面的 api 数据。
具体示例结合后面的 api 一起展示,需要从 api 中获取数据。
slot 插槽
api 数据接口
api
文件夹预配置为基于文件的路由公开数据。api 文件夹用于向应用添加数据。若要将数据传递到页面,请创建与项目 pages 文件夹中的现有文件同名的文件。
例如:app/api/index.mjs
对应app/pages/index.mjs
页面路由的 REST api
app
├── api ............... data routes
│ └── index.mjs
└── pages ............. file based routing
└── index.html
基本使用
- 创建 app/api/about.mjs 接口,返回数据 ```javascript /* @type {import(‘@enhance/types’).EnhanceApiFn} /
export async function get(req) { console.log(“🚀 ~ file: about.mjs:4 ~ get ~ req”, req); return { json: { message: “欢迎来到 about 页面!”, data: { date: “2022/12/13”, }, }, }; }
2. 创建 app/elements/my-about.mjs 元素展示数据
```javascript
export default function MyAbout({ html, state }) {
console.log("🚀 ~ file: my-about.mjs:2 ~ MyMessage ~ state", state);
const { store } = state;
const { message = "", data = { date: "" } } = store;
return html` <p class="my-message">${message} ${data.date}</p> `;
}
- 将元素
添加到 app/pages/about.html ```javascript
this is the “/about” page
查看页面<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/351630/1670899838524-bf51962e-e944-48a7-88ea-80c6ed522807.png#averageHue=%23fefefe&clientId=u9c9ae987-9441-4&from=paste&height=230&id=u14b473a3&originHeight=230&originWidth=1521&originalType=binary&ratio=1&rotation=0&showTitle=false&size=13384&status=done&style=stroke&taskId=udfea1972-c56b-4e9c-93d3-c083a4be64d&title=&width=1521)
打印数据查看<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/351630/1670899683684-79079589-4872-469b-8e1f-85107195c5aa.png#averageHue=%23292f3d&clientId=u9c9ae987-9441-4&from=paste&height=75&id=u04cef11c&originHeight=75&originWidth=540&originalType=binary&ratio=1&rotation=0&showTitle=false&size=27531&status=done&style=stroke&taskId=u159bafc7-b406-4efd-9138-a6076065e48&title=&width=540)<br />查看 api 的 request <br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/351630/1670899950177-6526c47f-f324-4212-9f84-a5727368ae1f.png#averageHue=%232a2e3c&clientId=u9c9ae987-9441-4&from=paste&height=738&id=u8108ab2e&originHeight=738&originWidth=814&originalType=binary&ratio=1&rotation=0&showTitle=false&size=468514&status=done&style=stroke&taskId=u0cd89344-a0a4-473c-842d-f1663221f4a&title=&width=814)
<a name="v6Z8q"></a>
## public 静态资源
CSS、图像和脚本等静态资产是任何 Web 应用程序的重要组成部分。enhance 提供了一种约定,通过`/_public/`从根公共目录识别和提供资源。
<a name="NUQmM"></a>
### 添加文件
只需将文件拖放到 enhance 项目的公共文件夹中即可。可以使用您想要的任何类型的目录结构进行组织
```javascript
.
├── app/ ............... dynamic app features
└── public ............. static assets
├── blog-comment.mjs
├── docs.css
└── img
└── logo.png
引用文件
基于上述结构,您的应用程序可以包含来自以下路径的资产:/_public/
<script type="module">
import BlogComment from '/_public/blog-comment.mjs'
// ...
</script>
<link rel="stylesheet" href="/_public/docs.css">
<img src="/_public/img/logo.png" />
HTML head 头
head 是应用的一个非常重要的自定义点。您将需要添加自定义标题,网站图标,社交开放图元等内容。
head 不能包含自定义元素。只有一部分现有的预定义 HTML 标签可以包含在 head 中 ,比如 meta、link等。
默认头部组件
enhance 附带了基本的默认头部内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link rel="stylesheet" href="/enhance-styles.css">
<link rel="icon" href="/_public/favicon.svg">
</head>
自定义 head
要提供您自己的自定义头部内容,将 /app/head.mjs
文件添加到您的项目中
- store:映射到当前页面的 API 数据
- req:标准请求对象
- error:如果发生错误,则会显示错误消息,以便您可以向站点的用户发送消息
- status:使您能够正确处理的状态代码 ```javascript import { getLinkTag } from ‘@enhance/arc-plugin-styles/get-styles’
export default function Head(state) {
const { store, status, req, error } = state
const { path } = req
const title = My app — ${path}
return <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${title}</title>
${getLinkTag()}
<link rel="icon" href="/_public/favicon.svg">
</head>
}
添加`head.mjs`前<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/351630/1670901588790-31f25dbc-10f4-4903-b448-de7941293d4a.png#averageHue=%23e8e7e6&clientId=u9c9ae987-9441-4&from=paste&height=95&id=ymdGu&originHeight=95&originWidth=290&originalType=binary&ratio=1&rotation=0&showTitle=false&size=5584&status=done&style=stroke&taskId=ubfa4a4b2-c05e-4682-93d8-bbeff27e460&title=&width=290)<br />添加后<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/351630/1670901710407-715a1f94-0943-4e98-9da9-d5e3c2935b06.png#averageHue=%23ebeae9&clientId=u9c9ae987-9441-4&from=paste&height=85&id=u8a95c85c&originHeight=85&originWidth=292&originalType=binary&ratio=1&rotation=0&showTitle=false&size=5864&status=done&style=stroke&taskId=udf5194ab-d169-4857-94e5-921c8b68914&title=&width=292)
<a name="Hzsl9"></a>
### templates 非自定义元素模板
可以为预定义的 HTML 标记定义模板,添加`/app/templates/twitter-meta.mjs`如下所示:
```javascript
export default function TwitterMeta(state) {
const { title, description, image, card } = state
return `
<meta name="twitter:title" content="${title}">
<meta name="twitter:description" content="${description}">
<meta name="twitter:image" content="${image}">
<meta name="twitter:card" content="${card}">
`
}
在head.mjs
中使用此元内容模板:
import { getLinkTag } from "@enhance/arc-plugin-styles/get-styles";
import TwitterMeta from "./templates/twitter-meta.mjs";
/** @type {import('@enhance/types').EnhanceHeadFn} */
export default function Head(state) {
const { store, status, req, error } = state;
const { path } = req;
const title = `My app — ${path}`;
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
${TwitterMeta(store)}
<title>${title}</title>
${getLinkTag()}
<link rel="icon" href="/_public/favicon.svg">
</head>
`;
}
404 和 500 错误页
在pages
添加 404.html
或404.mjs
;500.html
或500.mjs/
app/pages/404.mjs
export default function FourOhFour({ html, state }) {
console.log("🚀 ~ file: 404.mjs:2 ~ FourOhFour ~ state", state);
const { error } = state.attrs;
return html`
<main>
<h1>Not Found - 404</h1>
<h2>Sorry we can't find that.</h2>
<p>${error && error}</p>
</main>
`;
}
style 样式
默认情况下,样式的范围限定为自定义元素,可以添加