Blazor和Vue对比学习(基础-3):属性和父传子
组件除了要解决视图层展示、视图层与逻辑层的数据绑定,还需要解决一个重大问题,就是在组件树中实现数据传递,包括了父传子、子传父、祖传孙,以及任意组件之间传值。我们上一章讲到的实现双向绑定的两个指令,Vue的v-model,Blazor的@bind,可以认为是父子组件双向传值的语法糖,后面章节我们再来实现它。
我们先从最简单的父子传值开始学习。在Vue和Blazor中,都是通过属性来实现父子组件的数据传递。我们以往都是在html标签上设置属性,属性值可以是字面量,也可以绑定逻辑数据。比如这样【<a :href="href">连接</a>】。我们现在把a标签换成一个自定义的组件,【<MyLink :href="href">链接</MyLink>】,MyLink组件会如何处理这个绑定的href值呢?我们将通过以下几点来学习父传子:
- 父子传值的基本使用
- 传递属性值的类型
- 传递属性值的校验
1、父子传值的基本使用
①步骤一:父组件中,定义子组件的标签属性,并给标签属性赋值,即可将数据传递给子组件
②步骤二:子组件中,定义用来接受父组件传值的变量(属性),肯定不能是普通的变量。Vue通过defineProps来定义(defineProps是宏命令,不需要import),Blazor通过[Parameter]特性来标注
//Vue===================================== //1、子组件Post //定义两个属性用于接收数据 <script setup> const props = defineProps(['title','content']) //如果要在代码中中使用title和content,则需要定义一个变量来接收defineProps的返回值,通过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:当传递数组、对象等引用类型时,仅仅传递了引用地址。所以,在子组件中直接修改传递过来的属性值,父组件的值也会改变。如果需要修改传递过来的属性值,建议将属性值赋值给一个新变量,再对新变量进行加工处理
- 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实现编译时检验,使用起来不是特别顺手 //方法1:泛型约束 const props = defineProps<{ foo: string bar?: number }>() //方法2:使用接口 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; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!