Vue使用模板语法,Blazor使用祖传的Razor语法,从逻辑和方向上看,两者极为相似,比如:

  • 都基于HTML
  • 都通过声明式地将组件实例的状态(数据/方法)绑定到呈现的DOM上
  • 都通过指令实现更加丰富的视图/HTML与逻辑/JS和C#的互动应用
  • 底层机制都是通过虚拟DOM,实现差量更新
  • 工程组建方式都基于组件树
  • 都具有单文件组件特征

但在具体实现和语法上,两者有比较大的差异。给人的总体感觉就是,都很熟悉,但就是不太一样。以下仅对语法基础进行逐点比较,内容较多,目录如下:

  1. 标签内容绑定(单向)
  2. 标签属性绑定(单向)
  3. 控制结构(判断/循环等)
  4. 指令体系概述
  5. 补充:Vue的响应式约束

1、标签内容绑定(单向)
这是最基本的数据绑定形式,可以实现HTML标签体内容和逻辑代码的动态绑定。【单向】更新逻辑代码时,标签内容会自动更新。Vue和Blazor的标签体内容绑定语法如下所示:

  • Vue使用双大括号,{{ /*这里是JS表达式*/ }},如{{ number+1 }}
  • Blazor使用@符,@/*这里是C#表达式*/,如@(number+1),这里需要使用()显示标注表达式
  • 注:表达式可以使用常量、变量、方法调用、API调用、运算符的任意合法组合

(1)最简单的变量

//Vue=====================================
<template>
<span>Message: {{ msg }}</span>
</template> <script setup>
import { ref } form ‘vue’;
const msg = ref(‘你好,我是functonMC’);
</script> //Blazor====================================
<span>Message: @msg</span> @code {
private string msg = “你好,我是functonMC”;
}

(2)运算表达式

//Vue=====================================
<template>
<span>结果是:{{ number + 1 }}</span>
</template> <script setup>
import { ref } from "vue";
const number = ref(10);
</script> //Blazor====================================
<span>@(number+1)</span> @code {
private int number = 10;
}

(3)调用API的表达式

//Vue=====================================
<template>
<span>{{ message.split("").reverse().join("") }}</span>
</template> <script setup>
import { ref } from "vue";
const message = ref("Hello,functionMC");
</script> //Blazor====================================
<span>@(string.Join("",message.ToCharArray().Reverse().ToArray()))</span> @code {
private string message = "Hello,functionMC";
}

(4)三元表达式

//Vue=====================================
<template>
<span>{{ ok ? "好的" : "不行" }}</span>
</template> <script setup>
import { ref } from "vue";
const ok = ref(true);
</script> //Blazor====================================
<span>@(ok?"好的":"不行")</span> @code {
private string message = "Hello,functionMC";
}

(5)方法调用

//Vue=====================================
<template>
<span>{{ addResult(1, 2) }}</span>
</template> <script setup>
function addResult(a, b) {
return a + b;
}
</script> //Blazor===================================
<span>@AddResult(1,2)</span> @code {
private int AddResult(int a,int b)
{
return a + b;
}
}

2、标签属性绑定(单向)

和标签体内容绑定一样,标签属性也可以绑定逻辑代码,可以使用常量、变量、方法调用、API调用、运算符的任意合法组合的表达式。Vue需要使用v-bind指令(可以简写为冒号),Blazor仍然使用@符,表达式的使用“标签内容”绑定基本一致。两者的语法如下所示:

  • Vue:<span v-bind:title="newsTitle"></span>,简写为<span :title="newsTitle"></span>
  • Blazor:<span title="@newsTitle"></span>,可以省略引号为<span title=@newsTitle></span>

可以注意到Vue的冒号和Blazor@符所在位置的区别。所以在Blazor中,你是很容易区别指令、标签属性绑定和标签内容绑定三者的区别的,比如style="@TitleStyle"是标签属性绑定,@key="people.Id"是指令key。而在Vue中,这并不好区别,如:style="titleStyle"是标签属性绑定,:key="people.id"是指令呢?还是属性绑定呢?虽然这种区分,然并卵,但你能感觉到Blazor有着C#的严谨支撑,整个组件体系,也是基于C#的语法体系,Razor和C#之间是很容易打通的,源码比较容易看懂。而Vue在灵活的JS之上又做了一层抽象,总让人感到失去了语言的一惯性,现在的组合式API会好点,Vue2时代的选项式API,这种感觉更甚,甚至有人说,学了Vue后,都快忘了JS了。

