这章我们来学习,现代前端框架中最精彩的一部分,双向绑定。除了掌握原生HTML标签的双向绑定使用,我们还要在一个自定义的组件上,手撸实现双向绑定。双向绑定,是前两章知识点的一个综合运用(父传子、子传父),但因为又多了一层抽象,有一点小难度,需要一点时间和练习来熟悉套路,但必须要越过去。此后,基础部分就是一马平川了。此章我们分为以下几个部分来一起学习:

  • 补充:HTML标签和组件
  • HTML标签的双向绑定
  • 自定义组件的双向绑定
  • 再次认识指令属性/修饰符

一、补充:HTML标签和组件

在学习双向绑定前,我们需要进一步理解组件的本质,可以从下面两个角度:

角度1、我们定义一个组件,相当于定义一个类。在模板中使用一个组件时,比如这样<MyComponent></MyComponent>,相当于new一个实例对象,并通过标签属性进行数据赋值,实列化了,组件就具有了视图、状态、生命周期等特征。

角度2、无论Vue,还是Blazor。组件的视图模板,均由HTML和其它组件构成。其中组件成分还可以继续拆,拆到底,都是HTML。HTML是组件的根零件,到它就不可以再拆了,你只能使用它,无法窥探它的内部结构。你可以认为,组件在视图这个层面上,就是HTML的再组合。同时,组件还包括了数据和逻辑,通过绑定技术实现视图与数据的交互,再通过虚拟DOM技术实现了差量更新,提升了交互的性能。

理解了HTML标签和组件,将有助于我们学习后面的知识点。

二、HTML标签的双向绑定

我们之前使用{{}}或者@时,都只是实现了逻辑层>视图层的单向绑定,即逻辑层的数据改变时,视图层自动更新,这是不够的。比如输入框input,当我们在视图层输入值时,逻辑层的数据也应该响应新输入的值,实现自动更新,实现视图层>逻辑层的自动更新。

比如input(type为text),我们将value属性与逻辑层绑定,实现逻辑层到视图层的单向绑定。而视图层到逻辑层,则需要借助DOM事件的event对象,前面我们说过,DOM事件的回调里,会自动导入e对象。我们在回调里,直接通过e对象获得新输入的value值,然后赋值给逻辑层数据。这个过程很简单,因为不需要涉及跨组件通讯。

  1. //Vue=====================================
  2.  
  3. //通过属性绑定和事件回调,实现双向绑定,不需要在父子组件之间传值
  4. <template>
  5. <h1>逻辑层数据:{{inputValue}}</h1>
  6. <input :value = "inputValue" @input="(e)=>{inputValue = e.target.value}">
  7. </template>
  8.  
  9. <script setup>
  10. import { ref } from 'vue'
  11. const inputValue = ref('输入框初始值')
  12. </script>
  13.  
  14. //v-model可以认为是以上方式的语法糖
  15. <input type="text" v-model="inputValue"/>
  16.  
  17. //Blazor===================================
  18.  
  19. //通过属性绑定和事件回调,实现双向绑定,不需要在父子组件之间传值。获取event对象,需要指定类型,获取value值也和Vue不太一样,同时注意类型转换
  20. <h1>逻辑层数据:@inputValue</h1>
  21. <input value = "@inputValue" @oninput = "(ChangeEventArgs e)=>{inputValue = Convert.ToString(e.Value);}" />
  22.  
  23. @code {
  24. private string inputValue = "输入框初始值";
  25. }
  26.  
  27. //@bind可以认为是以上方式的语法糖
  28. //bind指令有三个属性,culture、format和event,其中enent用来指定更新时机,默认为onchang失去焦点时发生,此例修改为oninput输入时发生
  29. <input @bind = "inputValue" @bind:event = "oninput" />

三、自定义组件的双向绑定

如前所述HTML标签和组件的区别。在HTML标签中,我们可以使用原生的属性、事件及事件对象event,实现双向绑定。而组件,是一个再组合的东西,并没有原生的属性、事件及事件对象,都需要我们自己来实现。参照HTML标签的双向绑定,我们来尝试一下,思路和HTML标签是一样的,只是我们需要掰开组件,到内层去操作,所以需要进行数据的父传子和子传父。

