1.Vue2源码细读-new Vue()初始化
2.Vue—关于插件(源码级别的局部局钩插件分析+实践)
3.blazor组件生命周期
Vue2源码细读-new Vue()初始化
Vue.js 是一个数据驱动的前端框架,其核心是钩源通过数据生成视图,开发者更关注数据模型与流转而非视图生成。码全
从 new Vue() 开始,和局我们将探索 Vue 实例的部钩创建过程。新创建的局部局钩拼音小程序源码 Vue 实例本质上是一个 Vue 的实例对象。Vue 作为构造函数,钩源只能通过 new 操作符创建实例,码全核心功能是和局调用初始化方法 _init,并传入参数。部钩
Vue 的局部局钩实现中,构造函数定义了多个 mixin,钩源这些 mixin 被挂载到 Vue.prototype,码全以降低耦合度,和局便于维护。部钩初始化流程包括多个模块的挂载,如初始化、数据状态、事件发布订阅、生命周期与渲染。
初始化过程主要分为三个阶段:手动调用场景和组件场景。手动调用场景指直接创建的 Vue 实例,优先级高于组件场景。组件场景涉及全局或局部注册的htran 2.4 源码组件,组件创建和继承通过 Vue.extend 实现。
组件创建过程中,Vue.extend 用于获取组件构造函数,createComponent 则生成初始的 VNode。组件实例的创建发生在 patch 过程中,此时调用 init 钩子,真正创建组件实例。
组件实例的 options 包含组件配置,通过对象赋值保存到实例中。在组件场景中,initInternalComponent 函数处理组件实例的初始化,包括设置组件选项和相关属性。
综上所述,new Vue() 过程涉及构造函数的初始化、混合功能的挂载、配置的合并与组件的创建。这一过程在后续篇章中将详细分析。
参考资料:
Vue—关于插件(源码级别的插件分析+实践)
Vue插件的原理基于Vue的`use`方法,该方法接收一个函数或者提供`install`方法的对象作为参数,如果传入的参数是函数,这个函数会被当作`install`方法。在Vue 2.6.版本中,`use`方法内部使用`initUse`函数给Vue添加了一个静态方法`use`。android 刷卡源码以vuex为例,它暴露了一个`install`方法,通过`Vue.use(vuex)`来安装插件。vuex的`install`函数会调用`applyMixin`函数,并将Vue传递过去。`applyMixin`函数在Vue 2.x版本中会直接使用`Vue.mixin`来扩展功能,通过在组件的`beforeCreate`钩子中初始化vuex插件。
在Vue中使用混入(mixin)是一种设计模式,可以轻松地被子类继承功能,目的是实现函数复用。Vue中也应用了这一设计模式,通过`Vue.mixin`可以用来分发可复用逻辑。混入可以分为全局混入和局部混入,全局混入会影响所有的Vue实例,如果组件中与mixin中具有同名的属性,会进行选项合并,除了生命周期外,其它的所有属性都会被组件自身的属性覆盖。使用混入可以节省代码量,类似于类继承。
要自己实现一个提示框插件,可以通过`this.$notify()`进行调用,并且可以传入自定义模板。android sns 源码创建一个Vue工程,在`src`目录下新建`plugin`目录,然后创建一个`notify`目录,新建`index.js`和`Notify.vue`。在`index.js`中,引入`Notify.vue`组件,并通过`install`方法中注入的Vue来完成功能。实例挂载之后才可以访问`$el`选项,可以通过`Vue.use`来使用插件,然后在App.vue中验证功能是否正常。要实现传入模板并且显示出来,可以通过`$mount` API手动挂载一个实例,并在调用`$notify`方法时将挂载的元素插入到文档中。通过创建Vue组件,将DOM、JS、Style都创建好,最后调用`$notify`方法将组件插入到页面中。要实现传入模板,可以使用`v-html`指令来插入模板,并在Notify.vue中新增接收参数的方法。在App.vue中传递一段模板,页面上操作的wordpress 源码解读效果为显示提示框,两秒后消失。
blazor组件生命周期
翻译自: Component lifecycles
blazor组件包含一组虚方法,我们可通过重写这些方法来影响应用行为。这些方法会在组件生命周期的不同阶段执行。以下图展示了生命周期钩子方法的执行流程:
SetParametersAsync 方法在每次父组件渲染时执行。
传递给组件的参数被包含在ParameterView结构体中。这是根据传递到组件的状态对服务器进行异步调用的好时机。
原文:Parameters that were passed into the component are contained in a ParameterView. This is a good point at which to make asynchronous calls to a server (for example) based on the state passed into the component.
在重写的SetParametersAsync中调用base.SetParametersAsync(parameters)时,组件的[Parameter]修饰属性会被赋值。
此方法也适合为参数分配默认值,更多细节请参考 Optional route parameters。
OnInitialized / OnInitializedAsync 方法在为组件的[Parameter]属性赋值后执行。与SetParametersAsync类似,但可以使用组件状态。
这些方法仅在组件创建时执行一次。如果父组件稍后更改了组件的参数,则这些方法会被跳过。
注意:当组件是一个@page时,且Blazor应用在新的URL下重新渲染此@page,Blazor会重用此@page。因为它是同一个对象,Blazor不会调用IDisposable.Dispose方法,也不会执行OnInitialized方法。
这句话我就没有理解明白,我做了一个实验,一个@page组件有两个路由,一个是/page-one,另一个是/pageone,那么这两个路由来回跳转的话不单单不会执行OnInitialized,其他的方法也不会执行啊。
OnParametersSet / OnParametersSetAsync 方法在组件的新实例中,在OnInitializedAsync之后立即执行。如果它是一个已存在的组件,因为父组件正在重新呈现,所以OnInitialized*方法会被跳过,而这个方法将在SetParametersAsync之后立即执行。
StateHasChanged 方法会标记组件即将被渲染。
当组件希望通知Blazor发生了可能导致呈现输出不同的更改时,将调用此方法。例如,在一个Clock组件中,我们可以设置一个循环的1秒计时器,然后执行StateHasChanged以重新呈现正确的时间。
另一个用途是指导Blazor通过异步方法部分地执行重渲染。
ShouldRender 方法可以通过返回false来阻止组件的RenderTree被重新计算。注意,在第一次创建和呈现组件时,不会执行此方法。
例如,当我们知道我们的状态自上次渲染以来没有改变,或者只是以一种会导致相同输出被渲染的方式改变时,指示Blazor不要经过BuildRenderTree过程可以节省处理时间并改善用户体验。
这个方法不会在组件第一次被渲染的时候执行
BuildRenderTree 方法将应呈现给用户的内容放入内存中(虚拟DOM,即RenderTree)。
上述代码中,向渲染树添加一个h1,内容为“People”。然后它将为people变量中的每个currentPerson局部变量创建一个ShowPersonDetails的新实例。
如果我们的组件在稍后的时间重新渲染,在people中添加一个额外的项,那么ShowPersonDetails组件的一个新实例将被创建并添加到组件的RenderTree中。如果人的条目减少了,那么之前创建的一些ShowPersonDetails组件实例将从组件的RenderTree中被丢弃,如果它们实现了IDisposable, Dispose()将对它们执行。
注意:为了更有效地执行渲染,当在一个循环的上下文中执行渲染时,任何时候都应该添加一个 @key 指令
OnAfterRender / OnAfterRenderAsync 这最后两个方法在Blazor重新生成组件的RenderTree时执行。这可能是由于组件的父组件重新呈现,用户与组件交互(例如鼠标点击),或者组件执行它的StateHasChanged方法来调用重新呈现的结果。
这些方法只有一个名为firstRender的参数。只有在当前组件上第一次调用该方法时,该参数才为true,此后它将始终为false。在需要附加组件连接(例如,通过JavaScript)的情况下,知道这是第一次呈现是很有用的。
只有在OnAfterRender方法执行之后,才可以安全地使用通过@ref指令设置的对组件的引用。
同样的,直到OnAfterRender方法已经执行firstRender设置为true,才可以安全地使用任何通过@ref指令引用的HTML元素集。
Dispose 尽管这不是严格意义上的ComponentBase生命周期方法之一,但如果一个组件实现了IDisposable,那么一旦该组件从其父渲染树中移除,Blazor就会执行Dispose。为了实现IDisposable,我们需要在razor文件中添加@implements IDisposable。
Awaiting within Async lifecycle methods/在异步的生命周期方法中等待
值得注意的是,Blazor将尽可能快地触发渲染,而不是等待长时间运行的异步方法完成后才能呈现组件。
这使得组件能够在执行后台任务(如从服务器检索数据)时为用户呈现内容。
单个方法的等待行为SetParametersAsync
注意:如果重写了该方法,基类的SetParametersAsync方法必须在方法中的任何await指令之前执行,否则将抛出InvalidOperationException。
OnInitializedAsyncOnParametersSetAsyncOnAfterRenderAsync
(记住上述逻辑的一个)简单的规则是SetParametersAsync是唯一不能通过等待任务挂起生命周期进程的方法(观察SetParametersAsync的源码会发现,这个方法中根本就没有await任何东西,所以。。。)。
所有其他异步方法都可以挂起生命周期进程,直到执行退出该方法,而第一个await将导致通过BuildRenderTree进行渲染,以防止用户不得不等待查看更新。
OnRenderAsync可能看起来有些异常,因为它在两种情况下(第一次await时和退出方法时都没有什么动作)都不执行进一步的操作。如果我们考虑到渲染是执行链的最终目标这一事实,那么我们可以将渲染视作是执行链的最终结果,而不是什么都不做。至于在await上渲染,如果需要,那么程序员必须通过调用StateHasChanged来显式地完成(这个方法中调用StateHasChanged,我实在想不出什么场景能够做这样的操作,关键是容易出现渲染无限循环),否则OnAfterRenderAsync中将导致一个无限循环。
OnAfterRenderAsync这个方法在ComponentBase的源码中它直接了Task.CompletedTask
异步方法和多个await
在async方法中,Blazor执行的代码只会在第一次等待时执行。随后的await不会导致多个渲染。例如
上述例子是原文中的,可能并不好懂,我们来写一个更好懂的:
在上述代码中,如果我没有添加任何StateHasChanged()的话,那么在整个方法结束时页面上会输出_count的值是3,但是中间的变化过程会被忽略掉。
如果我们想要在额外的点上呈现,那么我们必须在所有额外的await语句之前调用StateHasChanged。
有关如何在同一组件上运行不同线程时安全工作的更多信息,请参阅多线程呈现一节。Multi-threaded rendering.