一、new vue时同时写了templet和render函数,优先渲染哪一个?

  1. const vm = new Vue({
  2. el: '#app',
  3. template: '<h1>{{ msg }}</h1>',
  4. render(h) {
  5. return h('h1', this.msg)
  6. },
  7. data: {
  8. msg: 'Hello Vue'
  9. }
  10. })

new vue时,这样写,在有编译器的vue版本下,是先渲染render,入口文件源码如下;

  1. // 把 template/el 转换成 render 函数
  2. if (!options.render) {
  3. let template = options.template
  4. // 如果模板存在
  5. ...
  6. }

`

二、创建vue采用的构造函数而不是class

不用 class 的原因是因为方便后续给 Vue 实例混入实例成员

  1. // 此处不用 class 的原因是因为方便后续给 Vue 实例混入实例成员
  2. function Vue (options) {
  3. if (process.env.NODE_ENV !== 'production' &&
  4. !(this instanceof Vue)
  5. ) {
  6. warn('Vue is a constructor and should be called with the `new` keyword')
  7. }
  8. // 调用 _init() 方法
  9. this._init(options)
  10. }
  11. // 注册 vm 的 _init() 方法,初始化 vm
  12. initMixin(Vue)
  13. // 注册 vm 的 $data/$props/$set/$delete/$watch
  14. stateMixin(Vue)
  15. // 初始化事件相关方法
  16. // $on/$once/$off/$emit
  17. eventsMixin(Vue)
  18. // 初始化生命周期相关的混入方法
  19. // _update/$forceUpdate/$destroy
  20. lifecycleMixin(Vue)
  21. // 混入 render
  22. // $nextTick/_render
  23. renderMixin(Vue)

三、注册 Vue.use() 用来注册插件

  1. export function initUse (Vue: GlobalAPI) {
  2. Vue.use = function (plugin: Function | Object) {
  3. //installedPlugins数组来存储已经注册了的插件
  4. const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
  5. //如果插件已经注册,直接返回
  6. if (installedPlugins.indexOf(plugin) > -1) {
  7. return this
  8. }
  9. // additional parameters
  10. // 把数组中的第一个元素(plugin)去除
  11. const args = toArray(arguments, 1)
  12. // 把this(Vue)插入第一个元素的位置
  13. args.unshift(this)
  14. //传入的插件是对象,调用他的install方法直接注册
  15. if (typeof plugin.install === 'function') {
  16. //在plugin下传入args参数执行
  17. plugin.install.apply(plugin, args)
  18. } else if (typeof plugin === 'function') {
  19. //如果传入的插件是函数,直接调用函数注册
  20. plugin.apply(null, args)
  21. }
  22. //最后将插件放入已经注册好的列表里
  23. installedPlugins.push(plugin)
  24. return this
  25. }
  26. }

四、Vue.minx实现

  1. export function initMixin (Vue: GlobalAPI) {
  2. Vue.mixin = function (mixin: Object) {
  3. //把mixin的成员全部拷贝到vue.options中
  4. this.options = mergeOptions(this.options, mixin)
  5. return this
  6. }
  7. }

五、Provide / Inject使用

provide/inject用于父子组件传参;
我们也可以在组合式 API 中使用 provide/inject。两者都只能在当前活动实例的 setup() 期间调用;
父组件provide,子组件接收inject
为了增加 provide 值和 inject 值之间的响应性,我们可以在 provide 值时使用 refreactive

  1. setup() {
  2. const location = ref('North Pole')
  3. const geolocation = reactive({
  4. longitude: 90,
  5. latitude: 135
  6. })
  7. provide('location', location)
  8. provide('geolocation', geolocation)
  9. }

六、谈一下你对MVVM原理的理解

image.png
传统的 MVC 指的是,用户操作会请求服务端路由,路由会调用对应的控制器来处理,控制器会获取数
据。将结果返回给前端,页面重新渲染
MVVM :传统的前端会将数据手动渲染到页面上, MVVM 模式不需要用户收到操作 dom 元素,将数据绑
定到 viewModel 层上,会自动将数据渲染到页面中,视图变化会通知 viewModel层 更新数据。
ViewModel 就是我们 MVVM 模式中的桥梁.

七、 请说一下响应式数据的原理?

理解:
1.核心点: Object.defineProperty
2.默认 Vue 在初始化数据时,会给 data 中的属性使用 Object.defineProperty 重新定义所有属
性,当页面取到对应属性时。会进行依赖收集(收集当前组件的watcher)
如果属性发生变化会通
知相关依赖进行更新操作。
image.png

  1. Object.defineProperty(obj, key, {
  2. enumerable: true,
  3. configurable: true,
  4. get: function reactiveGetter () {
  5. // 如果预定义的 getter 存在则 value 等于getter 调用的返回值
  6. // 否则直接赋予属性值
  7. const value = getter ? getter.call(obj) : val
  8. // 如果存在当前依赖目标,即 watcher 对象,则建立依赖
  9. if (Dep.target) {
  10. dep.depend()
  11. // 如果子观察目标存在,建立子对象的依赖关系
  12. if (childOb) {
  13. childOb.dep.depend()
  14. // 如果属性是数组,则特殊处理收集数组对象依赖
  15. if (Array.isArray(value)) {
  16. dependArray(value)
  17. }
  18. }
  19. }
  20. // 返回属性值
  21. return value
  22. }