下面的案例,我们在子组件里定义一个HTML标签:input文本框,实现子组件和父组件的逻辑数据实现双向绑定。双向绑定可以定义多个

  1. //Vue=====================================
  2. //1、父组件
  3. <template>
  4. <div class="Parent">
  5. <h1>灰色框是父组件</h1>
  6. <h1>父组件逻辑数据值:{{parentValue}}</h1>
  7. <Child :inputValue = "parentValue"
  8. @update:inputValue = "(newValue)=>{parentValue = newValue}">
  9. </Child>
  10. </div>
  11. </template>
  12.  
  13. <script setup>
  14. import Child from './components/Child.vue'
  15. import { ref } from 'vue'
  16. const parentValue = ref('父组件初始值')
  17. </script>
  18.  
  19. //2、子组件
  20. <template>
  21. <div class="Child">
  22. <h1>红色框是子组件</h1>
  23. <input :value = "inputValue" @input="childEmit"/>
  24. </div>
  25. </template>
  26.  
  27. <script setup>
  28. import {ref} from 'vue'
  29. const props = defineProps(['inputValue'])
  30. const emits = defineEmits(['update:inputValue'])
  31. const childEmit = (e)=>{
  32. emits('update:inputValue',e.target.value)
  33. }
  34. </script>
  35.  
  36. //3、下面来分析一下这个过程:
  37. //从案例中,我们可以看到,<Child>这个组件,实际上仅是起到搬运工的作用,①派出属性,将父组件的数据状态parentValue交给子组件内部的input消费;②拍出事件,将子组件内部的input新值,传递给父组件的数据状态parentValue消费。
  38. //除去Child这个外壳,实际上还是逻辑层的数据状态,在和HTML标签做交互,只是因为逻辑层数据和视图层HTML标签在不同的位置,所以需要<Child>这个桥梁!
  39.  
  40. //4、自定义组件的双向绑定,可以使用v-model语法糖吗?
  41. //可以的,但是要遵守属性和事件的命名约定,如下:
  42. //属性名:任意名称。但如果使用【v-model="parentValue】的格式,就必须命名为modelValue
  43. //事件名:update:属性名。但如果使用【v-model="parentValue"】的格式,就必须命名为update:modelValue
  44. //上面的案例,我们可以使用v-model来简化一下,但只能简化父组件哦,子组件保持不变【注意如果使用v-model的最简形式,案例中子组件的属性和事件名称改一下】
  45. <Child v-model = "parentValue"></Child>
    <Child v-model:firstValue = "parentValue1" v-model:secondValue = "parentValue2"></Child>
  1. //Blazor====================================
  2.  
  3. //1、父组件
  4. <div class = "Parent">
  5. <h1>灰色框里是父组件</h1>
  6. <h1>父组件逻辑数据值:@parentValue</h1>
  7. <Child InputValue="@parentValue" InputValueChanged="@((newValue)=>{parentValue = newValue;})"></Child>
  8. </div>
  9.  
  10. @code {
  11. private string parentValue = "输入框初始值";
  12. }
  13.  
  14. //2、子组件
  15. <div class="Child">
  16. <h1>红色框里是子组件</h1>
  17. <input value = "@InputValue" @oninput = "ChildEmit" />
  18. </div>
  19.  
  20. @code {
  21.  
  22. [Parameter]
  23. public EventCallback<string> InputValueChanged { get; set; }
  24.  
  25. [Parameter]
  26. public string? InputValue{ get; set; }
  27.  
  28. private async Task ChildEmit(ChangeEventArgs e)
  29. {
  30. await InputValueChanged.InvokeAsync(Convert.ToString(e.Value));
  31. }
  32. }
  33.  
  34. //3、分析:双向绑定的实现逻辑,和Vue基本是一样的。通过属性参数,将父组件的逻辑层数据parentValue交给子组件的input,通过EventCallback事件,将子组件input的新值,交给父组件的parentValue。本质上,还是逻辑层数据和HTML原生标签的交互,自定义组件只是玩个了寂寞。
  35.  
  36. //4、可以使用@bind的语法糖吗?肯定是可以的
  37. //一样要遵守属性和事件的命名约定,如下:
  38. //属性名称:任意名称
  39. //EventCallback事件名称:属性名称Changed
  40. //上面案例子组件不做改动,父组件可以简写为:
  41. <Child @bind-InputValue="parentValue"></Child>

四、再次认识指令属性/修饰符

虽然是再次认识,但仍旧不打算深入,对于Blazor的指令属性,或Vue的事件修饰符,我认为即使已经开始进行生产应用的开发,都仅需要掌握用法即可,不需要深入内部的实现甚或自己来实现一个。所以,下面仅是一个使用方法的汇总

1、Vue的修饰符,常用的主要有v-on类修饰符和v-model类修改符

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

(1)v-on类修饰符

①prevent:阻止默认行为。HTML标签a的默认行为“打开链接”,被阻止执行

<a href=”http://www.hiwork.xyz” @click.prevent=”show”>

②stop:阻止事件冒泡。如果没有stop,点击div2时,div1也会被执行。

<div id = "div1"@click = "show1">
    <div id= "div2" @click.stop = "show2"></div>
</div>

③capture:事件从外层开始执行。事件正常从内层开始执行(即冒泡),show2>show1。在外层使用capture后,从外层开始执行,show1>show2

<div @click.capture = "show1">
    <div @click = "show2"></div>
</div>

