时间:2023-06-06 23:12:02 | 来源:网站运营
时间:2023-06-06 23:12:02 来源:网站运营
简化版的 vue 页面模板语法:简化的目的:SomeComponent.tm
<html> <body> <div :title="myTitle" /> </body></html>
SomeComponent.ts
import * as Biz from '@triones/biz-kernel';export class SomeComponent extends Biz.MarkupView { public readonly myProp1: string; public readonly myProp2?: string; public get myTitle() { return '..some title...' + this.myProp1; }}
当调用 SomeComponent 组件的时候,会创建对应的 SomeComponent.ts 这个类的实例。然后渲染页面的时候,会用 SomeComponent.tm 来渲染。通过 :title 这样的属性来绑定“展现”和“逻辑”,渲染的时候 get myTitle() 这个 getter 属性会被求值。<SomeComponent myProp1="hello" />
这个时候,从 public readonly myProp1: string 上就可以取到传入的 myProp1 属性。没有传的 myProp2 属性就是 undefined。SomeComponent.tm
<html> <body> <button @onClick="sayHello">hello</button> </body></html>
SomeComponent.ts
import * as Biz from '@triones/biz-kernel';export class SomeComponent extends Biz.MarkupView { public sayHello() { // ... }}
和 vue 类似的是都是用 : 和 @ 来表达属性绑定和事件处理。和 vue 不同的是,在绑定的地方只能写属性名字引用对应的属性,不能写复杂的表达式。和微信的 wxml 语法类似,bind:tap 这样的事件绑定的地方,也是只能写一个 event handler 的方法名,不能写表达式。<template #default> <Header /> <Body /> <Footer /></template<template #Header> ...</template><template #Body> ...</template><template #Footer> ...</template>
这么写就省得建立 4 个组件了,合并写到一个组件里。如果没有写 <template #default>,那默认就是包裹在 <template #default> 里的。从语法上来说,也非常类似微信小程序的 wxml 的写法。只是微信小程序的 wxml 没有 <template #default>,而是直接写在了文件的顶层。<div>hello</div>
和这么写<template #default> <div>hello</div></template>
是等价的<LineChart width={500} height={300} data={data}> <XAxis dataKey="name"/> <YAxis/> <CartesianGrid stroke="#eee" strokeDasharray="5 5"/></LineChart>
如果是 react 组件,往往会用 React.Children 来遍历这些子节点,从中提取数据做为参数来使用。也就是给一个组件传递 children,有的时候传的是组件,有的时候传的是渲染组件的函数,有的时候传递过去被当成 array/object 使用。这也是 jsx 语法从一开始没有设计好的地方。<LineChart XAxis="{ dataKey: "name" }" YAxis CartesianGrid="{ stroke: "#eee", strokeDasharray="5 5" } />
书写体验会非常难受,这一行 LineChart 组件的调用也会非常的长。把这些属性折行之后写成 children,就可以更结构化地进行书写。<LineChart :wdith="500" :height="300" :data="data"> <attr #XAxis dataKey="name"/> <attr #YAxis>true</attr> <attr #CartesianGrid stroke="#eee" strokeDasharray="5 5"/></LineChart>
用 #xxx 的方式来表达,我是给组件传递了 xxx 属性。这样做为数据使用的 children,和做为组件使用的 children 就被区分开了。定义组件
<div class="container"> <header> <slot :render="header" /> </header> <main> <slot :render="children" /> </main> <footer> <slot :render="footer" /> </footer></div>
通过 <slot> 来表达,这个地方可以用户自定义。使用组件
<BaseLayout> <fragment #header> <h1>Here might be a page title</h1> </fragment> <fragment #children> <p>A paragraph for the main content.</p> <p>And another one.</p> </fragment> <fragment #footer> <p>Here's some contact info</p> </fragment></BaseLayout>
这里用 <fragment> 来表达,传入的是一个具体的实例,而不是可以被多次调用的参数。如果是 React,那么类型就是 ReactNode。定义组件
<div class="container"> <header> <slot :render="header" title="abc" /> </header> <footer> <slot :render="footer" title="xyz" /> </footer></div>
<slot> 渲染的额时候,额外提供了参数使用组件
<BaseLayout> <template #header> <h1>Here might be a page title: {{ #header.title }}</h1> </template> <template #footer> <p>Here's some contact info: {{ #footer.title }}</p> </template></BaseLayout>
传入 template 和 fragment 不同,template 会捕获参数,从而可以在 template 内容里引用。template 比 fragment 更常用,所以有一种简写形式:使用组件
<BaseLayout> <h1 #header>Here might be a page title: {{ #header.title }}</h1> <p #footer>Here's some contact info: {{ #footer.title }}</p></BaseLayout>
综上 #xxx 是一种传递各种复杂属性的写法。相比 jsx 的语法,折行书写更舒服。<import from="@vant/weapp/tag/index" as="VantTag"/><template #default> <view> <VantTag /> </view></template>
这里引用的 @vant/weapp 是外部第三方组件,通过 import 就可以直接被使用。import 后的组件可以当作“虚拟节点”传递出去使用。这个是微信小程序特有的概念:<import from="@app/MyComps/MyHeader" /><import from="@app/MyComps/MyFooter" /><template #default> <BaseLayout :header="<MyHeader/>" :footer="<MyFooter/>" /></template>
BaseLayout 要声明自己接受这么两个抽象节点,所以要和普通的 slot 区分开来<div class="container"> <header> <slot :component="header" title="abc" /> </header> <footer> <slot :component="footer" title="xyz" /> </footer></div>
区别就是 <slot :component ..> 代替了 <slot :render ...>。定义组件
<div class="container"> <main> <slot :render="children" /> </main></div>
使用组件
<BaseLayout> <p>A paragraph for the main content.</p> <p>And another one.</p></BaseLayout>
这个实际上等价于使用组件
<BaseLayout> <fragment #children> <p>A paragraph for the main content.</p> <p>And another one.</p> </fragment></BaseLayout>
也就是普通写法下的子组件,其实是一个 fragment 类型的 slot。<dynamic :visible="vip"> <p>you are vip</p></dynamic>
分支<dynamic :slot="userType"> <fragment #vip><p>you are vip</p></fragment> <fragment #normal><p>you are normal</p></fragment></dynamic>
循环<template #default> <ul> <dynamic :expand="items" key="id"><MyItem #element></dynamic> </ul></template><template #MyItem> <span>{{ #MyItem.firstName }}</span><span>{{ #MyItem.lastName }}</template>
关键词:模板,语法,简化