Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端基础知识之Vue篇 #21

Open
zptime opened this issue Oct 4, 2021 · 1 comment
Open

前端基础知识之Vue篇 #21

zptime opened this issue Oct 4, 2021 · 1 comment

Comments

@zptime
Copy link
Owner

zptime commented Oct 4, 2021

写 React / Vue 项目时为什么要在列表组件中写 key,其作用是什么

官网推荐使用 key,应该理解为“使用唯一 id 作为 key”。因为 index 作为 key,和不带 key 的效果是一样的。index 作为 key 时,每个列表项的 index 在变更前后也是一样的,都是直接判断为 sameVnode 然后复用。

说到底,key 的作用就是更新组件时判断两个节点是否相同。相同就复用,不相同就删除旧的创建新的。正是因为带唯一 key 时每次更新都不能找到可复用的节点,不但要销毁和创建 vnode,在 DOM 里添加移除节点对性能的影响更大。所以会才说“不带 key 可能性能更好”,没有 key 的情况下可以对节点就原地复用,提高性能。

node 框架比较:Next、Nuxt 和 Nest,这三个框架都是服务器端渲染

  • Next 是一个 React 框架,允许使用 React 构建 SSR 和静态 web 应用
  • Nuxt 是一个基于 Vue 的通用应用框架,预设了利用 Vue 开发服务端渲染的应用所需要的各种配置,主要关注的是应用的 UI 渲染
  • Nest 是一个渐进式 Node 框架,深受 Angular 的启发。用于构建高效,可扩展的 Node 服务器端应用程序的框架。使用 TypeScript 构建,保留与纯 JS 的兼容性,集 OOP(面向对象编程),FP(函数式编程),FRP(响应式编程)一身。服务引擎盖默认使用 Express 但也提供与各种其他库的兼容性,例如 Fastify,允许轻松使用可用的无数第三方插件

如何选择正确的 Node 框架:Express,Koa 还是 Hapi

  • Express 是一个最小且灵活的 Web 应用程序框架,为 Web 和移动应用程序提供了一组强大的功能,它的行为就像一个中间件,可以帮助管理服务器和路由
  • Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造,致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理 Koa 并没有捆绑任何中间件而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序
  • Hapi 是基础功能相对丰富的框架。开发人员更专注于业务,而不是花时间构建基础架构。配置驱动的模式,区别于传统的 web 服务器操作。他还有比一个独特功能,能够在特定的 IP 上创建服务器,具有类似的功能 onPreHandler。再需要的时候你可以拦截特地的请求做一些必要的操作

nuxtjs

生命周期

  • Vue 的生命周期全都跑在客户端(浏览器),而 Nuxt 的生命周期有些在服务端(Node)、客户端,甚至两边都在。如图所示:红框内的是 Nuxt 的生命周期(运行在服务端),黄框内同时运行在服务端&&客户端上,绿框内则运行在客户端。
    生命周期图片

    vue生命周期

    vue生命周期2

nodejs

@zptime
Copy link
Owner Author

zptime commented Oct 4, 2021

[前端进阶]

Vue 篇

vue 为什么要求组件模板只能有一个根元素(实质上是技术限制)

  • 1.dom 实现上来说
    • new Vue({el:'#app'}):实例化 vue 时,必须要指定入口,再从入口文件取出所有东西渲染、处理,最后再重新插入到 dom 中。
    • 单文件组件中,template 下的元素 div:单文件组件,本质上会被各种各样的 loader 处理成为.js 文件,template 里面的内容会被 vue 处理为虚拟 dom 并渲染的内容,组件渲染也是需要指定入口的,如果在 template 下有多个 div,就无法指定该 vue 实例的根入口。为了让组件能够正常的生成一个 vue 实例,那么这个 div 会被自然的处理成程序的入口。
    • template 是 HTML5 出来的新标签,它有三个特性:
      • 1.隐藏性:该标签不会显示在页面的任何地方,即便里面有多少内容,它永远都是隐藏的状态;
      • 2.任意性:该标签可以写在页面的任何地方,甚至是 head、body、sciprt 标签内;
      • 3.无效性:该标签里的任何 HTML 内容都是无效的,不会起任何作用;
    • 通过‘根节点’,来递归遍历整个 vue‘树’下的所有节点,并处理为 vdom,最后再渲染成真正的 HTML,插入在正确的位置
  • 2.技术上,取决于 diff 算法的编写方式。显然可以对其进行更新,但是需要对当前算法进行重大更改(React 在完全重写期间进行了更改)。
  • 3.算法上:这个问题可以抽象为“逻辑抽象树为什么只能有一个根?”
    • 从效率上,如果多个根,那么就会产生多个入口(遍历、查找)从效率上来说都不方便
    • 其次,如果一颗树有多个根,其实是可以优化的。肯定存在一个子节点,通过这个该子节点访问到所有的节点。那么,优化后,这个子节点就成为了新的树的根节点