④once:事件只触发一次。无论点击按钮多少次,show1都只在第一次点击时执行。

<button @click = "show1"></button>

⑤self:只有事件target是自己时才触发事件。点击div2时,按冒泡顺序,show1在show2之后执行,但因为div1使用了self,所以点击div2时,show1不会执行。

<div id="div1" @click.self = "show1" style="height: 100px;width: 100px;background-color: aquamarine;">
    <div id="div2" @click = "show2" style="height: 50px;width: 50px;background-color:blue;"></div>
</div>

⑥⑦passive/native:这两个极少用,但文档吧

(2)v-model类修饰符,如<input v-model.number = "count" />

①number:将输入值转为数值

②trim:去除输入值首尾空格

③lazy:输入框失去焦点时再更新

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2、Blazor的指令/事件属性,即少又难用,不知道未来是否会改进。主要有DOM事件的属性,Bind指令属性。另外,指令属性的使用也比较奇葩,需要重复申请,见案例

(1)DOM事件属性

①preventDefault,阻止HTML标签的默认行为,同Vue的prevent

<a href = "http://www.hiwork.xyz" @onclick = "Show1" @onclick:preventDefault></a>

②stopPropagation,组止冒泡,同Vue的stop

<div id = "div1" @onclick = "show1">
    <div id= "div2" @onclick = "show2" @onclick:stopPropagation></div>
</div>

(2)Bind指令属性

①event,指定双向绑定视图更新逻辑的时机,是失去焦点时更新onchange(默认),还是实时更新oninput

<input @bind ="parentValue" @bind:event="oninput"/>

②format,指定双向绑定的日期格式

<input @bind="StartDate" @bind:format="yyyy-MM-dd" />

③culture,指定语言,没有用过,查文档吧

Blazor和Vue对比学习(基础1.5):双向绑定的更多相关文章

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

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

  2. Blazor和Vue对比学习(基础1.2):模板语法和Razor语法

    Vue使用模板语法,Blazor使用祖传的Razor语法,从逻辑和方向上看,两者极为相似,比如: 都基于HTML 都通过声明式地将组件实例的状态(数据/方法)绑定到呈现的DOM上 都通过指令实现更加丰 ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 如何实现集群中的 session 共享存储?

    Session 是运行在一台服务器上的,所有的访问都会到达我们的唯一服务器上,这 样我们可以根据客户端传来的 sessionID,来获取 session,或在对应 Session 不 存在的情况下(s ...

  2. ACL 权限控制机制?

    UGO(User/Group/Others) 目前在 Linux/Unix 文件系统中使用,也是使用最广泛的权限控制方式.是一种粗 粒度的文件系统权限控制模式. ACL(Access Control ...

  3. 插值方法 - Lagrange插值多项式

    Lagrange插值多项式代码: 1 # -*- coding: utf-8 -*- 2 """ 3 Created on Wed Mar 25 15:43:42 202 ...

  4. PCB中的生产工艺、USB布线、特殊部件、蓝牙天线设计

    PCB中的生产工艺.USB布线.特殊部件.蓝牙天线设计 (2016-07-20 11:43:27) 转载▼     PCB生产中Mark点设计 1.pcb必须在板长边对角线上有一对应整板定位的Mark ...

  5. "双非"应届生校招如何获得大厂青睐?(内附前端大厂面经+技术岗超全求职攻略)

    写在前面的话 笔者从17年的2月份开始准备春招,其中遇到不少坑,也意识到自己走过的弯路.故写了这篇文章总结一番,本文适合主动学习的,对自己要学的课程不明确的,对面试有恐惧症的...等将来打算从事技术岗 ...

  6. jQ模拟打字效果插件typetype

    typetype是一个jquery插件,可以模拟人类的打字效果. 效果图如下所示: 查看演示 http://weber.pub/demo/160828/jQuery.Type/jQuery.type. ...

  7. Android Studio登陆界面+Button不变色问题

    今日所学内容: 1.初始相对布局 2.AS登录界面 3.一个可以下载小图标的阿里的网站iconfont-阿里巴巴矢量图标库 用GitHub账号绑定就可以免费下载 4.取颜色工具ColorCop 遇到的 ...

  8. 小程序wx.previewImage查看图片再次点击返回时重新加载页面问题

    wx.previewImage预览图片这个过程到底发生了什么? 首先我们点击图片预览,附上查看图片代码: <image class="headImg" data-src=&q ...

  9. 微信小程序animation动画2种方法

    这里介绍 2 种方法一种是常规的小程序方法操作,另一种是引入动画库 1. 常规动画操作设置 wxml: <view> <view bindtap="clickMe" ...

  10. 使用Object.Defineproperties改变对象数据结构

    此方法设置键的时候如果需要使键为变量则需要加中括号[]  如下 let addKeys = Number(keys[keys.length - 1]) + 1 Object.assign(this.t ...