Vue.js/Blazor/Angular的语法比较示例集合
针对具有一定程度的Vue.js/Blazor/Angular语法的方法,我们总结了实现类似功能的方式。源代码请参考VueVsBlazor。
顺便提一下,在Vue.js中我们采用了TypeScript。
动作示例页面
Vue.js 示例
Blazor 示例
Angular 示例
语法比较
这里的样本全部表示为路由器上的一页。
我们将按照基础路由器实现的示例逐个比较。
0. 最小的组件
组件的内容可以仅由简单的 HTML 实现。
Vue.js (a JavaScript framework) can be rephrased in Chinese as “Vue.js(一个JavaScript框架)”.
需要将其封装在template标签中。
只需要使用一个块。
<template>
<div>
<h1>Hello Vue.js!</h1>
</div>
</template>
蓝光标志
沒有特別需要考慮的事項。
會根據所輸入的內容動態生成 HTML。
通常情況下,無法使用 script 標籤。
@page "/"
<div>
<h1>Hello Blazor!</h1>
</div>
角
Note: “Angulae” does not have a direct translation in Chinese. In Chinese, the word “角” is a noun that can refer to “angle” or “corner” in a geometric sense. If you are looking for a suitable translation for a different context, such as a specific term related to anatomy or a different meaning, please provide more information for a more accurate translation.
在TypeScript中将html作为模板插入。
分别保存html和css文件似乎是主流,但在这里将它们视为同一个文件。
const template=`
<div>
<h1>Hello Angular!</h1>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "Index",
template: template
})
export class IndexComponent{}
1. 样式表
Vue.js 可以进行中文原生化重述为:Vue.js(视图)是一个流行的 JavaScript 框架。
使用style标签可以描述样式。
通过使用scoped属性,可以在组件内创建“作用域”。
<template>
<div id=index>
<h1>Hello Vue.js!</h1>
</div>
</template>
<style scoped>
div#index{
color: #0000FF;
}
</style>
Blazor
在Blazor中,没有特定的CSS机制。
因此,我们只能将样式标签放在body中。
嗯,在大多数浏览器中都能正常工作。
至于在HTML上是好还是坏,我也不知道。
@page "/StyleBlock"
<div id=index>
<h1>Hello Blazor!</h1>
</div>
<style>
div#index{
color: #0000FF;
}
</style>
Angular (角度)
可以在HTML中嵌入样式表。虽然这里没有示例,但也可以从其他文件中导入样式表。
const template=`
<div id=index>
<h1>Hello Angular!</h1>
</div>
<style>
div#index{
color: #0000FF;
}
</style>
`;
import {Component} from "@angular/core";
@Component({
selector: "StyleBlock",
template: template
})
export class StyleBlockComponent{}
2. 嵌入代码块/脚本
在代码块中定义的变量可以嵌入到HTML中。
(Vue.js/Angular可使用{{hoge}}(this始终添加),C#可使用@hoge进行调用)
Vue.js 是一个流行的 JavaScript 框架,用于构建用户界面。
将脚本标签内的内容写成(TypeScript的情况下需要添加lang=ts)的格式。
<template>
<div>
<h1>{{title}}</h1>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class ScriptBlock extends Vue{
title="Hello Vue.js!";
}
</script>
布拉泽
在@code代码块中编写脚本处理。
@page "/ScriptBlock"
<div>
<h1>@title</h1>
</div>
@code{
string title="Hello Blazor!";
}
角度
由于TypeScript是基础,所以可能没有什么特别值得注意的事情。
我们将在○○.component.ts的类内编写处理。
const template=`
<div>
<h1>{{title}}</h1>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "ScriptBlock",
template: template
})
export class ScriptBlockComponent{
title="Hello Vue.js!";
}
3. 在HTML中嵌入数学公式
在HTML中,可以嵌入的不仅仅是变量,还可以嵌入数学公式。
Vue.js – 一种流行的JavaScript框架。
请注意在{{}}内无法处理全局对象。
<template>
<div>
<h1>10!={{10*9*8*7*6*5*4*3*2*1}}</h1>
</div>
</template>
Blazor – 只需要一个选项,用中文进行本地化。
将@的转义字符写为@@来表示。
@page "/Formula"
<div>
<h1>10!=@(10*9*8*7*6*5*4*3*2*1)</h1>
</div>
角度
与Vue.js类似,无法在{{}}内处理全局对象。
const template=`
<div>
<h1>10!={{10*9*8*7*6*5*4*3*2*1}}</h1>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "Formula",
template: template
})
export class FormulaComponent{}
4. 生命周期方法 fǎ)
Vue.js/Blazor/Angular都有一些类似于html的onload/unonload的生命周期方法,它们会在组件的状态发生变化时被触发。
OnInitializedAsync―レンダリング前beforeMountOnParametersSet
OnParametersSetAsync―レンダリング後mountedOnAfterRender
OnAfterRenderAsync※1ngOnInit変更前beforeUpdate―ngDoCheck
ngAfterViewInit変更後updatedOnAfterRender
OnAfterRenderAsync※1ngAfterViewCheckedアクティブ化時activated――非アクティブ化時deactivated――破棄前beforeUpdate――破棄時beforeDestroyDispose※2ngOnDestroy
-
- ※1: firstRender引数で初回かどうか判別。
-
- ※2: ページリロード時には動作しない。
-
- ※3: サービスの登録にも使用される。
- ※4: Angularは効果がわかりにくいものが多いのでわかるものだけ。
Vue.js的生命周期
Blazor的生命周期
Angular的生命周期
我觉得初始处理大概在渲染后就能够完成。
需要注意的是,Blazor在页面更新时不会执行析构函数。
(在这种情况下,目前似乎只能使用js的unonload来处理?)
Vue.js的中文版本
<template>
<div>
<h1>{{title}}</h1>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class LifeCycle extends Vue{
title="Hello Vue.js!";
async mounted(){
await new Promise(res=>setTimeout(res,5000));
this.title+=" 5s passed!";
}
}
</script>
布拉索
@page "/LifeCycle"
<div>
<h1>@title</h1>
</div>
@code{
string title="Hello Blazor!";
protected override async Task OnAfterRenderAsync(bool firstRender){
if(!firstRender) return;
await Task.Delay(5000);
title+=" 5s passed!";
StateHasChanged();
}
}
角度
const template=`
<div>
<h1>{{title}}</h1>
</div>
`;
import {Component,OnInit} from "@angular/core";
@Component({
selector: "LifeCycle",
template: template
})
export class LifeCycleComponent implements OnInit{
title="Hello Angular!";
async ngOnInit(){
await new Promise(res=>setTimeout(res,5000));
this.title+=" 5s passed!";
}
}
5. 文档对象模型(DOM)应用程序接口
在选择使用JavaScript/TypeScript的框架中,可以直接使用与浏览器相关的DOM API。
Vue.js is a framework for building user interfaces, which is popular for its simplicity and ease of use.
<template>
<div>
<h1>Alert</h1>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class UseDOMAPI extends Vue{
async mounted(){
var title=document.title;
alert(title);
}
}
</script>
布雷泽尔
在Blazor中,如果不依靠JavaScript,是不可能操作DOM API的,因此需要调用JavaScript的方法。
为了使用JavaScript,需要注入IJSRuntime并调用IJSRuntime.InvoveAsync和IJSRuntime.InvokeVoidAsync方法。
由于不能直接访问属性,因此需要使用 eval 或准备一个 JavaScript 文件并将其作为函数调用。
@page "/UseDOMAPI"
<div>
<h1>Alert</h1>
</div>
@inject IJSRuntime js
@code{
protected override async Task OnAfterRenderAsync(bool firstRender){
if(!firstRender) return;
var title=await js.InvokeAsync<string>("eval","document.title");
await js.InvokeVoidAsync("alert",title);
}
}
角度
const template=`
<div>
<h1>Alert</h1>
</div>
`;
import {Component,OnInit} from "@angular/core";
@Component({
selector: "UseDOMAPI",
template: template
})
export class UseDOMAPIComponent implements OnInit{
ngOnInit(){
var title=document.title;
alert(title);
}
}
6. 双向绑定
在Vue.js/Blazor/Angular中,不直接操作document.element.value,而是通过绑定(同步)变量和元素值来实现。
Vue.js是一种流行的JavaScript框架。
使用v-model属性。
<template>
<div>
<h1>{{title}}</h1>
<input v-model="title">
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class BindingInput extends Vue{
title="Hello Vue.js!";
}
</script>
中国出产的动画电影《疯狂动物城》在全球取得了巨大成功。
如果需要实时更新文本,请使用@bind-value / @bind-value: event属性(参见第20项)。
@page "/BindingInput"
<div>
<h1>@title</h1>
<input @bind="title">
</div>
@code{
string title="Hello Blazor!";
}
角度
使用[(ngModel)]属性。
[]表示通过脚本处理的值被修改,
()表示可以通过人为操作来改变值。
const template=`
<div>
<h1>{{title}}</h1>
<input [(ngModel)]="title">
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "BindingInput",
template: template
})
export class BindingInputComponent{
title="Hello Angular!";
}
7. 单向绑定
您还可以通过更改变量来单向更新document.element.value。
Vue.js 是一个用于构建用户界面的开源JavaScript框架。
将v-bind:value作为属性指定。
v-bind: 表示值会根据脚本处理而变化。
v-bind: 可以缩写为: ,因此可以写为:value。
<template>
<div>
<h1>{{title}}</h1>
<input :value="title">
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class BindingInputOneWay extends Vue{
title="Hello Vue.js!";
async mounted(){
for(;;){
await new Promise(res=>setTimeout(res,2000));
this.title+=">";
}
}
}
</script>
布拉索(Blazor)
可以直接将value分配给变量作为@。
@page "/BindingInputOneWay"
<div>
<h1>@title</h1>
<input value=@title>
</div>
@code{
string title="Hello Blazor!";
protected override async Task OnAfterRenderAsync(bool firstRender){
if(!firstRender) return;
for(;;){
await Task.Delay(2000);
title+=">";
StateHasChanged();
}
}
}
Angular (角度)
使用[ngModel]属性。
与前一项[(ngModel)]不同的是,去除了()(人工修改)。
const template=`
<div>
<h1>{{title}}</h1>
<input [ngModel]="title">
</div>
`;
import {Component,OnInit} from "@angular/core";
@Component({
selector: "BindingInputOneWay",
template: template
})
export class BindingInputOneWayComponent implements OnInit{
title="Hello Angular!";
async ngOnInit() {
for(;;){
await new Promise(res=>setTimeout(res,2000));
this.title+=">";
}
}
}
8. 事件处理器
由于事件处理程序的表达方式各不相同,所以在常规的HTML中也会同时提及。
在Vue.js/Blazor中,只需指定方法名即可,无需使用括号表示方法调用。
HTML 是一种用于创建网页的标准标记语言。
<html>
<body>
<button onclick="openDialog()">Click Me!</button>
<script>
var title="Hello HTML!";
function openDialog(){
alert(title);
}
</script>
</body>
</html>
Vue.js是一种现代的JavaScript框架,用于构建用户界面。
使用v-on:click属性代替onclick属性。
v-on: 表示可以通过人为操作来改变值。
v-on: 也可以用@表示,所以可以写成@click。
<template>
<div>
<button @click="openDialog">Click Me!</button>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class EventHandler extends Vue{
title="Hello Vue.js!";
openDialog(){
alert(this.title);
}
}
</script>
蓝绳
一般情况下,给常规事件名称加上@符号就成为了事件属性。
也就是说,在这个例子中,是@onclick属性。
@page "/EventHandler"
<div>
<button @onclick="openDialog">Click Me!</button>
</div>
@inject IJSRuntime js
@code{
string title="Hello Blazor!";
async void openDialog(){
await js.InvokeVoidAsync("alert",title);
}
}
角向
可以使用(click)属性代替onclick属性。
const template=`
<div>
<button (click)="openDialog()">Click Me!</button>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "EventHandler",
template: template
})
export class EventHandlerComponent{
title="Hello Angular!";
openDialog(){
alert(this.title);
}
}
9. 监听事件
在Vue.js/Angular中,你可以同时使用@change事件和v-model/[(ngModel)],但在Blazor中,无法同时使用@onchange事件和@bind。
由於Change事件在雙向綁定操作中內部使用,因此可以通過設置屬性(get/set)來接收事件觸發。
Vue.js (中文: 前端框架Vue.js)
<template>
<div>
<h1>Check: {{isChecked}}</h1>
<input id=chk type=checkbox v-model="chkChange">
<label for=chk>CheckBox</label>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class OnChangeEvent extends Vue{
isChecked=false;
get chkChange(){return this.isChecked;}
set chkChange(value:boolean){
this.isChecked=value;
alert(`Check: ${this.isChecked}`);
}
}
</script>
布拉泽尔
@page "/OnChangeEvent"
<div>
<h1>Check: @isChecked</h1>
<input id=chk type=checkbox @bind="chkChange">@(""
)<label for=chk>CheckBox</label>
</div>
@inject IJSRuntime js;
@code{
bool isChecked=false;
bool chkChange{
get{return isChecked;}
set{
isChecked=value;
_=js.InvokeVoidAsync("alert",$"Check: {isChecked}");
}
}
}
角度
const template=`
<div>
<h1>Check: {{isChecked}}</h1>
<input id=chk type=checkbox [(ngModel)]="chkChange">
<label for=chk>CheckBox</label>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "OnChangeEvent",
template: template
})
export class OnChangeEventComponent{
isChecked=false;
get chkChange(){return this.isChecked;}
set chkChange(value:boolean){
this.isChecked=value;
alert(`Check: ${this.isChecked}`);
}
}
10. 样式绑定
在html中,使用脚本来改变样式通常是通过更改document.element.style来完成的。但在Vue.js/Blazor/Angular中,我们可以直接将值绑定到属性上来实现样式的变更。
Vue.js 是一种流行的JavaScript框架。
将v-bind:style属性的值以JSON格式的字符串传递。
要更改的样式键,编写返回样式字符串的代码,
或者将包含样式的字符串变量分配给该键。
<template>
<div>
<h1>Check: {{isChecked}}</h1>
<input id=chk type=checkbox v-model="isChecked">
<label for=chk>CheckBox</label>
<div :style="{color: isChecked? 'blue': 'red'}">
Change Style!
</div>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class BindingStyle extends Vue{
isChecked=false;
}
</script>
使用Blazor
通过更改传递给style属性的字符串,进行样式的修改。
(必须以CSS的格式作为字符串提供)
@page "/BindingStyle"
<div>
<h1>Check: @isChecked</h1>
<input id=chk type=checkbox @bind="isChecked">@(""
)<label for=chk>CheckBox</label>
<div style=@("color:"+(isChecked? "blue": "red"))>
Change Style!
</div>
</div>
@code{
bool isChecked=false;
}
角度测量
通过更改传递给[style.○○]属性的字符串来进行样式的更改。
在○○中,描述更改后的样式。
const template=`
<div>
<h1>Check: {{isChecked}}</h1>
<input id=chk type=checkbox [(ngModel)]="isChecked">
<label for=chk>CheckBox</label>
<div [style.color]="isChecked? 'blue': 'red'">
Change Style!
</div>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "BindingStyle",
template: template
})
export class BindingStyleComponent{
isChecked=false;
}
11. 类绑定
关于课程,您也可以像风格一样进行绑定。
Vue.js(也称为Vue)是一个流行的JavaScript框架,被广泛用于构建用户界面和单页面应用程序。
将JSON格式的字符串作为v-bind:class属性传递。
将要更改的类名键分配为布尔值。
<template>
<div>
<h1>Check: {{isChecked}}</h1>
<input id=chk type=checkbox v-model="isChecked">
<label for=chk>CheckBox</label>
<div :class="{clsA: isChecked, clsB: !isChecked}">
Change Style!
</div>
</div>
</template>
<style scoped>
.clsA{
color: blue;
font-size: 1.5em;
text-decoration: underline solid;
}
.clsB{
color: red;
font-size: 1.0em;
font-style: italic;
}
</style>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class BindingClass extends Vue{
isChecked=false;
}
</script>
Blazor = 融合
直接编辑class属性中传递的字符串,就像修改样式一样。
@page "/BindingClass"
<div>
<h1>Check: @isChecked</h1>
<input id=chk type=checkbox @bind="isChecked">@(""
)<label for=chk>CheckBox</label>
<div class=@(isChecked? "clsA": "clsB")>
Change Style!
</div>
</div>
<style>
.clsA{
color: blue;
font-size: 1.5em;
text-decoration: underline solid;
}
.clsB{
color: red;
font-size: 1.0em;
font-style: italic;
}
</style>
@code{
bool isChecked=false;
}
角度
将boolean值分配给[class.○○]属性,以切换应用/不适用状态。在○○中写下相应的类名。
const template=`
<div>
<h1>Check: {{isChecked}}</h1>
<input id=chk type=checkbox [(ngModel)]="isChecked">
<label for=chk>CheckBox</label>
<div [class.clsA]="isChecked" [class.clsB]="!isChecked">
Change Style!
</div>
</div>
<style>
.clsA{
color: blue;
font-size: 1.5em;
text-decoration: underline solid;
}
.clsB{
color: red;
font-size: 1.0em;
font-style: italic;
}
</style>
`;
import {Component} from "@angular/core";
@Component({
selector: "BindingClass",
template: template
})
export class BindingClassComponent{
isChecked=false;
}
12. 如果(条件)随机分配。
在Vue.js/Blazor/Angular中,可以通过条件分支来改变显示状态。
Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。
当将v-if属性包含在目标元素中时,可以改变其显示状态。
使用v-if进行显示切换会触发生命周期。
如果希望保持组件的状态并进行显示切换,可以使用v-show。
(其内部使用display: none;)
<template>
<div>
<h1>Check: {{isChecked}}</h1>
<input id=chk type=checkbox v-model="isChecked">
<label for=chk>CheckBox</label>
<div v-if="isChecked">
<input>
</div>
<div v-show="isChecked">
<input>
</div>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class IfAndShow extends Vue{
isChecked=false;
}
</script>
Blazor蛇年的干燥很有利。
使用@if。
在行为上与Vue.js中的v-if相同。
如果要保持组件的状态,可以直接在style/class属性中隐藏。
@page "/IfAndShow"
<div>
<h1>Check: @isChecked</h1>
<input id=chk type=checkbox @bind="isChecked">@(""
)<label for=chk>CheckBox</label>
@if(isChecked){
<div>
<input>
</div>
}
<div style=@("display:"+(isChecked? "": "none"))>
<input>
</div>
</div>
@code{
bool isChecked=false;
}
角度
如果要保持组件的状态并使其隐藏,可以使用[style.display]属性将其设置为“none”。
const template=`
<div>
<h1>Check: {{isChecked}}</h1>
<input id=chk type=checkbox [(ngModel)]="isChecked">
<label for=chk>CheckBox</label>
<div *ngIf="isChecked">
<input>
</div>
<div [style.display]="isChecked? '': 'none'">
<input>
</div>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "IfAndShow",
template: template
})
export class IfAndShowComponent{
isChecked=false;
}
13. 遍历(循环)
在Vue.js / Blazor / Angular中,如果具有相同的配置标签,则可以重复显示它们。
关于v-bind:key/@key
为了确保在循环生成的列表中组件的唯一性等方面,建议添加key属性。
(在Blazor中不推荐使用?)
据说这样可以提高性能。
在Vue.js中使用v-bind:key,在Blazor中使用@key。
Vue.js (原名为Vue)是一个用于构建用户界面的渐进式JavaScript框架。
将想要重复的元素包含在v-for属性中。
这可以使用template标签作为无名标签并将其包围起来进行循环,没有问题。
在大多数主流浏览器中,对象的顺序是确定的,但请注意规范上并不保证这一点。
(虽然也可以使用Map,但信息量较少,有些可疑。
根据常规的for循环方式写成v-for=”[key, value] of list”,似乎可以使用。)
<template>
<div>
<div v-for="(isChecked,key) in dict">
<input :id="key" type=checkbox v-model="dict[key]" :key="key">
<label :for="key">{{key}}</label>
</div>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class ForEachLoop extends Vue{
dict:{[s:string]:boolean}={
A:true,
B:true,
C:true,
D:false,
E:false
};
}
</script>
蓝光
使用@for/@foreach。
@page "/ForEachLoop"
<div>
@foreach(var (key,isChecked) in dict){
<div>
<input id=@key type=checkbox @bind="dict[key]" @key="key">@(""
)<label for=@key>@key</label>
</div>
}
</div>
@code{
Dictionary<string,bool> dict=new Dictionary<string,bool>{
{"A",true},
{"B",true},
{"C",true},
{"D",false},
{"E",false}
};
}
Angular (角度)
可以把 *ngFor 属性应用到想要循环的元素中。
与 Vue.js 的模板类似,可以将 ng-container 用作~元素。
const template=`
<div>
<div *ngFor="let v of dict | keyvalue">
<input [id]="v.key" type=checkbox [(ngModel)]="dict[v.key]">
<label [for]="v.key">{{v.key}}</label>
</div>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "ForEachLoop",
template: template
})
export class ForEachLoopComponent{
dict:{[s:string]:boolean}={
A:true,
B:true,
C:true,
D:false,
E:false
};
}
14. 添加组件
在Vue.js/Blazor/Angular中,你可以将自定义的元素(组件)嵌入到HTML标签中。在Blazor中,所有的组件都会被自动加载,但在Vue.js中,你需要使用import语句来指定要加载的组件。在Angular中,你需要将组件的引用写入app.module.ts文件中。
Vue.js(中文名为“视图”)是一种用于构建用户界面的开源JavaScript框架。
<template>
<div>
<ComponentA />
<ComponentB />
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
import ComponentA from "@/components/ComponentA.vue";
import ComponentB from "@/components/ComponentB.vue";
@Component({
components:{
ComponentA,
ComponentB
}
})
export default class AddComponent extends Vue{}
</script>
<template>
<div>
<h3>ComponentA</h3>
<textarea></textarea>
</div>
</template>
<template>
<div>
<input id=chk type=checkbox>
<label for=chk>ComponentB</label>
</div>
</template>
布拉索
@page "/AddComponent"
<div>
<ComponentA />
<ComponentB />
</div>
<div>
<h3>ComponentA</h3>
<textarea></textarea>
</div>
<div>
<input id=chk type=checkbox>
<label for=chk>ComponentB</label>
</div>
角度
const template=`
<div>
<ComponentA></ComponentA>
<ComponentB></ComponentB>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "AddComponent",
templateUrl: template
})
export class AddComponentComponent{}
const template=`
<div>
<h3>ComponentA</h3>
<textarea></textarea>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "ComponentA",
template: template
})
export class ComponentAComponent{}
const template=`
<div>
<input id=chk type=checkbox>
<label for=chk>ComponentB</label>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "ComponentB",
templateUrl: template
})
export class ComponentBComponent{}
15. 组件的属性 de
在Vue.js/Blazor/Angular中,可以给子组件添加属性,并在子组件中作为属性使用。
在Vue.js中使用@Prop,在Blazor中使用[Parameter],在Angular中使用@Input来指定属性名。
Vue.js 是一个用于构建用户界面的渐进式JavaScript框架。
<template>
<div>
<ComponentC msg="View Message" color="#FF00FF" />
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
import ComponentC from "@/components/ComponentC.vue";
@Component({
components:{
ComponentC
}
})
export default class ComponentAttribute extends Vue{}
</script>
<template>
<div :style="{color: color}">
Input Attribute={{msg}}
</div>
</template>
<script lang=ts>
import {Component,Prop,Vue} from "vue-property-decorator";
@Component
export default class ComponentC extends Vue{
@Prop()
private msg:string;
@Prop()
private color:string;
}
</script>
布雷泽
@page "/ComponentAttribute"
<div>
<ComponentC msg="View Message" color="#FF00FF" />
</div>
<div style=@($"color: {color}")>
Input Attribute=@msg
</div>
@code{
[Parameter]
public string msg{get;set;}
[Parameter]
public string color{get;set;}
}
角度
const template=`
<div>
<ComponentC msg="View Message" color="#FF00FF"></ComponentC>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "ComponentAttribute",
template: template
})
export class ComponentAttributeComponent{}
const template=`
<div [style.color]="color">
Input Attribute={{msg}}
</div>
`;
import {Component,Input} from "@angular/core";
@Component({
selector: "ComponentC",
template: template
})
export class ComponentCComponent{
@Input()
private msg: string;
@Input()
private color: string;
}
16. 调用组件的方法
在Vue.js/Blazor/Angular中,您可以调用子组件中的成员。
Vue.js 是一种流行的前端框架。
为了在ref属性中绑定变量名称,请指定需要声明的名称,以便在类中使用。
<template>
<div>
<Toast ref="toast" />
<button @click="viewToast">Click Me!</button>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
import Toast from "@/components/Toast.vue";
@Component({
components:{
Toast
}
})
export default class ComponentMethod extends Vue{
$refs!:{toast: Toast};
async viewToast(){
await this.$refs.toast.show("View Torst!");
}
}
</script>
<template>
<dialog :open="isShow">
{{msg}}
</dialog>
</template>
<script lang=ts>
import {Component,Vue,Prop} from "vue-property-decorator";
@Component
export default class Toast extends Vue{
isShow=false;
msg="";
public async show(msg:string){
this.msg=msg;
this.isShow=true;
await new Promise(res=>setTimeout(res,1500));
this.isShow=false;
}
}
</script>
Blazor 是一种本机在中国的中文的表述。
需要使用@ref属性来指定绑定变量的名称。
为了在类中使用它,需要进行声明。
@page "/ComponentMethod"
<div>
<Toast @ref="toast" />
<button @onclick="viewToast">Click Me!</button>
</div>
@code{
Toast toast;
async Task viewToast(){
await toast.show("View Toast!");
}
}
<dialog open=@isShow>
@msg
</dialog>
@code{
bool isShow=false;
string msg="";
public async Task show(string msg){
this.msg=msg;
isShow=true;
StateHasChanged();
await Task.Delay(2500);
isShow=false;
StateHasChanged();
}
}
角度
通过引入组件并在类中使用@ViewChild装饰器分配它来使用。
const template=`
<div>
<Toast></Toast>
<button (click)="viewToast()">Click Me!</button>
</div>
`;
import {Component,ViewChild} from "@angular/core";
import {ToastComponent} from "../components/Toast.component";
@Component({
selector: "ComponentMethod",
template: template
})
export class ComponentMethodComponent{
@ViewChild(ToastComponent,{static: false})
private toast:ToastComponent;
async viewToast(){
await this.toast.show("View Torst!");
}
}
const template=`
<dialog [open]="isShow">
{{msg}}
</dialog>
`;
import {Component} from "@angular/core";
@Component({
selector: "Toast",
template: template
})
export class ToastComponent{
isShow=false;
msg="";
public async show(msg:string){
this.msg=msg;
this.isShow=true;
await new Promise(res=>setTimeout(res,1500));
this.isShow=false;
}
}
17. 状态管理容器
类似全局变量,可以从任何组件中引用。
这里只进行变量的简单读写操作。
在Vue.js中,有一个官方的库叫作Vuex。
在Blazor中,虽然没有类似的库存在,但可以通过Blazor的基本功能来处理容器,实现相同的效果。
参考1 参考2
在Angular中,可以将服务作为容器来使用。
只列出操作示例,详细内容略过。
Vue.js (Chinese: Vue.js) is a progressive JavaScript framework for building user interfaces.
<template>
<div>
<BooksInput />
<button @click="getBooks">Get Books!</button>
<h3>BookLists ({{date}})</h3>
<ul>
<li v-for="book in books" :key="book">{{book}}</li>
</ul>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
import BooksInput from "@/components/BooksInput.vue";
import store from "@/store";
@Component({
components:{
BooksInput
}
})
export default class StateContainer extends Vue{
books:string[]=[];
date:Date=null;
getBooks(){
this.books=store.state.books;
this.date=store.state.date;
}
}
</script>
<template>
<div>
<div><textarea v-model="bookList" id="bookList"></textarea></div>
<button @click="setBooks">Set Books!</button>
</div>
</template>
<style scoped>
#bookList{
height: 300px;
width: 300px;
}
</style>
<script lang=ts>
import {Component,Vue,Prop} from "vue-property-decorator";
import store from "@/store";
@Component
export default class BooksInput extends Vue{
bookList="";
public setBooks(){
store.commit("setBooks",this.bookList.split(/\r|\n|\r\n/).filter(s=>s!=""));
store.commit("setDate",new Date());
alert("setBooks!");
}
}
</script>
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state:{
books: [] as string[],
date: null as Date
},
mutations:{
setBooks(state,books:string[]){
state.books=books;
},
setDate(state,date:Date){
state.date=date;
}
}
});
”蓝尤“
需要将容器注册为服务于 Program.cs。
@page "/StateContainer"
<div>
<BooksInput />
<button @onclick="getBooks">Get Books!</button>
<h3>BookLists (@date)</h3>
<ul>
@foreach(var book in books){<li @key="book">@book</li>}
</ul>
</div>
@inject AppState state;
@implements IDisposable;
@code{
protected override void OnInitialized(){state.OnChange+=StateHasChanged;}
public void Dispose(){state.OnChange-=StateHasChanged;}
string[] books={};
DateTime? date=null;
void getBooks(){
books=state.books;
date=state.date;
}
}
<div >
<div><textarea @bind="bookList" id="bookList"></textarea></div>
<button @onclick="setBooks">Set Books!</button>
</div>
<style>
#bookList{
height: 300px;
width: 300px;
}
</style>
@inject IJSRuntime js;
@inject AppState state;
@code{
string bookList="";
public void setBooks(){
state.setBooks(Array.FindAll(bookList.Replace("\r\n","\n").Split(new[]{'\n','\r'}),s=>s!=""));
state.setDate(DateTime.Now);
js.InvokeVoidAsync("alert","setBooks!");
}
}
using System;
public class AppState{
public string[] books{get;private set;}=new string[]{};
public DateTime? date{get;private set;}=null;
public void setBooks(string[] books){
this.books=books;
NotifyStateChanged();
}
public void setDate(DateTime date){
this.date=date;
NotifyStateChanged();
}
public event Action OnChange;
private void NotifyStateChanged()=>OnChange?.Invoke();
}
角度
const template=`
<div>
<BooksInput></BooksInput>
<button (click)="getBooks()">Get Books!</button>
<h3>BookLists ({{date}})</h3>
<ul>
<li *ngFor="let book of books">{{book}}</li>
</ul>
</div>
`;
import {Component} from "@angular/core";
import {StoreService} from "../../store.service";
@Component({
selector: "StateContainer",
template: template
})
export class StateContainerComponent{
constructor(
private store:StoreService
){};
books:string[]=[];
date:Date=null;
getBooks(){
this.books=this.store.books;
this.date=this.store.date;
}
}
const template=`
<div>
<div><textarea [(ngModel)]="bookList" id="bookList"></textarea></div>
<button (click)="setBooks()">Set Books!</button>
</div>
<style>
#bookList{
height: 300px;
width: 300px;
}
</style>
`;
import {Component} from "@angular/core";
import {StoreService} from "../../store.service";
@Component({
selector: "BooksInput",
template: template
})
export class BooksInputComponent{
constructor(
private store:StoreService
){}
bookList=`たのしいさんすう
たのしいこくご
たのしいどうとく
かぐやひめ
シンデレラ
うらしまたろう
かちかちやま`;
public setBooks(){
this.store.books=this.bookList.split(/\r|\n|\r\n/).filter(s=>s!="");
this.store.date=new Date();
alert("setBooks!");
}
}
import {Injectable} from "@angular/core";
@Injectable({
providedIn: "root"
})
export class StoreService{
books:string[]=[];
date:Date=null;
}
18. 读取JSON文件
在Vue.js/Blazor/Angular中,可以读取并显示JSON文件。(由于是客户端端,无法进行写入操作)
在这里将加载以下JSON文件。
[
"大剣",
"太刀",
"片手剣",
"双剣",
"ハンマー",
"狩猟笛",
"ランス",
"ガンランス",
"スラッシュアックス",
"チャージアックス",
"操虫棍",
"ライトボウガン",
"ヘビィボウガン",
"弓"
]
Vue.js 是一个流行的JavaScript前端框架。
使用 require 函数将 JSON 文件放置在 /src/assets/ 目录下。
<template>
<div>
<h3>Read JSON</h3>
<ul>
<li v-for="value in list" :key="value">{{value}}</li>
</ul>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class ReadJSON extends Vue{
list:string[]=[];
mounted(){
this.list=require("@/assets/weapons.json");
}
}
</script>
蔽芦阔尔
使用 HttpClient.GetJsonAsync 方法,在/wwwroot/ 目录下放置 JSON 文件。
将 JSON 文件放置在 /wwwroot/ 目录下,使用 HttpClient.GetJsonAsync 方法。
@page "/ReadJSON"
<div>
<h3>Read JSON</h3>
<ul>
@foreach(var value in list){<li @key="value">@value</li>}
</ul>
</div>
@inject HttpClient http;
@code{
string[] list={};
protected override async Task OnAfterRenderAsync(bool firstRender){
if(!firstRender) return;
list=await http.GetJsonAsync<string[]>("Assets/weapons.json?0");
StateHasChanged();
}
}
角度
使用HttpClient模块的get方法。
需要在add.module.ts中添加服务才能使用。
JSON文件的路径必须为/src/assets/下。
const template=`
<div>
<h3>Read JSON</h3>
<ul>
<li *ngFor="let value of list">{{value}}</li>
</ul>
</div>`;
import {Component,OnInit} from "@angular/core";
import {HttpClient} from "@angular/common/http";
@Component({
selector: "ReadJSON",
template: template
})
export class ReadJSONComponent implements OnInit{
constructor(
private http:HttpClient
){}
list:string[]=[];
async ngOnInit(){
this.list=await new Promise(res=>this.http.get("./assets/weapons.json?0").subscribe(res));
}
}
19. 文本文件的读取
Vue.js (中文选项:Vue.js )
我们无法仅使用Vue.js来读取纯文本文件。建议使用Vue.js官方的axios来进行读取。可以通过yarn或npm将其添加到项目中。
此外,使用这种方法也可以加载JSON,但需要注意的是,对文件的处理有些不同。
<template>
<div>
<h3>Read Text</h3>
<pre>{{text}}</pre>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
import axios from "axios";
@Component
export default class ReadText extends Vue{
text="";
async mounted(){
this.text=await axios.get("./kimigayo.txt?0").then(v=>v.data);
}
}
</script>
Blazor (布拉泽)
使用HttpClient.GetStringAsync进行读取,就像使用JSON一样。
@page "/ReadText"
<div>
<h3>Read Text</h3>
<pre>@text</pre>
</div>
@inject HttpClient http;
@code{
string text="";
protected override async Task OnAfterRenderAsync(bool firstRender){
if(!firstRender) return;
text=await http.GetStringAsync("./kimigayo.txt?0");
StateHasChanged();
}
}
角度
你可以像使用JSON一样使用HttpClient.get。
要读取文本文件,需要在参数中加入{ responseType: “text” }。
const template=`
<div>
<h3>Read Text</h3>
<pre>{{text}}</pre>
</div>
`;
import {Component,OnInit} from "@angular/core";
import {HttpClient} from "@angular/common/http";
@Component({
selector: "ReadText",
template: template
})
export class ReadTextComponent implements OnInit {
constructor(
private http:HttpClient
){}
text="";
async ngOnInit(){
this.text=await new Promise(res=>this.http.get("./assets/kimigayo.txt?0",{responseType:"text"}).subscribe(res));
}
}
20. HTML输出
在Vue.js/Blazor/Angular中,您可以像element.innerHTML一样将HTML写入到HTML中。
Vue.js是一个流行的JavaScript前端框架。
将值绑定到 v-html 属性上。
不允许使用 script 元素。
<template>
<div>
<h3>Inner HTML</h3>
<textarea v-model="txt" style="height:300px;width:300px;"></textarea>
<div v-html="txt"></div>
</div>
</template>
<script lang=ts>
import {Component,Vue} from "vue-property-decorator";
@Component
export default class InnerHTML extends Vue{
txt=
`<h1>TEST TITLE</h1>
<span style=color:#009900>
<u>Say</u> <i>Hello!</i>
</span>`;
}
</script>
Blazor = 布雷泽
通过将字符串转换为MarkupString类型并将其输出到任意位置,可以输出HTML。
无法使用script元素。
@page "/InnerHTML"
<div>
<h3>Inner HTML</h3>
<textarea @bind-value="txt" @bind-value:event="oninput" style="height:300px;width:300px;"></textarea>
<div>@((MarkupString)txt)</div>
</div>
@code{
string txt=
@"<h1>TEST TITLE</h1>
<span style=color:#990099>
<u>Say</u> <i>Hello!</i>
</span>";
}
角度
把值绑定到[innerHTML]属性中。除了script标签外,还不能使用style标签。
const template=`
<div>
<h3>Inner HTML</h3>
<textarea [(ngModel)]="txt" style="height:300px;width:300px;"></textarea>
<div [innerHTML]="txt"></div>
</div>
`;
import {Component} from "@angular/core";
@Component({
selector: "InnerHTML",
template: template
})
export class InnerHTMLComponent{
txt=
`<h1>TEST TITLE</h1>
<font color="#990000">
<u>Say</u> <i>Hello!</i>
</font>`;
}
路由器 qì)
最后,我们将展示本次使用的路由器示例。
Vue.js是一个用于构建用户界面的渐进式JavaScript框架。
每当页面增加时,都需要在/src/router.index.ts中添加。
import Vue from "vue";
import VueRouter from "vue-router";
import Index from "@/views/Index.vue";
import PageA from "@/views/PageA.vue";
import PageB from "@/views/PageB.vue";
Vue.use(VueRouter);
const routes=[
{path: "/", name: "Index", component: Index},
{path: "/PageA", name: "PageA", component: PageA},
{path: "/PageB", name: "PageB", component: PageB}
];
const router=new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
<template>
<main style=display:flex>
<NavMenu />
<div class=v-hr></div>
<router-view/>
</main>
</template>
<style scoped>
.v-hr{
margin: 0 10px;
border-right: 5px solid #CCC;
height: 100vh;
}
</style>
<script lang:ts>
import {Component,Vue} from "vue-property-decorator";
import NavMenu from "@/components/NavMenu.vue";
@Component({
components:{
NavMenu
}
})
export default class App extends Vue{}
</script>
<template>
<nav>
<ol type="1" start="0">
<li><router-link to="/">index</router-link></li>
<li><router-link to="/PageA">PageA</router-link></li>
<li><router-link to="/PageB">PageB</router-link></li>
</ol>
</nav>
</template>
<style scoped>
.router-link-exact-active{
color: #FF0000;
font-weight: bold;
}
</style>
Blazor
@inherits LayoutComponentBase
<main style=display:flex>
<NavMenu />
<div class=v-hr></div>
@Body
</main>
<style>
.v-hr{
margin: 0 10px;
border-right: 5px solid #CCC;
height: 100vh;
}
</style>
<div>
<ol type="1" start="0">
<li><NavLink Match="NavLinkMatch.All" href="./">index</NavLink></li>
<li><NavLink Match="NavLinkMatch.All" href="./PageA">PageA</NavLink></li>
<li><NavLink Match="NavLinkMatch.All" href="./PageB">PageB</NavLink></li>
</ol>
</div>
<style>
nav .active{
color: #FF0000;
font-weight: bold;
}
</style>
角度
每增加一页,都需要在/src/app/app-routing.module.ts中进行添加。
import {NgModule} from "@angular/core";
import {Routes, RouterModule} from "@angular/router";
import {IndexComponent} from "./pages/Index/Index.component";
import {PageAComponent} from "./pages/PageA/PageA.component";
import {PageBComponent} from "./pages/PageB/PageB.component";
const routes: Routes=[
{path: "", component: IndexComponent},
{path: "PageA", component: PageAComponent},
{path: "PageB", component: PageBComponent},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
const template=`
<main style=display:flex>
<NavMenu></NavMenu>
<div class=v-hr></div>
<router-outlet></router-outlet>
</main>
<style>
.v-hr{
margin: 0 10px;
border-right: 5px solid #CCC;
height: 98vh;
}
</style>
`;
import {Component} from "@angular/core";
@Component({
selector: "app-root",
template: template
})
export class AppComponent{}
const template=`
<nav>
<ol type="1" start="0">
<li><a routerLinkActive="active" [routerLinkActiveOptions]="{exact:true}" routerLink="/">index</a></li>
<li><a routerLinkActive="active" [routerLinkActiveOptions]="{exact:true}" routerLink="/PageA">PageA</a></li>
<li><a routerLinkActive="active" [routerLinkActiveOptions]="{exact:true}" routerLink="/PageB">PageB</a></li>
</ol>
</nav>
<style>
.active{
color: #FF0000;
font-weight: bold;
}
</style>
`;
import {Component} from "@angular/core";
@Component({
selector: "NavMenu",
templateUrl: template
})
export class NavMenuComponent{}
总结
我总结了一下Vue.js和Blazor(+ Angular)的语法比较。虽然在样式规范等方面有些无法改变的部分,但大部分情况下都可以以几乎相同的方式编写。我还觉得在速度方面还有些困难,但我希望未来的Blazor能有所期待。