你了解 vue 的 diff 算法吗

  • 虚拟 dom:virtual dom,也就是虚拟节点。它通过 JS 的 Object 对象模拟 DOM 中的节点,然后再通过特定的 render 方法将其渲染成真实的 DOM 节点。比较两棵 DOM 树的差异是 Virtual DOM 算法最核心的部分

  • DOM DIFF:通过 JS 层面的计算,返回一个 patch 对象,即补丁对象,在通过特定的操作解析 patch 对象,完成页面的重新渲染。简单的说就是新旧虚拟 dom 的比较,如果有差异就以新的为准,然后再插入的真实的 dom 中,重新渲染

  • 当数据发生变化时,vue 是怎么更新节点的:先根据真实 DOM 生成一棵 virtual DOM,当 virtual DOM 某个节点的数据改变后会生成一个新的 Vnode,然后 Vnode 和 oldVnode 作对比,发现有不一样的地方就直接修改在真实的 DOM 上,然后使 oldVnode 的值为 Vnode。diff 的过程就是调用名为 patch 的函数,比较新旧节点,一边比较一边给真实的 DOM 打补丁

dom diff渲染图示

  1. 用 JavaScript 对象模拟 DOM
  2. 把此虚拟 DOM 转成真实 DOM 并插入页面中
  3. 如果有事件发生修改了虚拟 DOM
  4. 比较两棵虚拟 DOM 树的差异,得到差异对象
  5. 把差异对象应用到真正的 DOM 树上
  • diff 的比较方式:比较只会在同层级进行, 不会跨层级比较。比较后会出现四种情况:
  1. 此节点是否被移除 -> 添加新的节点
  2. 属性是否被改变 -> 旧属性改为新属性
  3. 文本内容被改变-> 旧内容改为新内容
  4. 节点要被整个替换 -> 结构完全不相同 移除整个替换
  • diff 流程图:当数据发生改变时,set 方法会让调用 Dep.notify 通知所有订阅者 Watcher,订阅者就会调用 patch 给真实的 DOM 打补丁,更新相应的视图。

dom diff;流程图

在.vue 文件中 style 是必须的吗?那 script 是必须的吗?为什么

在 .vue 文件中,template 是必须的,而 script 与 style 都不是必须的。都不写的话,就是一个静态页面,也是可以的。如果是普通组件那么只能是一个静态 html,如果是函数式组件, 那么可以直接使用 props 等函数式组件属性。

自己实现一个双向绑定的微型框架,你该怎么做呢

  • Object.defineProperty():是实现双向绑定的核心,最主要的作用是重写数据的 get、set 方法,现在的三大框架(vue react angular)也都是通过这个 API 来实现双向绑定的。
