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

组件除了要解决视图层展示、视图层与逻辑层的数据绑定,还需要解决一个重大问题,就是在组件树中实现数据传递,包括了父到子、子到父、祖到孙,以及任意组织之间。而我们上一章讲到的实现双向绑定的两个指令,Vue的v-model,Blazor的@bind,可以认为是父到子和子到父,两个方向同时实现的语法糖,后面章节我们再来实现它。

我们先从最简单的父子传值开始学习。在Vue和Blazor中,都是通过属性来实现父子组件的数据传递。我们以往都是在html标签上设置属性,属性值可以是字面量,也可以绑定逻辑数据。比如这样<a :href="href">连接</a>。我们现在把a标签换成一个自定义的组件,<Link :href="href">链接</Link>,Link组件会如何对待这个绑定的href值呢?【例子中,大家不要忽略一个事实,无论是a标签也好,还是组件Link也罢,它们都是在另外一个组件中使用的,这个组件我们称为父组件,而a标签或Link组件,称为子组件】

  1. 父子传值的基本使用
  2. 传递属性值的类型
  3. 传递属性值的校验

 

1、父子传值的基本使用

Vue在子组件中,通过defineProps(宏命令,不需要import)来定义属性,Blazor在子组件中,通过[Parameter]特性,来标注属性。Vue不断的创造新的API,不看源码,你不会知道这个defineProps是怎么工作的,而Blazor无招胜有招,使用的时候,你就能大概明白是怎么一回事!

//Vue=====================================  //1、子组件Post  //定义两个属性用于接收数据 <script setup> const props = defineProps(['title','content'])  //在代码中,通过props.title来使用属性值 </script>  //在模板中使用接收到的两个属性值 <template>     <h1>{{title}}</h1>     <h3>{{content}}</h3> </template>    //2、父组件传递数据 //引入子组件Post <script setup> import {ref} from 'vue' import Post from './components/Post.vue' const content = ref('美国又来搅局!') </script>  //使用子组件,title属性绑定字面量,content属性绑定逻辑变量 <template>   <Post title="俄乌局事有重大变化" :content="content"></Post> </template>    //3、父组件传递数据-循环渲染 <script setup> import {ref} from 'vue' import Post from './components/Post.vue' const posts = ref([     {title:'标题1',content:'内容1'},     {title:'标题2',content:'内容2'}, ]) </script>  <template>   <Post v-for="post in posts" :title="post.title" :content="post.content"></Post> </template>

//Blazor===================================  //1、子组件Post //在模板中使用接收到的两个属性值 <h1>@Title</h1> <h3>@Content</h3>  //定义两个属性用于接收数据 @code {     [Parameter]     public string Title { get; set; }     [Parameter]     public string Content { get; set; } }   //2、父组件传递数据 //使用子组件,title属性绑定字面量,content属性绑定逻辑变量 <Post Title="俄乌局事有重大变化" Content="@content"></Post>  @code {     private string content = "美国又来搅局"; }   //3、父组件循环渲染传递数据 @foreach (var post in posts) {     <Post Title="@post.Title" Content="@post.Content"></Post> }  @code {     private List<PostModel> posts = new List<PostModel>     {         new PostModel{Title="标题1",Content="内容1"},         new PostModel{Title="标题2",Content="内容2"}     }; }

 

 

2、传递属性值的类型

对于HTML标签的属性,我们只能传递指定的类型,一般是数值、字符串、布尔等简单类型,但对于自定义组件,我们可以传递任意类型,Vue和Blazor在这方面都没有限制。

【有个注意点需要特别小心】:

Vue:当传递数组、对象等引用类型时,仅仅传递了引用地址。所以,在子组件中直接修改传递过来的属性值,父组件的值也会被改变。在Vue中,如果需要修改传递过来的属性值,建议将属性值赋值给一个新变量,再对新变量进行加工处理。

Blazor:不存在Vue的问题,即使传递引用类型,也是传递一个新值给子组件,属性值在父子组件中相互独立。

//Vue=====================================  //子组件,接收对象和数组 <script setup> const props = defineProps(['value1','value2']) </script>  <template>     <h1>{{value1.name}}-{{value1.age}}</h1>     <h3 v-for="item in value2">{{item.name}}-{{item.age}}</h3> </template>   //父组件,传递对象和数组类型数据 <script setup> import {ref} from 'vue' import Post from './components/Post.vue' const value1 = ref({name:'Fun',age:18}) const value2 = ref([     {name:'Fun',age:18},     {name:'MC',age:19}, ]) </script>  <template>   <Post :value1="value1" :value2="value2"></Post> </template>

//Blazor  //子组件,定义了一个PostModel类属性,以及这个类的集合属性 <h1>@($"{PostModel.Title}-{PostModel.Content}")</h1>  @foreach (var item in PostModels) {     <h3>@($"{item.Title}-{item.Content}")</h3> }   @code {     [Parameter]     public PostModel PostModel { get; set; }     [Parameter]     public List<PostModel> PostModels { get; set; } }   //父组件创建了一个PostModel实例,以及PostModel的集合实例 <Post PostModel="@postModel" PostModels="@postModels"></Post>  @code {     private PostModel postModel = new PostModel { Title = "标题1", Content = "内容1" };      private List<PostModel> postModels = new List<PostModel>     {         new PostModel{Title="标题2",Content="内容2"},         new PostModel{Title="标题3",Content="内容3"}     }; }

 

 

3、传递属性值的校验

Blazor是天生强类型,属性值的校验非常简单。而Vue中的属性值校验也麻烦些,如果不使用TS,只能支持运行时校验,使用TS,结果volar,可以支持编译时校验。

//Vue=====================================  //运行时校验 const props = defineProps({   // 基础类型检查   propA: Number,   // 多种可能的类型   propB: [String, Number],   // 必传,且为 String 类型   propC: {     type: String,     required: true   },   // Number 类型的默认值   propD: {     type: Number,     default: 100   },   // 对象类型的默认值   propE: {     type: Object,     default() {       return { message: 'hello' }     }   } }    //借助TS和volar实现编译时检验  //泛型约束 const props = defineProps<{   foo: string   bar?: number }>()  //使用接口 interface Props {   foo: string   bar?: number } const props = defineProps<Props>()  //默认值的话,比较麻烦,使用withDefault再包一层 const props = withDefault(defineProps<{   foo: string   bar?: number }>(),{   foo:'hello',   bar:10, })

//Blazor====================================  //类型、是否必填、默认值,一行搞定,而且都是c#本身的语法,不用借助API,就问你爽不爽!?  @code {     [Parameter]     public PostModel? PostModel { get; set; } = new PostModel { Title = "默认标题", Content = "默认内容" };     [Parameter]     public List<PostModel> PostModels { get; set; } }

 

发表评论

相关文章