vue实践小结之mvvm学习

MVVM是Model-View-ViewModel的简写。微软的WPF带来了新的技术体验。本文主要和大家分享vue实践小结之mvvm学习,希望能帮助到大家。

1 mvvm 学习

1.1 实现原理

mvvm类框架的实现原理不复杂,大致如下:

模板分析得到依赖的属性

通过某种变动监测手段监测这些依赖的属性

当属性变动的时候,触发相应的directive的处理逻辑即可

实际上,directive的处理逻辑不一定是对view进行操作,比如上报。但是,在mv的思想下,建议对view的操作都集中在directive里实现

从最核心上看,mv思想仅仅是一个观察者模式的具体应用于延展而已

1.2 核心技术点

1.2.1 模板分析

模板分析是比较基础的,凡是和view相关的基本都会涉及模板,这是原始资料,这里的关键点是模板来源的问题,实际上,它应该可以是任何字符串

这里暗示了框架需要一个模板解析器,不管这个解析器复杂还是简单,它都处于一个模式:【输入 –> 模板引擎 –> 输出】

于是,mvvm的模板解析器特点如下:

输入:任何符合规则的字符串

输出:需要监听的data.attr,directive,filter

在设计一个框架的时候,如果想要有更好的可扩展性,则

输入应该足够灵活,从来源上来说,模板可以是someDomHere.html(),也可以是动态输入,那就更有可适用性;从内容上来说,如果引擎可以识别更高级的语法,那就更有功能性

输出应该足够收敛,收敛的意思是有限并规则,像mvvm框架,最后出来的只是directive和filter,具体的处理都集中在这两个概念中,仅扩展这两个概念,即可对系统进行扩展

1.2.2 变动监测

在众多mvvm类框架中,实现变动监测有3种:

门面方法setter,getter:比如knockout,q。限定可以变动的入口,并且让入口使用权放给用户来决定。

利用defineProperty:比如vue,avalon。本质上也是setter,getter,但是没有把入口使用权放给用户来决定。

dirty check:比如angular。对angular的研究够多了,这里也不赘述了。

1

2

3

4

5

6

7

8

9

10

11

//方式1 vs. 方式2//方式1:vm.$set(aaa, 1);    //会触发变动逻辑vm._data.aaa = 2;   //不会触发变动逻辑,不过这不是框架希望的操作,可以被hackvm.$get(aaa);       //2//方式2:vm.aaa = 1;         //一定会触发变动逻辑vm._data.aaa = 2;   //也可以找到内部的data进行修改,但是没用vm.aaa;             //1

登录后复制

1.2.3 小结与延伸

对一类复杂并且常见的问题进行分析,解耦,抽象,在实践的过程中获得广泛的认可,那就形成了一种模式,mvvm也是一种模式,它不一定叫mvvm模式,这也不是笔者能决定的

对于这个模式的核心,笔者理解如下:系统根据配置得到了对某些数据源的某些处理规则,当数据源变动时就会引发相应的处理规则。模式的扩展是双向性,这由系统实现来决定,当符合某些规则的时候,可以对数据源进行更新。

我们跳出view的概念禁锢,联想实现一个监控系统,其实这个模式非常适合用在监控系统上面。

一般的监控系统的处理逻辑是:由收集源对监控数据进行收集整理,然后存储到数据库中,监控系统实时监控数据源,绘制实时的图线(反馈),当数据源发生了符合某些规则的变动时,就会触发相应的动作,比如报警。

如何实现这个系统,让系统具有更高的扩展性?参考mvvm模式,可以这样:

收集系统独立于监控系统,各不相同,暂且不论。监控系统通过某些配置文件取得需要监控的数据源与相应的处理逻辑规则,当数据源发生变动时触发相应的处理。

按照mvvm模式,进行一些抽象。

数据源不一定限定在数据库中,他可以在任何地方,只需要系统可以通过某些可配置的规则获取得到

处理规则进行抽象,让它更容易被扩展,比如发邮件,发短信,发微信,发qq消息等等

对应前端的mvvm框架,模板就是配置文件,directive就是处理规则,data对应数据源。