let obj = {
  singer: "周杰伦"
};
let value = "青花瓷";
Object.defineProperty(obj, "music", {
  // value: '七里香', // 设置属性的值 下面设置了get set函数 所以这里不能设置
  configurable: false, // 是否可以删除属性 默认不能删除
  // writable: true,  // 是否可以修改对象 下面设置了get set函数 所以这里不能设置
  enumerable: true, // music是否可以被枚举 默认是不能被枚举(遍历)
  // ☆ 通过defineProperty设置的属性,默认不能删除,不能遍历
  // ☆ get,set设置时不能设置writable和value,要一对一对设置,交叉设置/同时存在 就会报错
  get() {
    // 获取obj.music的时候就会调用get方法
    // let value = "强行设置get的返回值"; // 打开注释 读取属性永远都是‘强行设置get的返回值’
    return value;
  },
  set(val) {
    // 将修改的值重新赋给song
    value = val;
  }
});
console.log(obj.music); // 青花瓷
delete obj.music; // configurable设为false 删除无效
console.log(obj.music); // 青花瓷
obj.music = "听妈妈的话";
console.log(obj.music); // 听妈妈的话
for (let key in obj) {
  // 默认情况下通过defineProperty定义的属性是不能被枚举(遍历)的
  // 需要设置enumerable为true才可以 否则只能拿到singer 属性
  console.log(key); // singer, music
}
  • mvvm 系列的双向绑定,关键步骤:
  1. 实现数据监听器 Observer,用 Object.defineProperty()重写数据的 get、set,值更新就在 set 中通知订阅者更新数据。
  2. 实现模板编译 Compile,深度遍历 dom 树,对每个元素节点的指令模板进行替换数据以及订阅数据。
  3. 实现 Watch 用于连接 Observer 和 Compile,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图。

mvvm双向绑定

  • 1.实现数据监听器_observer():在 set 中可以监听到数据的变化,然后就可以触发 watch 更新视图。
myVue.prototype._observer = function(obj) {
  var _this = this;
  Object.keys(obj).forEach(key => {
    // 遍历数据
    _this._watcherTpl[key] = {
      // 每个数据的订阅池()
      _directives: []
    };
    var value = obj[key]; // 获取属性值
    var watcherTpl = _this._watcherTpl[key]; // 数据的订阅池
    Object.defineProperty(_this._data, key, {
      // 双向绑定最重要的部分 重写数据的set get
      configurable: true, // 可以删除
      enumerable: true, // 可以遍历
      get() {
        console.log(`${key}获取值:${value}`);
        return value; // 获取值的时候 直接返回
      },
      set(newVal) {
        // 改变值的时候 触发set
        console.log(`${key}更新:${newVal}`);
        if (value !== newVal) {
          value = newVal;
          watcherTpl._directives.forEach(item => {
            // 遍历订阅池
            item.update();
            // 遍历所有订阅的地方(v-model+v-bind+{{}}) 触发this._compile()中发布的订阅Watcher 更新视图
          });
        }
      }
    });
  });
};
  • 2.实现 Compile 模板编译
    • 首先是深度遍历 dom 树,遍历每个节点以及子节点。
    • 将模板中的变量替换成数据,初始化渲染页面视图。
    • 把指令绑定的属性添加到对应的订阅池中
    • 一旦数据有变动,收到通知,更新视图。
myVue.prototype._compile = function(el) {
  var _this = this,
    nodes = el.children; // 获取app的dom
  for (var i = 0, len = nodes.length; i < len; i++) {
    // 遍历dom节点
    var node = nodes[i];
    if (node.children.length) {
      _this._compile(node); // 递归深度遍历 dom树
    }
    // 如果有v-model属性,并且元素是INPUT或者TEXTAREA,我们监听它的input事件
    if (
      node.hasAttribute("v-model") &&
      (node.tagName = "INPUT" || node.tagName == "TEXTAREA")
    ) {
      node.addEventListener(
        "input",
        (function(key) {
          var attVal = node.getAttribute("v-model"); // 获取v-model绑定的值
          _this._watcherTpl[attVal]._directives.push(
            new Watcher(node, _this, attVal, "value") // 将dom替换成属性的数据并发布订阅 在set的时候更新数据
          );
          return function() {
            _this._data[attVal] = nodes[key].value; // input值改变的时候 将新值赋给数据 触发set=>set触发watch 更新视图
          };
        })(i)
      );
    }
    if (node.hasAttribute("v-bind")) {
      // v-bind指令
      var attrVal = node.getAttribute("v-bind"); // 绑定的data
      _this._watcherTpl[attrVal]._directives.push(
        new Watcher(node, _this, attrVal, "innerHTML") // 将dom替换成属性的数据并发布订阅 在set的时候更新数据
      );
    }
    var reg = /\{\{\s*([^}]+\S)\s*\}\}/g,
      txt = node.textContent; // 正则匹配{{}}
    if (reg.test(txt)) {
      node.textContent = txt.replace(reg, (matched, placeholder) => {
        // matched匹配的文本节点包括{{}}, placeholder 是{{}}中间的属性名
        var getName = _this._watcherTpl; // 所有绑定watch的数据
        getName = getName[placeholder]; // 获取对应watch 数据的值
        if (!getName._directives) {
          // 没有事件池 创建事件池
          getName._directives = [];
        }
        getName._directives.push(
          new Watcher(node, _this, placeholder, "innerHTML") // 将dom替换成属性的数据并发布订阅 在set的时候更新数据
        );
        return placeholder.split(".").reduce((val, key) => {
          return _this._data[key]; // 获取数据的值 触发get 返回当前值
        }, _this.$el);
      });
    }
  }
};
  • 3.Watcher 函数:在模板编译_compile()阶段发布订阅;在赋值操作的时候,更新视图
