精华内容
下载资源
问答
  • 2019-02-24 15:59:15

    前言

    目录整理:
    设计模式在vue中的应用(一)
    设计模式在vue中的应用(二)
    设计模式在vue中的应用(三)
    设计模式在vue中的应用(四)
    设计模式在vue中的应用(五)
    设计模式在vue中的应用(六)

    为什么要写这些文章呢。正如设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结(来自百度百科)一样,也是想通过分享一些工作中的积累与大家探讨设计模式的魅力所在。
    在这个系列文章中为了辅助说明引入的应用场景都是工作中真实的应用场景,当然无法覆盖全面,但以此类推也覆盖到了常见的业务场景



    观察者模式对我们来说应该不陌生,对vue原理稍微有点了解的都知道通过Object.defineProperty 拦截数据的 get/set ,在set中收集依赖Watcher,在get中触发更新Watcher.notify(),这里就是观察者模式的应用

    观察者(Observer)模式与发布(Publish)/订阅(Subscribe)的关系
    他们的行为方式相似add,notify/trigger,最明显的区别是观察者add一个具体观察者对象,发布/订阅add一个订阅事件

    // 观察者
    class Observer {
      update () {}
    }
    
    const Observer1 = new Observer()
    Subject.add(Observer1)
    Subject.notify()
    
    // 发布订阅
    Publish.add('event1',function Subscribe() { 
      ...do something 1
    })
    Publish.add('event1',function Subscribe() { 
      ...do something 2
    })
    Publish.add('event1',function Subscribe() { 
      ...do something 3
    })
    Publist.trigger('event1')
    复制代码

    一、场景

    • 两个form表单——发票信息和邮寄信息
    • 邮寄信息表单只在选中增值税专用发票时才需要
    • 提交按钮需在所有存在的表单(一个或者两个)验证通过后才有效,也就是在点击提交按钮后获取表单的验证结果和输入框的值

    二、分析

    大多数情况我们遇到的场景是一个表单对应一个提交按钮,现在的场景是一个提交按钮控制N个(大于1)且数量不可控的表单,我们可以借助观察者模式解决这个问题

    将表单对象(组件)作为观察者,点击提交按钮notify所有观察者(表单)获取值

    三、设计

    // invoiceForm.vue
    <template>
      ... do something
    </template>
    <srcipt>
      export default {
        methods: {
          // 所有form组件提供统一的获取值接口
          getValue () {
            // 需返回一个promise,目前大多数vue表单验证都是异步的
            return new Promise(() => {
              // 表单验证,返回值
              ...do something
            })
          }
        }
      }
    </script>
    复制代码
    // postForm.vue
    <template>
      ... do something
    </template>
    <srcipt>
      export default {
        methods: {
          // 统一的获取值接口
          getValue () {
            // 需返回一个promise
            return new Promise(() => {
              ...do something
            })
          }
        }
      }
    </script>
    复制代码
    // stage.vue
    <template>
      <div>
        <!-- ref获取组件对象 -->
        <invoice-form ref="invoice" />
        <post-form v-if="isNeedPost" ref="post" />
        <button @click="handleSubmit">提交</button>
      </div>
    </template>
    <script>
      export default {
        data () {
          isNeedPost: true
        }
        methods: {
          async handleSubmit () {
            // 已知有invoice和post两个观察者
            let invoice = await this.$refs.invoice.getValue()
            let post = {}
            if (this.$refs.post) {
                post = await this.$refs.post.getValue()
            }
            this.$axios.post({
                invoice,
                post
            })
          }
        }
      }
    </script>
    复制代码

    四、更复杂的场景

    每次点击新增联系人按钮页面上会增加一个这样的form,点击保存按钮时所有联系人表单分别做验证,所有表单验证通过后一并提交。与上面的场景类似,大家可以尝试本文的思路。
    上面的场景是已知有invoiceFormpostForm,而这个场景下联系人form可以无限制的添加

    当 ref 和 v-for 一起使用的时候,你得到的引用将会是一个包含了对应数据源的这些子组件的数组(来自vue文档)

    设计实现

    <template>
      <div>
        <div>
          <contact-form
            v-for="(item, index) in contactGroup"
            ref="contacts"
            :key="index"
          />
        </div>
        <button @click="handleAdd">添加联系人</button>
        <button @click="handleSave">保存</button>
      </div>
    </template>
    <script>
      export default{
        data () {
          return {
            contactGroup: [true]
          }
        },
        methods: {
          handleAdd () {
            this.contactGroup.push(true)
          },
          async handleSave () {
            // 伪代码
            try {
              // this.$refs.contacts是一个数组
              const promises = this.$refs.contacts.map(contact => contact.getValue())
              const contacts = await Promise.all(promises)
              this.$axios.post({
                contacts
              })
            } catch (error) {
              // 表单验证不通过
              console.dir(error)
            }
          }
        }
      }
    </script>
    复制代码

    结尾

    本文的内容相对来说比较简单,对于上面例举的场景你也可能会有更好的解决方式,不过个人觉得这种需求场景对于理解观察者模式还是蛮不错的。

    
    写到这一篇觉得有必要搞个小总结:
    
    1,在这一篇为了使用观察者模式我们需要获取观察对象(组件)——ref
    2,本系列第一篇我们用工厂模式生产input组件,为了透传type、status工厂组件设计的也需要接受
    这两个props,如果这时要透传更多的prop并且还有事件那怎么办呢,最好的方案——$attrs$listeners
    3,设计模式的一个主要特性能够动态的组合和决定使用哪个对象(组件)——动态组件component
    4,本系列第四篇为能自定义一个算法(组件渲染)的某一步——slot
    
    相信大家都已经了解了一个框架API的设计背后都是有一定考量的,当然上面例举的4个都只是基于本系列
    的内容不代表全部
    有人说不会这样用是因为对vue的文档不熟悉,我身边有朋友没事就把vue文档从头看到尾,他是不熟?
    个人觉得应该是代码的设计需求驱动你去深入了解框架,大多时候框架已经提供了满足你要求的API直
    接用就行了(查文档),如果框架没有提供现成的能不能通过其它API hack一下(这个时候可能就需要深入
    源码研究),如果依旧满足不了你,在自己技术能力允许的情况下给框架源码提个PR?
    
    复制代码

    本文实现同样适用于react,为什么文章以vue做题?vue的template让我们在理解一些概念的时候可能会有点不适应,而react的jsx可以看做就是在写JavaScript对各种概念实现更灵活
    友情提示:设计模式在vue中的应用应该会写一个系列,喜欢的同学记得关注下

    更多相关内容
  • VUE设计模式详解

    2021-09-23 10:58:05
    设计模式(1):只执行一次的函数 概述 最近最近做项目的时候总会思考一些大的应用设计模式相关的问题,我把自己的思考记录下来,供以后开发时参考,相信对其他人也有用。 只执行一次的函数 我们经常会遇到这种...

    设计模式(1):只执行一次的函数

    概述

    最近最近做项目的时候总会思考一些大的应用设计模式相关的问题,我把自己的思考记录下来,供以后开发时参考,相信对其他人也有用。

    只执行一次的函数

    我们经常会遇到这种情况,就是希望某个函数只执行一次,以后就不执行了。一般情况下,我们会这么写:

    <script>
    export default {
      data() {
        return {
          runOnce: true,
        };
      },
      methods: {
        func() {
          console.log('hello world', this);
        },
        funcRunOnce() {
          if (this.runOnce) {
            this.func();
            this.runOnce = false;
          }
        },
      },
    };
    </script>

    但是这样并不优雅,不仅污染了data,还用2个方法进行实现,实在难看。

    用闭包改进

    于是我们考虑用闭包,把data里面的runOnce这个变量放到闭包里面去,这样就不会污染data了。代码如下:

    <script>
    export default {
      methods: {
        func() {
          console.log('hello world', this);
        },
        funcRunOnce(params) {
          let runOnce = true;
          return () => {
            if (runOnce) {
              this.func();
              runOnce = false;
            }
          }();
        },
      },
    };
    </script>

    但是这么写显然是错了,因为每次调用funcRunOnce都会构造一次闭包,里面的runOnce这个变量根本不会共享。所以继续改写如下:

    // 方法1
    <script>
    export default {
      created() {
        this.funcRunOnce = this.runOnce(this.func);
      },
      methods: {
        func() {
          console.log('hello world', this);
        },
        runOnce(func) {
          let runOnce = true;
          return (params) => {
            if (runOnce) {
              func(params);
              runOnce = false;
            }
          };
        },
      },
    };
    </script>
    
    // 方法2
    <script>
    export default {
      methods: {
        func() {
          console.log('hello world', this);
        },
        runOnce(func) {
          let runOnce = true;
          return (params) => {
            if (runOnce) {
              func(params);
              runOnce = false;
            }
          };
        },
        funcRunOnce: this.runOnce(this.func),
      },
    };
    </script>

    使用utils

    可以看到,上面的方法仍然很不优雅,要么用一个created和2个方法实现,要么用三个方法实现。而都用了一个公共的方法runOnce。所以我们考虑把runOnce放到utils.js里面去。

    // utils.js
    export function runOnce(func) {
      let runOnce = true;
      return (params) => {
        if (runOnce) {
          func(params);
          runOnce = false;
        }
      };
    }
    
    //example.vue
    import { runOnce } from '@/utils';
    <script>
    export default {
      methods: {
        funcRunOnce: runOnce(() => {
          console.log('hello world', this);
        }),
      },
    };
    </script>

    上面的写法看起来非常简洁,但是实际上是不行的,因为this的指向错了。由于runOnce返回的函数并不是vue实例的方法,所以里面的this指向的是undefined

    注意:即使看起来我们好像在funcRunOnce方法中用箭头函数捕获了外面实例的this,但是实际上它捕获的并不是外面的实例的this,而是runOnce返回的函数里面的this。

    捕获this

    能用箭头函数的地方我们都用了,但是为什么我们还是捕获不了this呢?如此一来是不是完成不了这个任务了?

    并不是,方法还是有的,方法是不用箭头函数捕获this。代码如下:

    // utils.js
    export function runOnce(func) {
      let runOnce = true;
      return function(params) {
        if (runOnce) {
          func.apply(this, params);
          runOnce = false;
        }
      };
    }
    
    //example.vue
    import { runOnce } from '@/utils';
    <script>
    export default {
      methods: {
        funcRunOnce: runOnce(function h() {
          console.log('hello world', this);
        }),
      },
    };
    </script>

    通过查看代码可以看出,2个地方的箭头函数都被改写成了function,并且还用到了apply函数来强制施加this。

    理由很简单,由于runOnce函数里面没有用箭头函数,所以它返回的函数是属于vue实例的,所以它返回的函数的this,是指向vue实例的;又因为funcRunOnce里面没有用箭头函数,所以我们可以用apply把这个this强制附加到func里面去!

    同理我们还可以写出第一次不执行,后续才执行的函数:

    // utils.js
    // 第一次不执行,后续再执行
    export function notRunOnce(func) {
      let once = false;
      return function(params) {
        if (once) {
          func.apply(this, params);
        }
        once = true;
      };
    }

    学到了什么

    1. 在vue里面可以用赋值的形式初始化方法,或者在created里面初始化方法。
    2. 箭头函数虽然能捕获this,但不是万能的;有时候我们需要用function和apply结合来捕获this。


    设计模式(2): 响应store中数据的变化

    概述

    最近最近做项目的时候总会思考一些大的应用设计模式相关的问题,我把自己的思考记录下来,供以后开发时参考,相信对其他人也有用。

    store里面响应数据变化

    通常情况下,我们会把数据存在store里面,并且,有时我们也需要跟踪store里面的数据变化,并作出响应。例子如下:

    export default {
      computed: {
        categories: state => state.categories.categories,
      },
      watch: {
        categories() {
          this.fetchCardData();
        },
      },
      methods: {
        fetchCardData() {
          // 请求卡片数据
        },
      },
    }

    如上所示,当store里面的categories改变的时候,我们会自动调用api去请求数据

    不响应store里面的数据变化

    上面的例子里面,每次当categories改变的时候,fetchCardData方法都会被调用。有些时候,这并不是我们想要的,我们想要的是,当xxxx的时候,categories会改变,fetchCardData方法会跟着被调用;当xxxx的时候,categories会改变,fetchCardData方法又不会跟着被调用,怎么办呢?

    方法是创造一个标记,但是如何优雅的创造标记呢?我有一个方法如下所示:

    // store.js
    const state = {
      categories: [],
      categoriesChanges: 0,
    };
    
    const actions = {
      updateCategories({ commit }, value) {
        // 如果带有shouldNotChange,则表示不要刷新页面
        if (value.shouldNotChange) {
          commit(types.UPDATE_CATEGORIES, value.data);
        } else {
          commit(types.UPDATE_CATEGORIES, value);
          commit(types.UPDATE_CATEGORIES_CHANGES);
        }
      },
    };
    
    const mutations = {
      [types.UPDATE_CATEGORIES](state, value) {
        state.categories = value;
      },
      [types.UPDATE_CATEGORIES_CHANGES](state) {
        state.categoriesChanges += 1;
      },
    };
    
    // component.js
    export default {
      computed: {
        categories: state => state.categories.categories,
        categoriesChanges: state => state.categories.categoriesChanges,
      },
      watch: {
        categoriesChanges() {
          this.fetchCardData();
        },
      },
      methods: {
        fetchCardData() {
          // 利用this.categories的部分数据来请求卡片数据
        },
      },
    }
    
    // business.js
    this.$store.dispatch('updateCategories', value); // 会自动调用fetchCardData方法
    
    const payload = {
      shouldNotChange: true,
      data: [...value],
    };
    this.$store.dispatch('updateCategories', payload); // 不会自动调用fetchCardData方法

    这样,我们发出同一个action,却能达到2种不同的效果,非常方便。


    设计模式(3): 二次封装与高阶组件 

    概述

    最近最近做项目的时候总会思考一些大的应用设计模式相关的问题,我把自己的思考记录下来,供以后开发时参考,相信对其他人也有用。

    二次封装组件

    PM的需求无奇不有,所以很多时候,我们使用的组件满足不了PM的需求,怎么办呢?比如,组件需要传入一个数组,但是我们必须传2个变量;或者我们需要在组件focus的时候调用一个方法,但是组件并没有暴露focus事件等等。虽然都是些很简单的需求,但是组件就是没有暴露实现这些需求的方法。咋办?

    方法是对组件进行二次封装

    二次封装主要运用了vue的如下属性:

    • vm.attrs:包含了父作用域中不作为prop被识别(且获取)的特性绑定(class和style除外)。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(class和style除外),并且可以通过v−bind="attrs:包含了父作用域中不作为prop被识别(且获取)的特性绑定(class和style除外)。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(class和style除外),并且可以通过v−bind="attrs" 传入内部组件。

    • vm.$props: 当前组件接收到的 props 对象。

    • vm.listeners:包含了父作用域中的(不含.native修饰器的)v−on事件监听器。它可以通过v−on="listeners:包含了父作用域中的(不含.native修饰器的)v−on事件监听器。它可以通过v−on="listeners" 传入内部组件。

    props可以拿到传给当前组件的所有props,props可以拿到传给当前组件的所有props,attrs可以拿到传给组件的所有非props的属性,$listeners可以拿到所有传给组件的事件监听器

    例子

    举个例子,比如说el-upload需要传一个数组,但是我们只能传2个变量;并且,我们需要在el-upload上传success的时候做点其它的事。封装的代码如下:

    export default {
      name: 'YmUpload',
      props: {
        name: {
          type: String,
          default: '',
        },
        url: {
          type: String,
          default: '',
        },
        onSuccess: {
          type: Function,
          default: () => 1,
        },
      },
      data() {
        return {
          fileList: [],
        };
      },
      watch: {
        url() {
          this.init();
        },
      },
      computed: {
        uploadAttr() {
          return {
            ...this.$attrs,
            fileList: this.fileList,
            onSuccess: this.handleSuccess,
          };
        },
      },
      created() {
        this.init();
      },
      methods: {
        init() {
          // 组件初始化
          const payload = {
            name: this.name || this.url,
            url: this.url,
          };
          this.fileList = [payload];
        },
        handleSuccess(res, file, fileList) {
          // 做点其它的事
        },
      },
    };


    设计模式(4): 给组件实现单独的store 

    概述

    最近最近做项目的时候总会思考一些大的应用设计模式相关的问题,我把自己的思考记录下来,供以后开发时参考,相信对其他人也有用。

    组件自身的store

    我们在开发组件的时候,时常都有这种需求,就是希望给组件一个独立的store,这个store可能被用来储存数据,共享数据,还可以被用来对数据做一些处理,抽离核心代码等。

    store的数据不共享

    如果组件自身的store是每个实例独自拥有的并且不共享的话,我们可以直接用一个类来实现。

    // store.js
    export default class Store {
      constructor(data, config) {
        this.config = config;
        this.init(data);
      }
    
      init(data) {
        // 对数据做处理
      }
    
      // 其它方法
    }

    然后我们在组件中实例化这个store,然后挂载到data属性里面去:

    <script>
    import Store from './store';
    
    export default {
      data() {
        return {
          store: [],
        };
      },
      methods: {
        initStore() {
          // 生成 options 和 config
          this.store = new Store(options, config);
        },
      },
    };
    </script>

    store的数据需要共享 

    如果store的数据需要共享,我们建议用动态挂载vuex的store的方法,示例如下: 

    // store.js
    const state = {
      data: [],
    };
    
    const getters = {};
    
    const actions = {};
    
    const mutations = {
      setData(state, value) {
        this.state.data = [...value];
      },
    };
    
    export default {
      state,
      getters,
      actions,
      mutations,
    };

    然后我们在注册这个组件的时候动态挂载这个store:

    import Store from './store';
    
    export default {
      install(Vue, options) {
        Vue.store.registerModule('xxx', store);
      },
    };

    最后我们就可以在组件中使用这个store的数据啦~~~ 


     设计模式(5): vue 不监听绑定的变量

    概述

    最近最近做项目的时候总会思考一些大的应用设计模式相关的问题,我把自己的思考记录下来,供以后开发时参考,相信对其他人也有用。

    绑定变量

    一般情况下,如果我们需要在组件中使用某个变量,会这么使用:

    data() {
      return {
        myData: [],
      };
    }

    如果这个变量是外部变量,例如从外部文件引入的话,就会这么使用:

    import { provinces } from '@/util/consts';
    
    export default {
      data() {
        return {
          myData: provices,
        };
      },
    }

    问题 

    但是如果这个变量是一个嵌套层级很深,数据量很大的对象的话,如果按照上面那样使用,vue 就会去遍历这个变量的所有属性,来监听这个变量的变化。非常的消耗性能,一个典型的例子是:

    export default {
      data() {
        return {
          bannerBg: null,
        };
      },
      mounted() {
        this.loadScript('/js/three.min.js', () => {
          this.loadScript('/js/vanta.net.min.js', () => {
            this.bannerBg = window.VANTA.NET({
              el: '#bannerBg',
              color: 0x2197F3,
              backgroundColor: 0x071E31,
            });
          });
        });
      },
      beforeDestroy() {
        this.bannerBg.destroy();
      },
      methods: {
        loadScript(path, callback) {
          const script = document.createElement('script');
          script.src = path;
          script.language = 'JavaScript';
          script.onload = () => callback();
          document.body.appendChild(script);
        },
      },
    }

    上面的例子中,我们为了避免内存泄漏,在 beforeDestroy 生命周期里面进行回收,而为了获取回收的变量,我们把它绑定给了 this.bannerBg。

    但是事实是,我们并不需要监听 this.bannerBg 这个变量,而这么绑定的结果是,这个 vue 组件在 mounted 的时候需要遍历 this.bannerBg 来增加 vue 的监听属性,非常消耗性能

    解决方案

    所以,我们建议不把 bannerBg 放到 data() 里面去监听,而是**直接绑定给 this **就行了。优化后的代码如下:

    export default {
      mounted() {
        this.loadScript('/js/three.min.js', () => {
          this.loadScript('/js/vanta.net.min.js', () => {
            this.bannerBg = window.VANTA.NET({
              el: '#bannerBg',
              color: 0x2197F3,
              backgroundColor: 0x071E31,
            });
          });
        });
      },
      beforeDestroy() {
        this.bannerBg.destroy();
      },
      methods: {
        loadScript(path, callback) {
          const script = document.createElement('script');
          script.src = path;
          script.language = 'JavaScript';
          script.onload = () => callback();
          document.body.appendChild(script);
        },
      },
    }

    如果这个变量不是过程中生成的,而是初始化的时候生成的,我们建议在 data() 方法里面这么做:

    import { provinces } from '@/util/consts';
    
    export default {
      data() {
        this.myData = provices;
    
        return {
          // 移到上面去了
          // myData: provices,
        };
      },
    }


    设计模式(6): 数据抽象与业务封装 

    概述

    最近最近做项目的时候总会思考一些大的应用设计模式相关的问题,我把自己的思考记录下来,供以后开发时参考,相信对其他人也有用。

    情景描述

    我们在做项目的时候,经常会碰到各种各样的业务情景,然后为了实现这些需求,就不断地在 vue 单文件组件里面加代码来实现,最终业务越来越多单文件组件越来越大,非常难以维护。

    解决方案

    我们都知道,vue 是通过数据来处理视图的,所以很多业务可以抽象成只处理数据,然后这些业务可以再抽象成 class 来进行业务封装。

    event-bus

    举个例子来说,vuex 或者 redux 这些状态管理的库,就是用的这个思想,把数据层脱离出去,带来的好处是简化了组件之间的数据流动。它们的源码有些复杂,我们以 event-bus 来举例说明。

    首先,我们可以自己实现一个 bus 类,这个类能够储存数据,还能够进行事件的分发与监听

    import Vue from 'vue';
    import Bus from 'xxxx';
    
    Vue.prototype.$bus = new Bus();

    然后,分别在组件 A 和 B 里面,我们可以监听事件和分发事件。 

    // 组件A -- 监听事件
    created() {
      this.$bus.on('xxxx', this.xxx);
    },
    beforeDestroy() {
      this.$bus.off('xxxx', this.xxx);
    },
    
    // 组件B -- 分发事件
    methods: {
      xxxx() {
        this.$bus.emit('xxxx', this.xxx);
      }
    }

    这样,即使处于不同层级,组件 A 和 B 也能流畅的进行数据交互。

    抽象方法

    我们抽象一下实现方法,我们先把业务抽象为数据和对数据的操作,然后在组件之外实现一个 class,最后用这个 class 进行保存数据和业务处理

    上面这个例子把这个 class 放在了 Vue 实例上面,可能没有那么明显,下面举一个把它放在单文件组件里面的例子。

    cascader

    这一段参考了 element-cascader 的实现。

    比如说,我们要自己实现一个 cascader,要怎么做?

    我们上面提到过,我们对 cascader 的操作其实就是对数据的操作,所以我们可以把整个数据抽象出来,然后给它加上选中的业务功能:

    import { capitalize } from '@/utils/util';
    
    export default class Node {
      constructor(data, parentNode) {
        this.parent = parentNode || null;
    
        this.initState(data);
        this.initChildren(data);
      }
    
      initState(data) {
        // 加上本身的属性
        for (let key in data) {
          if (key !== 'children') {
            this[key] = data[key];
          }
        }
    
        // 自定义属性
        this.isChecked = false;
        this.indeterminate = false;
    
        // 用于自动取消
        this.isCheckedCached = false;
        this.indeterminateCached = false;
      }
    
      initChildren(data) {
        this.children = (data.children || []).map(child => new Node(child, this));
      }
    
      setCheckState(isChecked) {
        const totalNum = this.children.length;
        const checkedNum = this.children.reduce((c, p) => {
          const num = p.isChecked ? 1 : (p.indeterminate ? 0.5 : 0);
          return c + num;
        }, 0);
    
        this.isChecked = isChecked;
        this.indeterminate = checkedNum !== totalNum && checkedNum > 0;
      }
    
      doCheck(isChecked) {
        this.broadcast('check', isChecked);
        this.setCheckState(isChecked);
        this.emit('check', isChecked);
      }
    
      broadcast(event, ...args) {
        const handlerName = `onParent${capitalize(event)}`;
    
        this.children.forEach(child => {
          if (child) {
            child.broadcast(event, ...args);
            child[handlerName] && child[handlerName](...args);
          }
        });
      }
    
      emit(event, ...args) {
        const { parent } = this;
        const handlerName = `onChild${capitalize(event)}`;
    
        if (parent) {
          parent[handlerName] && parent[handlerName](...args);
          parent.emit(event, ...args);
        }
      }
    
      onParentCheck(isChecked) {
        if (!this.disabled) {
          this.setCheckState(isChecked);
        }
      }
    
      onChildCheck() {
        const validChildren = this.children.filter(child => !child.disabled);
        const isChecked = validChildren.length
          ? validChildren.every(child => child.isChecked)
          : false;
    
        this.setCheckState(isChecked);
      }
    }

    上面实现的 class 封装了如下业务:

    1. 通过 initState 加入了各种自定义的状态,这个状态有了业务:选中状态,半选中状态和未选中状态
    2. 通过 setCheckState 实现了 点击 的业务。
    3. 通过 broadcast 和 emit 实现了 父子组件联动 的业务。

    当然,实际情形可能比这个更加复杂,我们只需要在上面的代码中加入各种状态和处理方法即可。

    更进一步

    上面封装的底层的业务,再高一层,我们可能有 搜索、自动选中 等业务,这个时候要怎么办呢?

    方法是在 Node 类和单文件组件之间再封装一层,来实现这些业务,示例代码如下:

    export default class Store {
      constructor(data) {
        this.nodes = data.map(nodeData => new Node(nodeData));
      }
    
      // 自动选中
      autoSelect(query, label) {
    
      }
    
      // 搜索
      search(searchString) {
    
      }
    }

    然后我们可以在单文件组件里面直接使用它

    data() {
      return {
        store: null;
      };
    },
    watch: {
      data(newVal) {
        this.store = new Store(newVal);
      }
    },

     推荐阅读:

    学习Web前端 自学宝典

    【uni-app】uniapp项目优化方式及建议

    前端跨域设置 withCredentials: true

    展开全文
  • vue设计模式_笔记

    2021-09-28 20:00:04
    Vue设计模式响应式原理认识Object.prototype.constructor对象的构造函数改变constructorget、setObject.defineProperty()MVVM设计模式(响应式原理) 响应式原理 认识Object.prototype.constructor 返回创建实例...

    响应式原理

    认识Object.prototype.constructor

    返回创建实例对象的 Object 构造函数的引用。注意,此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。对原始类型来说,如1,true和"test",该值只可读。

    var o = {};
    o.constructor === Object; // true
    
    var o = new Object;
    o.constructor === Object; // true
    
    var a = [];
    a.constructor === Array; // true
    
    var a = new Array;
    a.constructor === Array // true
    
    var n = new Number(3);
    n.constructor === Number; // true
    

    在这里插入图片描述

    对象的构造函数
    function Tree(name) {
       this.name = name;
    }
    
    var theTree = new Tree("Redwood");
    console.log( "theTree.constructor is " + theTree.constructor );
    

    在这里插入图片描述

    改变constructor

    obj instanceof Object 检测Object.prototype是否存在于参数obj的原型链上。

    function Type() {};
    var types = [
        new Array, [],
        new Boolean,
        true, // remains unchanged
        new Date,
        new Error,
        new Function,
        function() {},
        Math,
        new Number,
        1, // remains unchanged
        new Object,
        {},
        new RegExp,
        /(?:)/,
        new String,
        "test" // remains unchanged
    ];
    
    for (var i = 0; i < types.length; i++) {
        types[i].constructor = Type;
        types[i] = [types[i].constructor, types[i] instanceof Type, types[i].toString()];
    };
    
    console.log(types.join("\n"));
    

    输出:
    在这里插入图片描述

    get、set

    obj.__defineGetter__(prop, func)
    

    prop
    一个字符串,表示指定的属性名。
    func
    一个函数,当 prop 属性的值被读取时自动被调用。

    // 请注意,该方法是非标准的:
    
    var o = {};
    o.__defineGetter__('gimmeFive', function() { return 5; });
    console.log(o.gimmeFive); // 5
    
    
    // 请尽可能使用下面的两种推荐方式来代替:
    
    // 1. 在对象字面量中使用 get 语法
    var o = { get gimmeFive() { return 5; } };
    console.log(o.gimmeFive); // 5
    
    // 2. 使用 Object.defineProperty 方法
    var o = {};
    Object.defineProperty(o, 'gimmeFive', {
      get: function() {
        return 5;
      }
    });
    console.log(o.gimmeFive); // 5
    
    obj.__defineSetter__(prop, fun)
    

    prop
    一个字符串,表示指定的属性名。
    fun
    一个函数,当试图去为 sprop 属性赋值时被调用。通常你要给这个函数指定一个参数:

    Object.defineProperty()

    JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性。 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。
    每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
    在这里插入图片描述

    MVVM设计模式(响应式原理)

    View和Model之间并没有直接的联系,而是通过ViewMode进行交互,ViewModel通过双向数据绑定把View层和Model层连接了起来

    const data = {};
    let name = "张三";
    
    Object.defineProperty(data, 'name', {
        get: function() {
            console.log('触发get')
            return name
        },
        set: function(newVal) {
            console.log('触发set')
            name = newVal
        }
    })
    
    //测试
    console.log(data.name) // 触发get  张三
    data.name = '李四' // 触发set
    

    在这里插入图片描述

    展开全文
  • 目录 vue的基本介绍 什么是vue? 为什么使用vue?...mvc设计模式 MVVM设计模式 vue的基本介绍 什么是vue? 1.渐进式javascript框架 2.作者:尤雨溪 个人开发 3.Vue (读音 /vjuː/,类似于 ..

    目录

    vue的基本介绍

    什么是vue?

    为什么使用vue?

    vue优点

    缺点

    对于Vue是一套渐进式框架的理解(面试题) ?

    SPA(单页面应用)

    相对复杂

    说说你对 SPA 单页面的理解,它的优缺点分别是什么?

    vue的下载及引入

    练习

    vue的使用

    实例化vue

    定义数据和方法

    设计模式

    mvc设计模式

    MVVM设计模式


    vue的基本介绍


    什么是vue?

    1.渐进式javascript框架
    2.作者:尤雨溪  个人开发
    3.Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。

    为什么使用vue?

    一个完整的页面:HTML(基本视图)+CSS(样式)+js(交互).通常情况下对于HTML我们又称之为视图结构
    视图结构组成: 内容(标签)和数据(文本内容和属性值)
    而刚好vue只关注视图层.将数据和内容进行拆分
    内容交给HTML进行处理,数据交给后端进行处理.
    优势:
        1.适用于前后端分离
         2.用户体验更优 

    vue优点

    vue的两个核心:组件化应用和数据驱动

    • 轻量级框架    大小33.46KB min+gzip

    • 双向数据绑定 

    模型层数据的改变会更新到视图层,视图层数据的更新会同步到模型层

    • 提供了基本的指令

    使用指令可以解决有些特殊的复杂的逻辑

    • 客户端路由

    可以做到页面和地址实现一一对应的关系

    • 数据驱动

     可以做到页面和地址实现一一对应的关系

    缺点

    • 不支持 IE8及以下浏览器

    • 首屏加载速度慢

     在首次加载项目时,会将所有的静态资源全部加载过来,eg:CSS js img font

    • 不利于SEO优化

     因为在百度搜索引擎中检索不到js

    对于Vue是一套渐进式框架的理解(面试题) ?

    渐进式代表的含义是:主张最少。
    Vue可能有些方面是不如React,不如Angular,但它是渐进的,没有强主张,你可以在原有大系统的上面,把一两个组件改用它实现,当jQuery用;也可以整个用它全家桶开发,当Angular用;还可以用它的视图,搭配你自己设计的整个下层用。你可以在底层数据逻辑的地方用MVVM和设计模式的那套理念,也可以函数式,都可以,它只是个轻量视图而已,只做了自己该做的事,没有做不该做的事,仅此而已。

    SPA(单页面应用)


    PA:single page application 单页面应用

    MPA:multi page application 多页面应用

    单页面(SPA)和多页面(MPA)的区别?

    单页面(SPA)多页面(MPA)
    刷新方式页面局部刷新或更改整页刷新
    url 模式a.com/#/pageone a.com/#/pagetwoa.com/pageone.html a.com/pagetwo.html
    用户体验页面片段间的切换快,用户体验良好页面切换加载缓慢,流畅度不够,用户体验比较差
    转场动画容易实现无法实现
    数据传递容易依赖 url传参、或者cookie 、localStorage等
    搜索引擎优化(SEO)需要单独方案、实现较为困难、不利于SEO检索 ,可利用服务器端渲染(SSR)优化实现方法简易
    适用范围高要求的体验度、追求界面流畅的应用适用于追求高度支持搜索引擎的应用
    开发成本较高,常需借助专业的框架较低 ,但页面重复代码多
    维护成本相对容易

    相对复杂

    说说你对 SPA 单页面的理解,它的优缺点分别是什么?

    SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI (视图template的内容)与用户的交互,避免页
    面的重新加载。

    优点:用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;基于上面一点,SPA 相对对服务器压力小;前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;

    缺点:初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。 

    vue的下载及引入


    • cdn

    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
    • 直接通过script引入

    <script src="vue.js"></script>
    • npm

    1.npm init   #初始化package.json
    2.npm i vue -S  或者 npm i vue --save   #下载vue模块,并且保存到package.json文件
    • 教手架

    练习

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <!-- 1.引入vue  cdn-->
        <!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
         -->
         <!-- 2.引入vue  script -->
         <!-- <script src="./vue.js"></script> -->
         <!-- 3.引入vue npm -->
         <script src="./node_modules/vue/dist/vue.js"></script>
    </head> 
    <body>
        <div id="app">
            <h2>购买的商品为:{{name}}</h2>
            <div>单价:
                <input type="text"  v-model="price">
            </div>
            <div>数量:
                <input type="text"  v-model="num">
            </div>
            <div>
                总价:{{price*num}}
            </div>
        </div>
        <script>
            // 实例化vue对象
            let vm =  new Vue({
                el:'#app',
                data:{
                    name:'iphone13',
                    price:6999.00,
                    num:1,
                }
            })
        </script>
    </body>
    </html>

    vue的使用


    实例化vue

      * 1.实例化vue需要接收一个参数
      * 2.接收参数为:Object
      * 3.该对象中会有很多选项: el data
      * 4.不能将vue实例化挂载到HTML或者body上,将vue实例挂载到正常的元素节点上
      * 5.任何CSS选择器都可以作为vue实例的挂载点,但是建议使用id选择器
      * 6.一个页面中建议只有一个vue实例化

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <!-- 1.引入vue  -->
        <script src="./vue.js"></script>
    </head>
    <body>
        <!-- 2.创建DOM元素 -->
        <div id="app">
            <h2>{{title}}</h2>
            <div>{{name}}</div>
        </div>
        <!-- <div class="app1">
            <h2>{{title}}</h2>
            <div>{{name}}</div>
        </div> -->
        <script>
            // 3.实例化vue
            /**
             * 1.实例化vue需要接收一个参数
             * 2.接收参数为:Object
             * 3.该对象中会有很多选项: el data
             * 4.不能将vue实例化挂载到HTML或者body上,将vue实例挂载到正常的元素节点上
             * 5.任何CSS选择器都可以作为vue实例的挂载点,但是建议使用id选择器
             * 6.一个页面中建议只有一个vue实例化
            */
        //    注释: 将vue实例挂载到id等于app的div元素上 
           let vm =  new Vue({
                el:'#app',//el:element
                data:{//数据|属性   主要存放数据
                    name:'哈哈哈',
                    title:"vue基础学些",
                }
           });
        //    console.log(vm.$el);
    
        //    new  Vue({
        //        el:'.app1',
        //        data:{
        //             name:'哈哈哈',
        //             title:"vue基础学些",
        //        }
        //    })
    
    
        </script>
    </body>
    </html>
    • mustache语法

    采用{{}}来解析data选项中的属性, 向{{}}我们把它称之为mustache语法 

    定义数据和方法

    • 数据

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <!-- 1.引入vue -->
        <script src="./vue.js"></script>
    </head>
    <body>
        <!-- 2.创建dom元素 -->
        <div id="app">
            <!-- 总结:在{{}}可以直接写js语法 -->
            <!-- 直接展示data中属性值 -->
            <div>name的值为:{{name}}</div>
            <div>num的值为:{{num}}</div>
            <!-- 字符串拼接  -->
            <div>{{'hello'+name}}</div>
            <!-- 计算 -->
            <div>{{1+1}}</div>
            <!-- 判断  -->
            <div>{{age >= 18 ? '已成年' : '未成年'}}</div>
            <!-- 数组  -->
            <p>{{arr}}</p>
            <!-- 对象 -->
            <div>{{obj}}</div>
        </div>
        <script>
            let  vm = new Vue({
                el:'#app',
                data:{//属性
                    name:'vue',
                    num:10,
                    age:20,
                    arr:['贾玲','沈腾','关晓彤'],
                    obj:{
                        name:'杨志远',
                        age:20,
                        girlFriend:'翠花',
                    }
                }
            })
        </script>
    
    </body>
    </html>
    • 方法

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <!-- 1.引入vue -->
        <script src="./vue.js"></script>
    </head>
    <body>
        <!-- 2.创建DOM元素 -->
        <div id="app">
            <!-- 调用自调用方法 -->
            <div>{{foo()}}</div>
            <!-- 调用系统方法 -->
            <div>{{price.toFixed(2)}}</div>
            <div>{{fn()}}</div>
        </div>
        <script>
            // vue实例的选项: el ,data, methods
            new Vue({
                el:'#app',
                data:{//属性
                    name:'vue',
                    price:30.00,
                },
                methods:{//方法
                    foo(){
                        console.log(this.name);
                    },
                    fn:function(){
                        console.log('调用了');
                    },
                }
            })
        </script>
    </body>
    </html>

    设计模式


    mvc设计模式

    M:Model 模型层 作用:处理数据逻辑,一般跟数据库交互

    V:View 视图层 作用:展示页面及渲染数据

    C:Controller 控制器 作用:处理业务逻辑,为view和model的中间件

    MVVM设计模式

    Model–View–ViewModel (MVVM) 是一个软件架构设计模式MVVM 源自于经典的 Model–View–Controller(MVC)模式(大部分后端模式)

     MVVM 的出现促进了前端开发与后端业务逻辑的分离,极大地提高了前端开发效率,MVVM 的核心是 ViewModel 层,它就像是一个中转站(value converter),负责转换 Model中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与 Model 层通过接口请求进行数据交互,起呈上启下作用。如下图所示:

    M:Model 模型层 作用:处理数据及逻辑

    V:View 视图层 作用:展示内容和渲染数据

    ViewModel: 视图模型层, 作用:作为model和view的中间件

    (1)View 层
    View 是视图层,也就是用户界面。前端主要由 HTML 和 CSS来构建 。
    (2)Model 层
    Model 是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,对于前端来说就是后端提供的 api 接口。
    (3)ViewModel 层ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分,而 Model 层的数据模型是只包含状态的,比如页面的这一块展示什么,而页面加载进来时发生什么点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互),视图状态和行为都封装在了ViewModel 里。这样的封装使得 ViewModel 可以完整地去描述 View 层。MVVM 框架实现绑定,这样 ViewModel 的内容会实时展现在 View 层,前端开发者再也不必低效又麻烦地通过操纵 DOM 去更新视图,MVVM 框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护 ViewModel,更新数据视图就会自动得到相应更新。这样 View 层展现的不是Model 层的数据,而是 ViewModel 的数据,由 ViewModel负责与 Model 层交互,这就完全解耦了 View 层和 Model
    层,这个解耦是至关重要的,它是前后端分离方案实施的重
    要一环。 

    展开全文
  • vue设计模式

    千次阅读 2020-08-06 15:16:38
    vue是一个渐进式的框架 那什么是渐进式??? 渐进式,简单翻译一下就是主键做加法的模式
  • vue 源码目录设计简述

    2022-04-25 18:08:57
    学习vue.js的源码,首先要学习源码目录,vue.js的源码都在src目录下,目录结构如下: src ├── compiler # 编译相关 ├── core # 核心代码 ├── platforms # 不同平台的支持 ├── server # 服务端渲染 ├...
  • }, }) Vue设计模式 Vue主要使用了两种设计模式 观察者模式:由具体的目标调度,比如当事件触发,Dep发布者就会去调用Watcher观察者的方法,所以观察者模式的订阅者与发布者之间是存在依赖的 发布订阅模式:由统一...
  • MVC是Model-View-...MVC模式的特点在于实现关注点分离,即应用程序的数据模型与业务和展示逻辑解耦。在客户端web开发,就是将模型(M-数据、操作数据)、视图(V-显示数据的HTML元素)之间实现代码分离,松散耦
  • Vue - MVVM设计模式

    2021-06-24 16:12:48
    转变思维, 用数据驱动视图改变, 操作dom的事, vue源码内干了 设计模式: 是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。 MVVM,一种软件架构模式,决定了写代码的思想和层次 M: ...
  • 6、从源码中学习设计模式,一举两得 7、编程思想的提升及代码质量的提高 8、通过分析源码学习架构,看看优秀的框架 9、项目实战开发 10、面试准备,完善个人简历 暂时想到的就这么多,把这列举的10点做好了,我觉得...
  • 手写Vue源码,实现核心技术,麻雀虽小五脏俱全:”响应式原理,模板编译,依赖收集”算法:Diff算法实现”设计模式:发布-订阅模式,装饰者模式,代理模式”数据结构:AST树,vnode,vDom 文件名,方法名称,变量得...
  • Vue.js 的源码都在 src ⽬录下,其⽬录结构如下。 如图所示: compiler ⽬录包含 Vue.js 所有编译相关的代码。它包括把模板解析成 ast 语法树,ast 语法树优化,代码⽣成等功能。core ⽬录包含了 Vue.js 的核⼼代码...
  • vue源码看观察者模式

    千次阅读 2018-01-30 00:42:56
    摘要:源码解读设计模式系列文章将陆陆续续进行更新 ~ 观察者模式 首先话题下来,我们得反问一下自己,什么是观察者模式? 概念 观察者模式(Observer):通常又被称作为发布-订阅者模式。它定义了一种一...
  • Vue设计模式简介

    千次阅读 2019-09-26 17:03:44
    ViewModel是Vue.js的核心,它是一个Vue实例。 vm监听DOM,当数据改变的时候,vm会去自动更新视图。 VM有DOM Listeners和Data Bindings两个工具,它们是实现双向绑定的关键。 从View侧看,ViewModel的DOM ...
  • Vue源码的整体架构无非是初始化Vue对象,挂载数据data/props等,在不同的时期触发不同的事件钩子,如created() / mounted() / update()等,后面专门整理各个模块的文章。这里先讲双向数据绑定的部分,也是最主要的...
  • vue -观察者模式

    2022-05-27 20:31:27
    观察者模式vue中的观察者模式什么是观察者模式 vue中的观察者模式 vue2 底成的原理是 object.defineproperty() 配合观察者模式 object.defineproperty()对数据可以进行劫持 当数据发生变化的时候 需要通知被依赖...
  • Self-Vue(自己实现的vue监听数据变化和...其中还需使用正则编译HTML模板,同时多处使用了观察者/订阅发布设计模式,以便能直接在此操作this.data的属性,还使用了代理模式等等。 目前遇到了层叠在html遍历渲染
  • java语言课程设计-设计模式大作业用Springboot和Vue实现的考勤系统源代码。系统访问账号 账号 密码 角色 1111 123 员工 5555 123 财务 4444 123 人事 0000 123 总经理 目录 前端 frontpage为前端项目,使用...
  • 基于 Java EE 的 web 开发平台,采用Spring+SpringMvc+Mybatis+Vue+阿里云OSS+ElementUi前后端分离的架构模式设计并实现国民品牌独立商城——《“依伴汉服”商城》
  • 这是一款javaWeb的前后端分离的Springboot和vue源码,包含论文和答辩ppt,前端vue.js,基于B/S模式,idea或者eclipse为开发工具,功能也比较全面,毕业设计使用,感兴趣的朋友可以下载看看哦 管理员:首页、个人中心、...
  • VUE源码相关面试题汇总

    千次阅读 多人点赞 2020-07-12 10:52:41
    vue-router,vuex他们都是作为vue插件,请说一下他们分别都是如何在vue中生效的? A: 通过vue的插件系统,用vue.mixin混入到全局,在每个组件的生命周期的某个阶段注入组件实例。 Q3: 请你说一下vue设计架构。 A...
  • 期末大作业基于Electron+Vue构建的桌面音乐播放器源码。 特性 支持音乐频谱 界面友好,支持皮肤切换 跨平台,可打包Windows、Mac、Linux 良好的架构模式和代码风格 提供支持主流的第三方音乐平台 期末大作业基于...
  • 源码这个东西对于实际的工作其实没有立竿见影的效果,不会像那些针对性极强的文章一样看了之后就立马可以运用到实际项目,产生什么样的效果,源码的作用是一个潜移默化的过程,它的理念、设计模式、代码结构等看了...
  • vue 源码详解(一): 生成 Vue 实例前的准备工作 1. 从 new Vue() 开始 vue/src/core/index.js : import Vue from './instance/index' // 1. 引入 Vue 构造函数 import { initGlobalAPI } from './global-api/index...
  • 深入理解vue核心设计模式

    千次阅读 2020-07-15 01:08:34
    这个设计模式我也看过不少文章,被称为订阅-发布设计模式确实更合理,在vue2的架构,我们把核心的设计模式分为Observer,Dep,Watcher,Observer被称为观察者,观察着我们的数据,Dep为数据分配中心,收集数据和...
  • Vue源码解读(个人见解 + 网友理解)

    千次阅读 2020-11-30 16:13:07
    【个人总结】Vue源码解读 文章目录【个人总结】Vue源码解读前言目录解说Vue的实例Mixin的解说Vue生命周期钩子Vue响应式原理数据劫持收集依赖与派发更新虚拟DOM 前言 作为一名前端开发攻城狮来讲,我觉得学习源码是...
  • Vue 源码分析与讲解 》,详情请戳:[ 资料分享 ] Vue 源码分析与讲解 - 附下载地址这段时间我也是把文档和配套的课程学习了一遍,对Vue的原理有了更深层次的理解,由于原文档涉及大量的源代码以及实现逻辑分享,...
  • vue已是目前国内前端web端三分天下之一,同时也作为本人主要技术栈之一,在日常使用知其然也好奇着所以然,另外最近的社区涌现了一大票vue源码阅读类的文章,在下借这个机会从大家的文章和讨论汲取了一些营养,...
  • 这是一款javaEE的前后端分离的Springboot和vue源码,前端vue.js,采用javaweb,基于B/S模式,idea或者eclipse为开发工具,功能也比较全面,毕业设计使用,感兴趣的朋友可以下载看看哦 二、功能介绍 本论文系统地描绘了...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,952
精华内容 5,180
关键字:

vue源码中的设计模式