app.js 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. /**
  2. * page/app.js —— 页面层(page):Lit 无构建页面,组合 <quote-calc>(wc)。
  3. *
  4. * 页面层才持有「业务页面状态 + 接口地址 + 布局」。组件库只提供 <quote-calc>。
  5. */
  6. import { LitElement, html, css } from 'lit';
  7. import { quote } from '../core/index.js';
  8. import { createBrowserTransport } from '../wc/browser-transport.js';
  9. import '../wc/index.js'; // 注册 <quote-calc>
  10. export class AppRoot extends LitElement {
  11. static properties = { _log: { state: true } };
  12. static styles = css`
  13. :host { display: block; max-width: 720px; margin: 32px auto; padding: 0 16px; }
  14. h1 { font-size: 20px; }
  15. .demo { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
  16. pre { background: #f7fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 10px; overflow: auto; max-height: 260px; }
  17. .hint { color: #718096; font-size: 12px; }
  18. `;
  19. constructor() {
  20. super();
  21. this._log = [];
  22. this._items = [
  23. { sku: 'FM-PRINT-A3', price: 12.5, qty: 20 },
  24. { sku: 'FM-FRAME-W', price: 88, qty: 2 },
  25. ];
  26. }
  27. firstUpdated() {
  28. // 宿主注入 I/O:换成 createBrowserTransport({ endpoint: '/api/quote' }) 即走真实接口
  29. this._calc = this.renderRoot.querySelector('quote-calc');
  30. // 演示:本地 transport(用 core 算),模拟一次网络往返
  31. this._calc.transport = {
  32. call: async (input) => {
  33. await new Promise((r) => setTimeout(r, 150));
  34. return quote(input.items, { discount: input.discount || 0 });
  35. },
  36. };
  37. }
  38. render() {
  39. return html`
  40. <h1>core → wc → page 示例</h1>
  41. <p class="hint">
  42. core(纯 ESM,Node 可测)提供报价计算;&lt;quote-calc&gt;(Web Component)只做交互;
  43. 本页面组合二者。另开 <code>plain.html</code> 可看到同一组件在纯 HTML(无框架)里运行。
  44. </p>
  45. <div class="demo">
  46. <quote-calc .items=${this._items} discount="0.05"
  47. @quote-done=${(e) => this.#logEvent('quote-done', e.detail)}
  48. @quote-error=${(e) => this.#logEvent('quote-error', e.detail)}>
  49. <span slot="title">Lit 页面里的报价组件</span>
  50. </quote-calc>
  51. <div>
  52. <strong>事件日志</strong>
  53. <pre>${this._log.join('\n') || '(点击「计算报价」后出现)'}</pre>
  54. </div>
  55. </div>
  56. `;
  57. }
  58. #logEvent(name, detail) {
  59. const line = `[${name}] ${JSON.stringify(detail)}`;
  60. this._log = [line, ...this._log].slice(0, 20);
  61. }
  62. }
  63. // 注册幂等:同一页面重复加载不抛 NotSupportedError
  64. if (!customElements.get('app-root')) customElements.define('app-root', AppRoot);