// new Watcher() 为this._compile()发布订阅+ 在this._observer()中set(赋值)的时候更新视图
function Watcher(el, vm, val, attr) {
  this.el = el; // 指令对应的DOM元素
  this.vm = vm; // myVue实例
  this.val = val; // 指令对应的值
  this.attr = attr; // dom获取值,如value获取input的值 / innerHTML获取dom的值
  this.update(); // 更新视图
}
Watcher.prototype.update = function() {
  this.el[this.attr] = this.vm._data[this.val]; // 获取data的最新值 赋值给dom 更新视图
};

vue 生命周期的原理是什么

  • vue生命周期的作用
    • 相当于一个事件
    • 准确地控制数据流和其对DOM的影响
    • 给了用户在不同阶段添加自己的代码的机会

vue 3.0计划

  • 高层 API 变动
    • 模板语法的 99% 将保持不变,scoped slot 语法可能会有一些微调。
    • 3.x 的代码库本身将用 TypeScript 来编写,并提供增强的 TypeScript 支持。
    • 3.0 版本将原生地支持基于 class 的组件,而且无需借助任何编译及各种 stage 阶段的特性。
    • 函数式组件将支持纯函数的书写形式。
    • 为了避免在安装插件时造成对 Vue 的运行时的修改,顶层 API 可能会做一个大的翻修。
    • 变动最大的部分将是渲染函数 (render) 中的虚拟DOM的格式。
  • 监测机制:3.0 带来基于 Proxy 的 observer 实现,消除了 Vue 2 中基于 Object.defineProperty 的一些局限,如:对属性的添加、删除动作的监测;对数组基于下标的修改、对于 .length 修改的监测;对 Map、Set、WeakMap 和 WeakSet 的支持。新的 observer 还有以下特性:
    • 公开的用于创建 observable (即响应式对象) 的 API。为小型到中型的应用提供了一种轻量级的、极其简单的跨组件状态管理解决方案。
    • 默认为惰性监测(Lazy Observation)。在 3.x 版本中,只有应用的初始可见部分所用到的数据会被监测。
    • 更精准的变动通知。通过 Vue.set 强制添加一个新的属性,在 3.x 中,只有依赖于这个具体属性的 watch 函数会被通知到。
    • 不可变监测对象(Immutable observable):可以创建一个对象的“不可变”版本,阻止对它的修改——包括它的嵌套属性,除非系统内部临时解除了这个限制。这种机制可以用来冻结传递到组件属性上的对象和处在 mutation 范围外的 Vuex 状态树。
    • 更良好的可调试能力:通过使用新增的 renderTracked 和 renderTriggered 钩子,可以精确地追踪到一个组件发生重渲染的触发时机和完成时机,及其原因。
  • 其他的运行时提升
    • 更小巧:对“摇树优化 (tree-shaking 一种在打包时去除没用到的代码的优化手段)”的友好。那些如内置组件 (<transition>、<keep-alive>)、运行时工具性指令(v-model)等特性将变为按需导入。新的运行时大小将永远保持在 10kb 之下。
    • 更快:整体性能提升一倍,包括虚拟DOM的挂载和打补丁(patching,指更新) 的速度,以及组件实例化速度和数据监测的性能。在 3.0 中,应用的启动时间将缩减一半。
    • 支持 Fragments 和 Portal:3.0 还将内置对 Fragments (即允许组件拥有多个根节点) 和 Portal (即允许在 DOM 的其他位置进行渲染,而不是组件内部,即跨组件渲染或者异地渲染) 的支持。
    • 增强的 slot 机制:所有由编译器生成的 slot 都将是函数形式,并且在子组件的 render 函数被调用过程中才被调用。(现在只有 scoped slot 才是函数形式,其渲染的时机也是在父组件的渲染进行时)。这使得 slot 中的数据将被作为子组件的依赖项,而不是现在的父组件;从而意味着:1)当 slot 的内容发生变动时,只有子组件会被重新渲染;2)当父组件重新渲染时,如果子组件的内容未发生变动,子组件就没必要重新渲染。这种机制可以提供更精确的变动探测,也就可以消除没必要的重渲染。
    • 支持自定义渲染器 (Renderer):这个 API 可以用来创建自定义的渲染器,将使得那些如 Weex 和 NativeScript 的“渲染为原生应用”的项目保持与 Vue 的同步更新变得更加容易。
  • 编译器相关的提升
    • “摇树友好”的输出;更多的 AOT 优化;更良好的解析错误;支持 source map。
  • 兼容 IE 11 *

