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和MVVM面试题 #64

Open
yym-yumeng123 opened this issue Feb 18, 2019 · 0 comments
Open

Vue和MVVM面试题 #64

yym-yumeng123 opened this issue Feb 18, 2019 · 0 comments

Comments

@yym-yumeng123
Copy link
Owner

说一下 jQuery 和 使用框架的区别

  • jQuery 实现 todo-list
<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-1.9.1.min.js"></script>
  <meta charset="utf-8">
  <title>todo</title>
</head>
<body>
  <input type="text" id="input">
  <button id="btn-submit">提交</button>
  
  <div>
    <ul id="ul-list"></ul>
  </div>
  
  <script>
    let $ipt = $('#input')
    let $sub = $('#btn-submit')
    let $list = $('#ul-list')

    $sub.click(() => {
      let title = $ipt.val()
      let $li = $('<li>' + title + '</li>')
      $list.append($li)
      $ipt.val('')
    })
  </script>
</body>
</html>
  • vue 实现 todo-list
<!DOCTYPE html>
<html>
<head>
<script src="http://vuejs.org/js/vue.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <div id="app">
     <input type="text" v-model="title">
    <button @click="add">提交</button>

    <div>
      <ul>
        <li v-for="item in list">{{ item }}</li>
      </ul>
    </div>
  </div>
  <script>
    new Vue({
      el: '#app',
      data: {
        title: '',
        list: []
      },
      methods: {
        add () {
          this.list.push(this.title)
          this.title = ''
        }
      }
    })
  </script>
</body>
</html>

区别 :

  • 数据和视图的分离, 解耦 (开放封闭原则)
  • 以数据驱动视图, 只关心数据变化, DOM操作被封装

说一下 MVVM 的理解

  • MVC
    • MVVM 不算是一种创新
    • 但其中的 ViewModel 确实是一种创新
    • 真正结合前端场景应用的创建
M -- Model 模型/数据源
V -- View 视图
C -- Controller 控制器 / 控制 view 和 model 的变化
  • MVVM
// 回顾 Vue todo-list 例子

// 对应 View 视图 模板 (视图和模板是分离的)
<div id="app">
    <input type="text" v-model="title">
    <button @click="add">提交</button>

    <div>
        <ul>
            <li v-for="item in list">{{ item }}</li>
        </ul>
    </div>
</div>

// 对应 Model
var data = {
    title: '',
    list: []
},

// VM ViewModel   Vue实例 事件绑定 数据绑定, 类似于桥梁
new Vue({
    el: '#app',
    data: {
        title: '',
        list: []
    },
    methods: {
        add () {
            this.list.push(this.title)
            this.title = ''
        }
    }
})
  • 总结
    • MVVM - Model View ViewModel
    • 三者之间联系, 以及如何对应隔断代码
    • ViewModel 的理解, 联系 ViewModel

MVVM 框架的三要素

  • 响应式 : vue 如何坚挺到 data 的每个属性变化
  • 模板引擎 : vue的模板如何被解析, 指令如何处理
  • 渲染: vue 的模板如何呗渲染成 html ? 以及渲染过程

1. vue中如何实现响应式

  • 什么是响应式
    • 修改 data 属性之后, vue 立刻监听到
    当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,
    并使用 Object.defineProperty 把这些属性全部转为 getter/setter。
    这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
    
    • data 属性被代理到 vm
    var vm = new Vue({
      data:{
        a:1
      }
    })
    // `vm.a` 是响应的
    
    vm.b = 2
    // `vm.b` 是非响应的
    
    • Object.defineProperty
      • Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
    var obj = {a: 1}
    Object.defineProperty(obj, 'a', {
        get () {
            console.log('get')
            return a
        },
        set (newVal) {
            console.log('set')
            a = newVal
        }
    })
    obj.a = 3
    
// 模拟实现
var vm = {}
var data = {
    price: 100,
    name: 'yym'
}

var key, value
for(key in data) {
    // 闭包, 新建一个函数,保证 key 的独立作用域
    (function (key) {
        Object.defineProperty(vm, key, {
            get () {
                return data[key]
            },
            set (newval) {
                data[key] = newVal
            }
        })
    })(key)
}

2. vue 中如何解析模板

  • 模板是什么
    • 本质 : 字符串
    • 有逻辑 , 如 v-if v-for
    • html 格式很像, 但又很大区别
    • 最后还要转换为 html 来显示
    • 模板最终必须转换为JS代码, 因为 :
      • 有逻辑, 必须用JS才能实现 (图灵完备)
      • 转换为 html 渲染页面, 必须用 JS 才能实现
      • 因此, 模板最重要转换为一个JS函数 (render 函数)
<div id="app">
    <input type="text" v-model="title">
    <button @click="add">提交</button>

    <div>
        <ul>
            <li v-for="item in list">{{ item }}</li>
        </ul>
    </div>
</div>

render 函数

with 的用法
var obj = {
    name: 'yym',
    age: 20,
    getAdd () {
        // todo...
    }
}

不使用with
function fn1() {

    alert(obj.name)
    alert(obj.age)
    obj.getAdd()
}
fn1()

使用 with
function fn1() {
    with(obj) {
        alert(name)
        alert(age)
        getAdd()
    }
}
fn1()

render函数

<div id="app">
   <p>{{price}}</p>
</div>
<script>
   new Vue({
       el: '#app',
       data: {
           price: 100,
       }
   })
</script>

- 模板中所有信息都包含在render函数中
- this 即 vm
- price 即 this.price 即 vm.price, 即 data 中的 price

function render () {
   with(this) {
       return _c(  // createElement
           'div',
           {
               attrs: {"id": "app"}  // 属性
           },
           [
               _c('div',[_v(_s(price))])
           ],
       )
   }
}
// todo-list 的 render 函数
 
function render () {
    with(this) {
        return _c('div', {
                attrs: {"id": "app"}
            },
            [
                _c('div',[_v(_s(price))])
            ],
            [
                _c('input',
                    {
                        directives: [{
                            name: 'model',
                            rawName:: 'v-model',
                            value: (title),
                            expression: 'title'
                        }],
                        domProps: {
                            "value": (title)
                        },
                        on: {
                            "input": function($event) {
                                if ($event.target.composing) return
                                title = $event.target.value
                            }
                        }
                    }
                ) , _v(" "), _c('button', {
                    on: {
                        "click": add
                    }
                })
                // ...
            ]
        )
    }     
}

3. vue 的整个实现流程

  1. 解析模板成 render 函数
    • with 的用法
    • 模板中所有信息被 render 函数包含
    • 模板中用到的 data 中的属性, 变成 js 变量
    • 模板中的 v-model v-for @on 变成 JS 逻辑
    • render 返回 vnode
  2. 响应式开始监听
    • Object.defineProperty
    • data 代理到 vm
  3. 首次渲染, 显示页面, 且绑定依赖
    • 初次渲染, 执行updateComponent, 执行 vm._render()
    • 执行render 函数, 会访问 vm.list 和vm.title
    • 会被响应式 get 方法监听到
    • 执行 updateComponent, 会走到 vdom 的patch 方法
    • patch 将 vnode 渲染成DOM, 初次渲染完成
  4. data 属性变化, 触发 rerender
    • 修改属性, 被 响应式 set 监听到
    • set 执行 updateComponent
    • updateComponent, 重新执行 vm._render()
    • 生成 vnode 和prevVnode ,通过 patch 进行对比
    • 渲染到 html
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