当系统需要新增一个数据源的时候,只需要更新配置文件,让系统读取即可启动数据监控

当需要新增一个处理规则的时候,可以通过一个热插拔的处理规则插件系统,扩展一个新的处理规则,再更新配置文件,系统即可接受新的处理规则

2 vue实践

vue介绍就不用了,太多资源了。这里讲述一下vue实践过程中的一些收获

2.1 组织结构

1

2

3

4

5

6

7

8

9

10

11

12

13

14

+ src

     +– common

           +– vue

                +– coms

                +– directives

                +– filters

                +– vue.js

                +– vue.ext.js

     +– pages

           +– index

                 +– index.js

                 +– vue.ext.js

                 +– xxx.mixin.js

2.2 Vue扩展

vue的扩展非常方便,与vue相关的资源都放置在src/common/vue/下面,比如coms(组件),directive,filter

src/common/vue/vue.ext.js是对vue进行全局公共的扩展,对于所有页面共有的扩展放在这个文件下面,内容如下:

vue实践小结之mvvm学习

可以看到,扩展vue库本身有4个扩展点:

扩展Vue库的全局方法/属性,方式:Vue.xxx = …

扩展Vue实例的方法/属性,方式:Vue.prototype = …

扩展directive,方式:Vue.directive(‘directiveName’, options);

扩展filter,方式:Vue.filter(‘filterName’, function(){});

立即学习“前端免费学习笔记(深入)”;

对于页面单独需要的扩展,集中在src/pages/pageName/vue.ext.js里面,形式与全局的vue.ext.js一样

在实例化Vue的过程中也有许多可以扩展与优化的地方,在实践过程中只是应用了mixin功能,其他的可以慢慢深入

mixin的作用是在实例化Vue的时候混入一些功能,它可以混入许多特性,格式与实例化Vue时用到的option格式一样,比如index页面的mixin.js的内容如下:

vue实践小结之mvvm学习

这个mixin混入了两个方法,多个Vue实例共享的options可以放置到mixin中,从而避免了代码重,比如在实例化Vue的时候这样使用mixin:
vue实践小结之mvvm学习

可以看到mixin是个数组,因此可以同时使用多个mixin

实际上这里的mixin主要不是为了避免代码重复(实践的时候只是这样用),mixin是一种模式,一个mixin内聚了实现一项功能的方法/属性集合,在定义/生成实例的时候,通过混入mixin就可以让该实例拥有某项功能,归根结底是组合vs继承问题的产物

2.3 vue组件插入问题

2.3.1 首屏

对于首屏的vue组件,直接把模板放在主页面中即可,初始化的时候只需要把el参数传入,Vue就会用el的html作为模板来初始化Vue实例:

vue实践小结之mvvm学习

这里需要注意的是在模板中不能使用{{}},否则在还没初始化之前,页面会显示奇怪的东西,比如:

1

2

3

4

5

6

7

hello, {{name}}

      vue实践小结之mvvm学习"{{imgSrc}}" />    <!--初始化前,会报错,can not find http://xxx.com/{{imgSrc}}--> 

"'hello, '+name">hello

vue实践小结之mvvm学习"src: imgSrc" />

登录后复制

 

{{}} 只是一个语法糖,不建议使用

2.3.2 非首屏

对于非首屏的组件,使用vue的方式和原始方式差不多,先生成节点,然后append,譬如:

vue实践小结之mvvm学习

el参数可以接收query string,也可以直接是一个dom节点,如果是dom节点则直接编译dom的内容。如果dom节点不在文档树中,则利用vueObj.$appendTo方法将vue实例的根节点插入到文档树中

上面这种方式是在页面中没有组件的【坑】的情况下使用的,如果页面为组件留了【坑】,比如:

1

2

class=”hotRecord” id=”js-hotRecord”>

 

那么,我们可以这样初始化vue实例:

vue实践小结之mvvm学习

利用template参数传入模板,并指定el,那么vue实例在初始化之后就会自动把内容插入到el中

通过vue实现组件的主要核心也就这些,更方便的组件写法也只是对这些进行封装

2.4 自定义 directive