言归正传,标签属性绑定的应用,主要涉及到样式绑定、表单组件的双向绑定、父子组件的数据传递、以及指令体系,每个在后续都会另起章节详述,所以暂且略过!

3、控制结构(条件/循环)

这里的控制结构,主要指DOM结构的条件渲染和循环渲染。Vue需要使用指令来完成,用于条件的v-if/v-else-if/v-else/v-show,用于循环的v-for;而Blazor则灵活很多,因为在Blazor中,html和C#可以混写,所以你就感觉是在写C#一样,这和react倒是很像。

(1)条件渲染

//Vue中使用v-if===============================
//根据绑定的type值,只渲染判断为true的DOM节点,其它全部干掉。如果type值在运行时频繁改变,开销将比较大,这种情况推荐使用v-show
<template>
<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else-if="type === 'C'">C</div>
<div v-else>Not A/B/C</div>
</template> <script setup>
import { ref } from "vue";
const type = ref("B");
</script> //Vue中使用v-show=============================
//使用v-show时,所有节点都有渲染,只是改变的style的display属性,所以运行时频繁改变type值时,开销会少很多。
<template>
<div v-show="type === 'A'">A</div>
<div v-show="type === 'B'">B</div>
<div v-show="type === 'C'">C</div>
<div v-show="!(type==='A'||type==='B'||type==='C')">Not A/B/C</div>
</template> <script setup>
import { ref } from "vue";
const type = ref("B");
</script> //Blazor中使用if===============================
@if (type == "A")
{
<div>A</div>
}
else if (type == "B")
{
<div>B</div>
}
else if (type == "C")
{
<div>C</div>
}
else
{
<div>not A/B/C</div>
} @code {
private string type = "g";
} //Blazor中使用switch============================
@switch (type)
{
case "A":
<div>A</div>
break;
case "B":
<div>B</div>
break;
case "C":
<div>C</div>
break;
default:
<div>not A/B/C</div>
break;
} @code {
private string type = "g";
} //Blazor中实现类似Vue的v-show=====================
<div style="display:@((type=="A")?"inline":"none")">A</div>
<div style="display:@((type=="B")?"inline":"none")">B</div>
<div style="display:@((type=="C")?"inline":"none")">C</div>
<div style="display:@(!(type=="A"||type=="B"||type=="C")?"inline":"none")">not A/B/C</div> @code {
private string type = "A";
}

(2)循环渲染

//Vue使用v-for指令=============================
//可以循环渲染数组和类数组,类数组包括了对象、字符串、整数等 <template> //循环对象数组,同时拿到索引。也可以v-for=“item in items1"
<li v-for="(item, index) in items1" :key="item.id">
{{ index + 1 }}-{{ item.name }}
</li> //循环对象,按顺序拿到value,key和index
<li v-for="(value, key, index) in items2" :key="key">
{{ key }}-{{ value }}-{{ index }}
</li> //循环一个整数
<li v-for="n in 10" :key="n">
{{ n }}
</li> //循环一个字符串
<li v-for="n in 'hello,functionMC'" :key="n">
{{ n }}
</li>
</template> <script setup>
import { ref } from "vue";
const items1 = ref([
{ id: 1, name: "ZhangSan", age: 18 },
{ id: 2, name: "LiSi", age: 18 },
{ id: 3, name: "WangWu", age: 18 },
]); const items2 = ref({
type: "上衣",
number: "KY2022001",
price: 200,
});
</script> //Blazor中可以使用所有C#的控制语句=================== //使用foreach循环
@foreach (var item in peoples)
{
<li>
@($"{item.Id}-{item.Name}-{item.Age}")
</li>
} //使用for循环
@for (var i = 0; i < peoples.Count; i++)
{
<li>
@peoples[i].Name
</li>
} //使用while循环。不是闲得蛋蛋疼,应该不会用它
@{
var j = 0;
}
@while (j < peoples.Count)
{
<li>
@peoples[j].Name
</li> j++;
} //循环整数
@for (var i = 0; i < 10; i++)
{
<li>@i</li>
} //循环字符串
@foreach (var item in "Hello,functionMC")
{
<li>@item</li>
} //是否可以像Vue一样循环对象?p1对象身上并没有迭代器,可以尝试定义一个迭代器来实现,或者通过遍历Json来实现。太费脑,先留着吧 @code {
private List<People> peoples = new List<People>
{
new People{Id=1,Name="Zhangsan",Age=18},
new People{Id=1,Name="LiSi",Age=19},
new People{Id=1,Name="WangWu",Age=20}
}; public class People
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}