vue2.0不再支持v-html中使用过滤器了怎么办

  • 全局方法
  • computed
  • $options.filters,过滤器 Vue.filter
// 使用
v-html="htmlFilter(htmlString)"

// 全局方法
Vue.prototype.htmlFilter= function (msg) {
   return msg.replace("\n", "<br>")
};

// computed
computed: {
  htmlFilter(msg){
    return msg.replace("\n","<br>")
  }
}

// $options.filters
v-html="$options.filters.htmlFilter(msg)"
filters:{
  htmlFilter:function(msg){
    return msg.replace(/\n/g,"<br>")
  }
}

v-if和v-show

(1)关于条件渲染
所谓条件渲染,就是根据不同的条件,使用不同的模板来生成 html。 在 Vue.js 中,使用 v-if 和 v-show 指令来控制条件渲染。

(2)区别
v-show 会在app初始化的时候编译并且渲染,并且在之后一直存在。当切换v-show模块时,只是简单的更改css。

v-if 当切换v-if模块时,Vue.js 有一个局部编译/卸载过程,因为 v-if 之中的模板也可能包括数据绑定或子组件。v-if 是真实的条件渲染,因为它会确保条件块在切换当中合适地销毁与重建条件块内的事件监听器和子组件。 v-if 是惰性的,如果为false,则什么也不错-不编译,不渲染。 当第一次条件为真时,才开始局部编译(编译会被缓存起来)。

(3)建议
v-show的切换消耗比较低,但是不会重新渲染子组件,所以最好用于静态的内容或者不需要重新构建结构的组件。

而 v-if 比较适合不太频繁的切换状态的组件。所以项目设计的时候,不要对复杂的业务设计模块太频繁的视图切换。尽量将静态内容和动态内容分离到不同的模块中。

一般来说,v-if 有更高的切换消耗而 v-show 有更高的初始渲染消耗。因此,如果需要频繁切换 v-show 较好,如果在运行时条件不大可能改变 v-if 较好。在v-show中,元素是一直存在的,当v-show为false时,元素display:none只是隐藏了而已。

前端数据驱动模式

  • 传统的模式:响应用户操作->发送数据给后台->拿到新数据->更新UI(维护DOM)
    • 事件驱动,一个很典型的例子就是 jQuery。
    • 用 jQuery 开发的页面执行初期:通过特定的选择器查找到需要操作的节点 -> 给节点添加相应的事件监听
    • 响应用户操作:用户执行某事件(点击,输入,后退等等) -> 调用 JavaScript 来修改节点
    • 这种模式,对于业务需求简单的页面来说没什么问题。只是现在前端越来越复杂,光用这样的模式已经满足不了很多大型项目的需求。另一方面,找节点和修改节点这件事儿,效率本身就很低。
  • 数据驱动模式:响应用户操作->发送数据给后台->拿到新数据->更新前端model。Angular,Vue是典型的“数据驱动”的前端框架
    • 以MVVM 来举例子,执行初期就像这样:读取模板,同时获得数据,并建立 VM(view-model) 的抽象层 -> 在页面进行填充
    • MVVM 对应了三个层,M - Model,数据层;V - View,视图或者网页界面;VM - ViewModel,一个抽象层,简单来说可以认为是 V 层中抽象出的数据对象,并且可以与 V 和 M 双向互动(一般实现是基于双向绑定,双向绑定的处理方式在不同框架中不尽相同)。
    • 针对用户的操作,大致是这样:用户执行某个操作 -> 反馈到 VM 处理(可以导致 Model 变动) -> VM 层改变,通过绑定关系直接更新页面对应位置的数据
    • 总结一下:数据驱动不是操作节点的,而是通过虚拟的抽象数据层来直接更新页面。
  • 后者与前者的区别是不需要去维护复杂的DOM,而是只需要维护前端model,所有基于model的UI部分会自动更新。省去了维护繁琐的DOM结构的工作。