在vue中自定义directive是非常简单明了的,要自定义一个directive,可以注册3个钩子函数:

bind:仅调用一次,当指令第一次绑定元素的时候。

update:第一次调用是在 bind之后,用的是初始值;以后每当绑定的值发生变化就会被调用,新值与旧值作为参数。

unbind:仅调用一次,当指令解绑元素的时候。

下面简单介绍一个自定义directive——lazyload:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

function addSrc(){}function load(){} module.exports = {    bind: function() {        if (!hasBind) { //全局事件只绑定一次            hasBind = true;            (document.querySelector('.z-scroller') || window).addEventListener('scroll', T.debounce(load, 100), false);        }        //这里也可以使用data属性来获取        var defaultSrc = this.el.getAttribute('data-defaultsrc');        if (defaultSrc) addSrc(this.el, defaultSrc);    //先使用默认图片    },    update: function(src) {        //directive初始化时,会调用一次bind和update,bind没有传入src,只有update才会传入src        //因此只能在update这里拿到需要lazyload的src        //lazyload不允许修改src,这里限制只会执行一次update,防止src被修改造成的影响        //注:接受src改变可以实现,只是需要一些复杂的处理,这里为了简单起见不让src改变        if (this.init) return;          this.init = true;         //如果图片已经加载了,就不需要注册了,这里也可以使用data属性来区分        var isLoad = parseInt(this.el.getAttribute('data-isload'));        if (isLoad) return;         //注册需要lazyload的图片        list[index++] = this;        list[index++] = src;    }    //这里有一个最大的问题:由于有local的存在,会创建两个一模一样的lazyload directive    //按理说应该定义一个unbind,但是在unbind中找到并除掉local创建出来的lazyload directive会比较麻烦    //因此在load函数里面做了一个处理:如果发现需要lazyload的节点不在文档树中,则剔除掉这个lazyload    //通过这个直接省掉了unbind函数};

登录后复制

 

自定义filter也很简单,只是定义一个处理函数而已,这里就不多介绍了

2.5 实践过程中的痛点与小技巧

2.5.1 没有事件代理

用习惯了事件代理,突然没有了会有点不习惯,但是回头想想,事件代理真的很重要吗?还是说我们只是习惯了事件代理而已?

通过vue注册相同的事件并不费事。另一个问题,只要事件不多,大约不超过50,100,也不至于耗掉很大的内存,因此有时候还真不需要事件代理。如果真的需要,也只是实现一个contain方法而已

2.5.2 没有if-else的奇怪

最初看到下面的代码真的会觉得很奇怪

1

2

3

if=”hasTitle”>xxx

if=”!hasTitle”>xxx

 

2.5.3 单值

虽然vue有语法解析器,可以在directive的值中使用表达式,但是当出现一个复杂的表达式时,会污染模板,让代码可读性变得很差,又或者,表达式完成不了这个任务的时候。

因此,在mvvm实践的过程中,深深地发现,利用单值(最多只用一个?:表达式)来写模板会让代码变得很清晰,更加可读,增加代码的可维护性,而且这也更符合mvvm的核心思想:f(state) = view

有些库连语法解析器都没有,比如q,但也能很好的工作。

那么,复杂的操作放在哪里呢?

对于不会变的值来说,也就是常量,要在初始化之前完成处理

对于会变的值来说,把复杂的操作放在filter里面,在filter里面不仅可以进行复杂处理,甚至可以同时应用到其他字段,这不完全等同于computed attribute

2.5.4 替代 $(document).on

用jquery/zepto的时候,习惯了用$(document).on来充当一个全局的事件代理,在使用vue的时候,需要抛弃zepto,因此需要解决这个问题

因为vue实例本身就有event功能,因此这里解决的办法是创建一个全局的空vue对象,把它作为全局的事件代理:

1

2

3

4

5

6

7

8

9

//common/vue/vue.ext.js 回头看前面对该文件的介绍可以看到这句

Vue.noopVue = new Vue({});

 

//a.js

Vue.noopVue.$on(‘someEvent’, function() {});

 

//b.js

Vue.noopVue.$emit(‘someEvent’, [opts]);

3 总结

虽然,最后在付出产出比权衡中放弃了对现有项目的vue改造,但是这并不妨碍我们研究mvvm类框架

mvvm模式还是值得我们去深入学习的,而在实践中,我们也能学习到许多

用一种不一样的思想和思维去开发的体验也会令我们在看待问题,处理问题的道路上有所收获。

相关推荐:

Angularjs如何实现mvvm式选项卡?案列+代码

js实现一个简单的MVVM框架示例分享

什么是MVVM架构和数据绑定?

以上就是vue实践小结之mvvm学习的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2783710.html

(0)
上一篇 2025年3月8日 16:53:34
下一篇 2025年3月8日 16:53:42

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 怎样用代码直观的表示mvvm原理

    这次给大家带来怎样用代码直观的表示mvvm原理,用代码的表示mvvm原理的注意事项有哪些,下面就是实战案例,一起来看一下。 nbsp;html>        Document                             …

    编程技术 2025年3月8日
    200
  • react.js的学习

    这次给大家带来react.js的学习,react.js学习的注意事项有哪些,下面就是实战案例,一起来看一下。 react本质上是一个状态机,可以帮助开发者管理复杂的随时间变化的状态。它以一个精简的模型实现了这一点,react只关心两件事: …

    编程技术 2025年3月8日
    200
  • 使用DOM的一些小结

    这次给大家带来使用dom的一些小结,使用dom的注意事项有哪些,下面就是实战案例,一起来看一下。 DOM是语言中立的API,用于访问html,xml文档。DOM1级将html和xml文档形象的看作为一个参差画的节点树,可以使用javascr…

    编程技术 2025年3月8日
    200
  • ajax的学习笔记

     这次给大家带来ajax的学习笔记,使用ajax的注意事项有哪些,下面就是实战案例,一起来看一下。 XMLHttpRequest原型对象:   let xhr = new XMLHttpRequest();  //new一个XMLHttpR…

    2025年3月8日 编程技术
    200
  • vue中的provide/inject的学习

    本次的文章给大家分享了关于vue中的provide/inject的学习,希望可以帮助到有需要的朋友 前言 最近在看element-ui的源码,发现了一个这样的属性:inject.遂查看官网provider/inject provider/i…

    2025年3月8日
    200
  • 新手入门如何学习vue

    这次给大家带来新手入门如何学习vue,新手入门学习vue的注意事项有哪些,下面就是实战案例,一起来看一下。 一、vue是什么 Vue 是一套用于构建用户界面的 渐进式框架 。 压缩后仅有17kb 二、vue环境搭建 你直接下载并用 标签引入…

    2025年3月8日
    200
  • qps统计方法小结

    这次给大家带来qps统计方法小结,qps统计方法的注意事项有哪些,下面就是实战案例,一起来看一下。 统计最近N秒内的QPS值(包括每秒select,insert等值) mysql> select variable_name,sum(p…

    编程技术 2025年3月8日
    200
  • JS排序算法小结

    这次给大家带来JS排序算法小结,使用JS排序算法的注意事项有哪些,下面就是实战案例,一起来看一下。 关于排序算法的问题可以在网上搜到一大堆,但是纯 JS 版比较零散,之前面试的时候特意整理了一遍,附带排序效率比较 1.冒泡排序 var bu…

    编程技术 2025年3月8日
    200
  • 使用JS经验小结

    这次给大家带来使用JS经验小结,使用JS的注意事项有哪些,下面就是实战案例,一起来看一下。 鉴于时不时,有同学私信问我怎么学前端的问题。 这里统一回复一下,如下次再遇到问我此问题同学,就直接把本文链接地址发给你了。 首先说句题外话。关于有人…

    编程技术 2025年3月8日
    200
  • 简单易懂,javascript自学学习笔记

    下面是我给大家整理的javascript自学学习笔记,有兴趣的同学可以去看看。 第一章一、JavaScript概述JavaScript是基于对象和事件驱动的脚本语言,主要应用在客户端。特点:1.交互性(它可以做的就是信息的动态交互)2.安全…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论