4、指令体系概览

Vue和Blazor都有指令,指令本质上是内置宏(即一组命令),从这个角度理解,Vue在逻辑代码中使用的defineProps、defineEmits、defineExpose,算不算指令?对比Vue,Blazor的指令的划分、语法格式和使用,更加规范,也更加广泛。但目前为止,Blazor还不能够自定义指令,而Vue可以(单独章节来说)。下面对两个框架的指令,进行概述,后续章节再和其它知识点做更深入的总结

(1)Blazor的指令:可以划分为三类,Razor文件/组件级别指令、组件/标签级别指令、DOM事件指令

//1、Razor文件/组件级别的指令。Razor文件/组件,本质上是一个类,这些指令主要作用于类。除了@code外,其它指令所在位置都在文件头。
@code //c#代码块,可以定义多个
@page //路径,代码层面是作用于类的特性
@layout //母板,代码层面是作用于类的特性
@inject //依赖注入
@implements //实现接口
@inherits //继承基类
@attribute //标注特性
@typeparam //类的泛型
@namespace //所属命名空间 //2、组件或HTML标签级别的指令。这些指令都定义在标签的属性名位置,以@符开头,如<span @ref="title"></span>
@ref //引用组件或HTML标签
@key //作为组件或HTML标签的唯一标识,主要在循环渲染时使用
@attributes //将字典扩展为组件或HTML标签属性
@bind //实现双向绑定 //3、HTML的DOM事件指令。这部分比较多,主要分为焦点、鼠标、拖动、键盘、输入、剪切板、触摸、指针、多媒体、进度、其它。需要注意几个点: //①如果我们把指令视为类,那么就还可以通过指令属性来定义指令的特殊形为。Blazor中称为指令属性(事件指令特有),Vue中叫事件修饰符。在Blazor中,使用麻烦点,需要重复一次指令。
<div @onclick = "SomeFunction">
<div @onclick = "AddCount" @onclick:stopPropagation></div>
</div> //②事件回调可以默认获得DOM事件参数,但需要注意,不同事件类别,事件参数类型不一样,比如鼠标事件为MouseEventArgs,输入事件为ChangeEventArgs等。如果要传入事件参数以外的参数,需要使用以下形式:
<button @onclick = "@((e)=>AddCount(e,1,2))"></button>
@code{
private int AddCount(MouseEventArgs e,int a,int b){return a+b;}
}

(2)Vue的指令特指v-开头的那十几个