vue依赖的软件环境

  • vuejs核心
  • VueRouter2实现路由组织工具
  • webpack项目打包以及编译工具
  • nodejs前端开发环境
  • npm前端包管理器
  • vue-resource接口请求工具,axios,fetch
  • sass-loader和node-sass css预处理
  • vue-cli vue项目脚手架,一键安装vue的工具

vue-router

  • active-class是哪个组件的属性?嵌套路由怎么定义?
    • vue-router模块的router-link组件
  • 怎么定义vue-router的动态路由?怎么获取传过来的动态参数?
    • 在router目录下的index.js文件中,对path属性加上/:id。 使用router对象的params.id
  • vue-router有哪几种导航钩子?三种
    • 全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截。afterEach((to, from)
    • 组件内的钩子:beforeRouteEnter,beforeRouteUpdate (2.2 新增),beforeRouteLeave
    • 单独路由独享组件beforeEnter: (to, from, next) => {}

MVVM框架是什么?它和其它框架(jquery)的区别是什么?哪些场景适合?

  • 一个model+view+viewModel框架,数据模型model,viewModel连接两个
  • 区别:vue数据驱动,通过数据来显示视图层而不是节点操作。
  • 场景:数据操作比较多的场景,更加便捷
  • DOMListeners和DataBindings是实现双向绑定的关键。DOMListeners监听页面所有View层DOM元素的变化,当发生变化,Model层的数据随之变化;DataBindings监听Model层的数据,当数据发生变化,View层的DOM元素随之变化。

directives指令

  • 自定义指令(v-check、v-focus)的方法有哪些?它有哪些钩子函数?还有哪些钩子函数参数?
    • 全局定义指令:在vue对象的directive方法里面有两个参数,一个是指令名称,另外一个是函数。组件内定义指令:directives
    • 钩子函数:bind(绑定事件触发)、inserted(节点插入的时候触发)、update(组件内相关更新)
    • 钩子函数参数:el、binding

vue双向数据绑定实现原理

  • vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
    • 第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter。这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
    • 第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
    • 第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
      1、在自身实例化时往属性订阅器(dep)里面添加自己
      2、自身必须有一个update()方法
      3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
    • 第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

vue的生命周期

  • 总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
    • 创建前/后: 在beforeCreated阶段,vue实例的挂载元素$el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,$el还没有。
    • 载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
    • 更新前/后:当data变化时,会触发beforeUpdate和updated方法。
    • 销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在

vuex

  • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
    • state,驱动应用的数据源;
    • view,以声明方式将 state 映射到视图;
    • 改变状态的方式是提交mutations,这是个同步的操作
    • actions,响应在 view 上的用户输入导致的状态变化,异步逻辑应该封装在action中。
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    },
    incrementAsync ({ commit }) {
      setTimeout(() => {
        commit('increment')
      }, 1000)
    }
  }
})

store.commit('increment')
store.dispatch('increment') // mapState, mapGetters, mapActions 和 mapMutations
store.dispatch('incrementAsync', { amount: 10 }) // 以载荷形式分发
store.dispatch({ type: 'incrementAsync', amount: 10 }) // 以对象形式分发

vue-loader是什么?使用它的用途有哪些?

  • 解析.vue文件的一个加载器,将template/js/style转换成js模块。
  • 用途:js可以写es6、style样式可以scss或less、template可以加jade等

模块化(AMD,CMD,CommonJS)

  • CommonJS:用于服务器
  • AMD:用于浏览器
  • ES6:import/export
    • ES6在编译时就能确定模块的依赖关系,AMD和CommonJS运行时确定

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant