一次学俩Vue&Blazor:1.3基础-模板语法和Razor语法

一、先复习一下上个章节学习的组件本质


1、Vue的组件本质是一个对象(通过选项式API来看Vue组件本质):

  • 视图层是属性template的值。在视图层中,使用模板语法,使视图层和逻辑层建立关联。
  • date()方法返回响应式数据。
  • methods属性中,定义方法。
  • computed属性中,定义计算属性(本质是方法)。
  • 同时还提供了生命周期函数等方法或属性。
  • 在视图层中调用定义好的组件时,如,实质是以组件对象为模板创建这个对象的实例。
  • 组合式API可以视为是选项式API的语法糖,使我们可以更加流畅的进行组件开发。

2、Blazor的组件本质是一个类:

  • 组件头部以@符号开头的指令,如@page、@implements等,定义类的特性、继承、实现、泛型、依赖注入等行为。
  • 视图层是类的一个特殊方法,在方法内部,使用Razor语法,C#和标签元素可以混写,也可以访问类的其它成员,类似于React/JSX。
  • 在@code{}中,定义类的其它成员,可以是字段、属性或者方法。
  • 在视图层中调用定义好的组件时,如,实质是创建这个类的实例。


二、Vue的模板语法和Blazor的Razor语法


1、概述

  • 无论是模板语法,还是Razor语法,都为我们提供了操作视图层和逻辑层的便捷方法(声明式),如数据绑定、数据更新、事件响应、双向绑定等,而不需要像以前一下直接操作DOM。
  • 模板语法,有模板两字,意味框架提供了一系列模式方式,我们必须按照这些模式使用相应的功能。
  • Razor语法,类似于React的JSX,C#和元素/组件标签可以混写,提供了更大的自由度。
  • 自由度是双面的,模板语法限制了自由,但因为有了模板,框架能够直接判断代码意图,从而提升处理效率,同时也能防止我们写出低效代码,所以在很多性能测试报告中,会看到Vue的性能会优于React。

2、标签体内容的数据绑定(单向)

实现标签体内容和逻辑层数据的单向绑定,当更新逻辑层数据时,标签内容会自动更新。两者语法如下所示:
  • Vue:{{ 双花括号内是JS表达式 }},如{{number+1}}
  • Blazor: @( 括号内是C#表达式 ),如@(number+1)。如果表达式是一个标识符,()可以省略,如@number
  • 特别注意:只能绑定表达式,可以使用常量、变量、运算符、方法调用、API调用的任意合法组合的表达式
1)简单变量
//******Vue******
<template> 
  <span>Message: {{ msg }}</span>
</template> 

<script setup>
import { ref } form ‘vue’;
const msg = ref(‘你好,我是functonMC’); //使用ref将字符串转为响应式
</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)方法调用
//******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;
    }
}
4)调用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";
}
5)三元表达式
//******Vue******
<template>
  <span>{{ ok ? "好的" : "不行" }}</span>
</template>

<script setup>
import { ref } from "vue";
const ok = ref(true);
</script>
//******Blazor******
<span>@(ok?"好的":"不行")</span>

@code {
    private bool ok = true;
}

3、标签属性的数据绑定(单向)

和标签体内容绑定一样,标签属性也可以绑定逻辑层数据,可以使用常量、变量、运算符、方法调用、API调用的任意合法组合的表达式。两者的语法如下所示:
  • Vue:<span v-bind:title="newsTitle"></span>,简写为<span :title="newsTitle"></span>。newsTitile须为合法表达式。
  • Blazor:<span title="@newsTitle"></span>,属性值的引用可以省略,但建议保留。newsTitile须为合法表达式。
  • 标签属性的绑定,会涉及到样式绑定、表单组件的双向绑定、父子组件传值等功能,后续章节再逐一详述。

4、控制语句(DOM的条件渲染和循环渲染)

这里的控制结构,主要指DOM结构的条件渲染和循环渲染。Vue的模板语法需要使用指令来完成,如用于条件的v-if/v-else-if/v-else/v-show,用于循环的v-for;而Blazor的Razor语法,支持标签/组件和C#可以混写,可以直接使用C#的控制语句,如if/else、for、foreach等。
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>

//②v-show指令
//使用v-show时,节点实际上已被加载,只是改变了元素样式的display属性
//如果type值在运行时频繁变化,相对于v-if,开销会较少。
<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";
}

//②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中也能实现类似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-forr指令
//可以循环渲染数组和类数组,类数组包括了字符串、整数、对象等

<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******
//可以循环集合、数组、整数、字符串,只要是可迭代对象

//①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>
}

@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; }
    }
}


三、指令体系

模板语法和Razor语法,都需要通过指令来实现特定功能,如前所述的{{}}v-ifv-forv-bind@@page等。当编译器碰到这些指令时,将按照特定规则进行编译处理。由于Vue使用模板语法,而Blazor的C#和标签可以混写,所以Vue的指令会比Blazor更加繁杂。这些指令,我们将在后续章节深入学习,本节仅做汇总介绍。


1、Vue模板语法的指令,主要以v-开头,目前十几个左右

//1、数据和事件绑定
//①标签体内容绑定表达式,双花括号
<span>{{number+1}}</span>
//②标签属性值绑定表达式,简写用冒号
<span v-bind:title="title"></span>
<a :href="href"></a>
//③双向绑定,针对表单组件
<input v-model="count" />
<input v-model.number="count" />
<input v-model.trim="name" />
<input v-model.lazy="name" />
//④事件绑定,简写用@符。
<button v-on:click = "addCount"></button>
<button @click = "addCount"></button>
<button @click.stop="doThis"></button> //事件附加属性.stop,阻止冒泡行为


//2、控制语句
//①循环渲染
<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>

//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> //可以等价于{{}},text可定义为响应式,如const text = ref("Hello")
<div v-html = "html"></div> //绑定html原始标签,有风险,甚用,html可定义为响应式,如const html = ref('<h1>aaa</h1>')

//5、具名插槽
//可简写为<template #header>...</template>
<template v-slot:header>
  <!-- header插槽的内容放这里 -->
</template>

2、Blazor的Razor语法指令:可以划分为三类,文件级别指令、标签级别指令、DOM事件指令。

//1、文件级别的指令。Razor文件/组件,本质上是一个类,这些指令主要作用于类。除了@code外,其它指令所在位置都在文件头。
@code //c#代码块,可以定义多个
@page //路径,代码层面是作用于类的特性
@layout //母板,代码层面是作用于类的特性
@inject //依赖注入
@implements //实现接口
@inherits //继承基类
@attribute //标注特性
@typeparam //类的泛型
@namespace //所属命名空间


//2、标签级别的指令。除@符外,其它指令一般者都定义在标签的属性名位置,如<span @ref="title"></span>
@ //标签体内容或标签属性值,单向绑定
@bind @bind:event @bind:culture @bind:get @bind:set @bind:after  //实现双向绑定
@ref //引用组件或HTML标签
@key //作为组件或HTML标签的唯一标识,主要在循环渲染时使用
@attributes //将字典对象扩展为组件或HTML标签属性


//3、事件指令。这部分比较多,主要分为焦点、鼠标、拖动、键盘、输入、剪切板、触摸、指针、多媒体、进度等。
//①格式:【@on{事件名}】,如【<div @onclick = "SomeFunction">】
//②事件附加行为:【@on{事件名}:{附加行为},如【<div @onclick = "AddCount" @onclick:stopPropagation>】
//③完整例子:
<div @onclick = "SomeFunction">
  <div @onclick = "AddCount" @onclick:stopPropagation></div>
</div>


posted @ 2022-05-06 22:22  functionMC  阅读(1733)  评论(0编辑  收藏  举报