//1、条件循环渲染
//①循环渲染
<li v-for="item in items">{{item.id}}</li> //②条件渲染
<div v-if="Math.random() > 0.5">大于0.5</div>
<div v-else-if="Math.random() < 0.5">小于0.5</div>
<div v-else>Now you don't</div> //③条件渲染通过更新display属性
<div v-show="true"></div> //2、数据事件绑定
//①属性绑定,简写用冒号
<span v-bind:title="title"></span>
<a :href="href"></a> //②事件绑定,简写用@符
<button v-on:click = "addCount"></button>
<button @click = "addCount"></button>
<button @click.stop="doThis"></button> //③双向绑定,表单标签
<input v-model="count" />
<input v-model.number="count" />
<input v-model.trim="name" />
<input v-model.lazy="name" /> //3、控制组件渲染
//①只在第一次加载时渲染
<div v-once> {{ message }}</div> //②不编译,包括子组件,保持原始输出(此例中输出{{ message }})
<div v-pre> {{ message }}</div> //③直至编译完才出现
<div v-cloak> {{ message }}</div>
<style>
[v-cloak] {
display:none !important;
</style> //4、文件html绑定
①可以等价于{{}}
<div v-text = "text"></div>
...
const text = ref('hello') ②绑定html原始标签,有风险,甚用
<div v-text = "html"></div>
...
const html = ref('<h1>aaa</h1>')

5、补充:Vue的响应式约束

Vue通过reactive和ref,这两个API来创建响应式数据,实现html视图和js逻辑的数据绑定。实际应用中,有几个点需要特别注意:

(1)reactive只能用来创建对象类型(如对象、数组、Map、Set),不能创建原始类型(如string、number、boolean等)。而ref可以创建任何类型。

const a = reactive({name:'MC',age:18}) //正确
const b = reactive(18) //错误
const a = ref({name:'MC',age:18}) //正确
const b = ref(18) //正确

(2)reactive创建的响应式对象,默认是深层次的,所以里面嵌套的数据都是响应式的。

const a = reactive({})
a.people = {name:'MC',age:18} //增加的people属性也是响应式

(3)当使用ref时,值保存在ref对象的value属性上。如果是在逻辑代码里读取或修改,需要通过访问value属性,如b.value+=2;如果在模板中读取或修改,会自动解包,不需要.value

//逻辑代码中,需要通过.value来访问。模板中,自动解包,不需要.value
<script setup>
import {ref} from 'vue'
const a = ref({name:”MC”,age:18})
a.value.name
</script> <template>
<h1>{{a.name}}</h1>
</template>

(4)当使用ref创建对象类型时,会调用reactive来创建value属性,类似于这种感觉ref(reactive(value)),所以替换value值时,新值仍然是响应式的,而reactive如果替换新值,则会失去响应性。所以在实际应用中,创建对象数组类型时,需要使用ref,因为ref创建的对象,使用数组的map、filter、reduce等返回新数组的方法时,新数组仍然可以保持响应性。除此之外,创建分离的组合式API时,暴露出来的数据,也应该使用ref,这样在引用这个API时,解构出来的数据仍然具有响应性。

 //这样是行不通的
const a = reactive({name:”MC”,age:18})
a = reactive{name:”Fun”,age:16} //ref才可以实现响应式替换
const b = ref({name:”MC”,age:18})
b.value = {name:”Fun”,age:16} //ref实现响应式解构
const obj1 = {foo: ref(1),bar: ref(2)}
const {foo,bar} = obj1 //响应式解构 //使用ref,b还是响应式
const b = ref([
{name:”MC1”,age:18},
{name:”MC2”,age:19},
{name:”MC3”,age:20}])
b.value = b.value.filter((e)=>{return e.age >18}) //换成reactive,b失去了响应式
const b = reactive([
{name:”MC1”,age:18},
{name:”MC2”,age:19},
{name:”MC3”,age:20}])
b = b.filter((e)=>{return e.age >18})

总结:官方文档有一句话“为了解决reactive带来的限制,Vue 也提供了一个ref方法来允许我们创建可以使用任何值类型的响应式ref”。创建响应式数据时,我推荐尽量使用ref,虽然.value麻烦点。

Blazor和Vue对比学习(基础1.2):模板语法和Razor语法的更多相关文章

  1. Blazor和Vue对比学习(基础1.4):事件和子传父

    Blazor和Vue的组件事件,都使用事件订阅者模式.相对于上一章的组件属性,需要多绕一个弯,无论Blazor还是Vue,都是入门的第一个难点.要突破这个难点,一是要熟悉事件订阅模式<其实不难& ...

  2. Blazor和Vue对比学习:说在开始前

    1.Vue:现代前端三大框架之一(Vue/React/Angualr),基于HTML.CSS和JavaScript,2014年正式对外发布,目前已发展到3.X版本.值得说道的是,Vue的创始人作者是华 ...

  3. Blazor和Vue对比学习(进阶2.2.4):状态管理之持久化保存(2),Cookie/Session/jwt

    注:本节涉及到前后端,这个系列的对比学习,还是专注在前端Vue和Blazor技术,所以就不撸码了,下面主要学习概念. 我们知道,Http是无状态协议,客户端请求服务端,认证一次后,如果再次请求,又要重 ...

  4. Blazor和Vue对比学习(基础1.8):Blazor中实现计算属性和数据监听

    1.7章<传递UI片断>,需要做几个案例,这部分暂停消化几天.我们先把基础部分相对简单的最后两章学习了. 计算属性和数据监听是Vue当中的概念,本质上都是监听数据的变化,然后做出响应.两者 ...

  5. Blazor和Vue对比学习(基础1.9):表单输入绑定和验证,VeeValidate和EditFrom

    这是基础部分的最后一章,内容比较简单,算是为基础部分来个HappyEnding.我们分三个部分来学习: 表单输入绑定 Vue的表单验证:VeeValidate Blazor的表单验证:EditForm ...

  6. Blazor和Vue对比学习(基础1.3):属性和父子传值

    组件除了要解决视图层展示.视图层与逻辑层的数据绑定,还需要解决一个重大问题,就是在组件树中实现数据传递,包括了父到子.子到父.祖到孙,以及任意组织之间.而我们上一章讲到的实现双向绑定的两个指令,Vue ...

  7. Blazor和Vue对比学习(基础1.5):双向绑定

    这章我们来学习,现代前端框架中最精彩的一部分,双向绑定.除了掌握原生HTML标签的双向绑定使用,我们还要在一个自定义的组件上,手撸实现双向绑定.双向绑定,是前两章知识点的一个综合运用(父传子.子传父) ...

  8. Blazor和Vue对比学习(基础1.1):组件结构

    难度:★ 简单说一说: 1.Vue和Blazor都遵循单文件结果,即HTML(视图模板).CSS(样式).JS/C#(代码逻辑)写在一个文件里,Vue的文件后缀为.vue,Blazor的文件后缀为.r ...

  9. Blazor和Vue对比学习(基础1.6):祖孙传值,联级和注入

    前面章节,我们实现了父子组件之间的数据传递.大多数时候,我们以组件形式来构建页面的区块,会涉及到组件嵌套的问题,一层套一层.这种情况,很大概率需要将祖先的数据,传递给子孙后代去使用.我们当然可以使用父 ...

随机推荐

  1. 什么时候使用session?什么时候使用application?

    application:程序全局变量对象,对每个用户每个页面都有效session:用户全局变量,对于该用户的所有操作过程都有效

  2. 什么是通用 SQL 函数?

    1.CONCAT(A, B) – 连接两个字符串值以创建单个字符串输出.通常用于将两个 或多个字段合并为一个字段. 2.FORMAT(X, D)- 格式化数字 X 到 D 有效数字. 3.CURRDA ...

  3. Zookeeper 下 Server 工作状态?

    服务器具有四种状态,分别是 LOOKING.FOLLOWING.LEADING.OBSERVING. 1.LOOKING:寻找 Leader 状态.当服务器处于该状态时,它会认为当前集群中没有 Lea ...

  4. TCP 重传、滑动窗⼝、流量控制、拥塞控制

    重传机制 TCP 会在以下两种情况发⽣超时重传: 数据包丢失 确认应答丢失 重传超时 重传超时是TCP协议保证数据可靠性的另一个重要机制,其原理是在发送某一个数据以后就开启一个计时器,在一定时间内如果 ...

  5. python中模块制作、发布、安装

    模块的发布 需要在当前目录下 模块的安装 真实制作发布一个包 包的制作 (1)将写好的包放在moudelTest目录下 (2)moudelTest目录下创建一个setup.py文件(格式上面有介绍) ...

  6. 论文解读( N2N)《Node Representation Learning in Graph via Node-to-Neighbourhood Mutual Information Maximization》

    论文信息 论文标题:Node Representation Learning in Graph via Node-to-Neighbourhood Mutual Information Maximiz ...

  7. Vue的computed(计算属性)使用实例之TodoList

    最近倒腾了一会vue,有点迷惑其中methods与computed这两个属性的区别,所以试着写了TodoList这个demo,(好土掩面逃~); 1. methods methods类似react中组 ...

  8. snippet,让你编码效率翻倍

    为什么谈到Snippet 今天下午在用vscode做小程序的时候,发现很不方便,因为商店里提供的代码片段极为有限,而且平时几乎每天都需要用到代码片段,所以就在思考他们是怎么做到给别人提供代码的,我可以 ...

  9. react 实用项目分享-mock server

    使用react16+router4+mobx+koa2+mongodb做的mock平台 moapi-cli 本地工具版,一行命令 ,方便个人使用 安装 npm i moapi-cli -g 使用 mo ...

  10. C#编写一个简易的文件管理器

    编写一个简易的文件管理器,通过本次实验,练习 TreeView.ListView 和SplitContainer 控件的使用,同时熟悉 C#文件系统的操作方法以及 File 类和 Directory类 ...