最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

实时焦点:一次学俩Vue&Blazor:1.4基础-响应式数据

来源:博客园


(资料图片仅供参考)

一、声明式编程和响应式数据

1、声明式编程

  • 逻辑层修改视图层元素属性值的方式有两种,一是命令式,先通过getElementById等方法获取元素对象,然后再修改对象的属性;二是声明式,先将视图层元素的属性值和逻辑层数据绑定,通过修改逻辑层数据,实现视图层元素属性值的自动更新。
  • 现代前端开发框架,都采用声明式。

2、响应式数据

  • 使用声明式编程的开发框架,需要通过特定的机制通知视图层更新。
  • Vue通过Proxy代理机制,劫持读取或修改数据的行为,进而通知使用到数据的UI节点进行更新,被Proxy代理的数据,就称之为响应式数据,在组合式API中,Vue提供了ref和reactive两个API来创建响应式数据。
  • 而Blazor中的字段或属性,不需要特殊处理,天然具有响应式特性,其内在机制,暂不清楚。.NET的另一个响应机制MVVM,则是通过事件机制,来通知UI层更新。

二、Vue定义响应式数据的方法

Vue提供reactive和ref两个API来创建响应式数据,只有响应式数据才具有通知更新功能。实际应用中,有几个点需要特别注意:

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>

4、当使用ref创建对象类型时,会调用reactive来创建value属性,类似于这种感觉ref(reactive(value))。当整体替换value值时,新值仍然是响应式的,而reactive如果整体替换新值,则会失去响应性。

  • 在实际应用中,创建对象数组类型时,推荐使用ref,因为ref创建的对象,使用数组的map、filter、reduce等返回新数组的方法时,新数组仍然可以保持响应性。
  • 使用模块化开发时,export出来的数据,也应该使用ref,这样在引用这个API时,解构出来的数据仍然具有响应性。
  • 官方文档有一句话“为了解决reactive带来的限制,Vue 也提供了一个ref方法来允许我们创建可以使用任何值类型的响应式ref”。创建响应式数据时,除了对象类型,其它类型都请尽量使用ref,虽然.value麻烦点。
//整体替换,a失去响应性const a = reactive({name:”MC”,age:18})a = reactive{name:”Fun”,age:16}//ref可以实现响应式替换,b仍具有响应性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,即使使用filter等方法,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})

5、Vue的响应式原理

无论是选项式API的date()方法,还是组合式API的ref和reactive,都会将数据包装为Proxy对象。如果熟悉C#的属性,代理机制其实很简单。

//需要被代理的数据const obj = {  name:"functionMC",  age:18}//当读取或修改数据时,指定代理的行为//当读取数据时,调用get方法; 当修改数据时,调用set方法//参数说明:target-被代理的对象、prop-读取的属性、receiver-代理对象、value-新值const handler = {  get(target,prop,receiver){        //通过代理读取属性时,在返回值之前,它会做一个跟踪的操作,标记哪些地方用到了这个数据    //track(),追踪谁用了这个属性......    return target[prop]  },  set(target,prop,value,receiver){    target[prop] = value    //通过代理修改值之后,做一些其它操作    //trigger(),触发所有使用了该值的位置进行更新  }};//为数据obj,创建一个代理对象proxy//之后对数据obj的读取和修改,都通过代理proxy来完成const proxy = new Proxy(obj,handler)

三、Blazor中的响应式数据

Blazor中,字段和属性天然具有响应性,对象也是深层次绑定。利用属性的getter和setter方法,可以对响应式数据进行更复杂的控制。

@page "/"

@Num

增加

@employee.Name

更改名称

@employee.Address.City

更改城市@foreach (var sport in sports){

@sport

}增加运动@code{ //值类型的属性绑定 public int Num { get; set; } //对象类型的字段绑定(深层次响应) private Employee employee = new Employee { Id = 1, Name = "functionMC", Address = new Address { Province = "广东", City = "广州" } }; //集合类型对象的字段绑定 private List sports = new List { "Running", "Swiming", "BasketBall" }; private void AddNum() { Num++; } private void ChangeName() { employee.Name = "MC"; } private void ChangeCity() { employee.Address.City = "深圳"; } private void AddSport() { sports.Add("FootBall"); }}

关键词: 创建对象 声明式编程 元素属性