前端面试(五)MVVM

jQuery和现在使用vue和React框架的区别

  • jQuery实现todo-list

<body>
    <div>
        <input type="text" name="" id="txt-title">
        <button id="btn-submit">submit</button>
    </div>
    <div>
        <ul id="ul-list"></ul>
    </div>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <script>
      var $txtTitle = $('#txt-title')
      var $btnSubmit = $('#btn-submit')
      var $ulList = $('#ul-list')
      $btnSubmit.click(function() {
        var txt = $txtTitle.val()
        if (!title) {
          return
        }
        var $li = `<li>${txt}</li>`
        $ulList.append($li)
        $txtTitle.val('')
      })
    </script>
</body>复制代码

  • vue实现todo-list

<body>
    <div id="app">
        <div>
          <input type="text" v-model="title">
          <button @click="add">submit</button>
        </div>
        <div>
          <ul>
            <li v-for="(item, index) in list" :key="index">{{item}}</li>
          </ul>
        </div>
    </div>
    <script src="https://unpkg.com/vue"></script>
    <script>
    var vm = new Vue({
      el: '#app',
      data: {
        title: ''
      },
      methods: {
        add() {
          this.list.push(this.title)
          this.title = ''
        }
      }
    })
    </script>
</body>复制代码

  • jQuery 和框架的区别

(1)数据和视图的分离(解耦:开放封闭原则)

(2)以数据驱动视图(只关心数据变化,DOM操作被封装)

如何理解MVVM

  • MVVM框架的三大要素:

(1)响应式:vue如何监听到data的每个属性变化?

(2)模板渲染:vue的模板如何被解析,指令如何处理?

(3)渲染:vue的模板如何被渲染成html?以及渲染过程?

  • MVC

(1)M:Model数据

(2)V:View视图、界面

(3)C:Controller控制器、逻辑处理

一般都是view发送命令到控制器,控制器修改model,model再将修改对应到View

  • MVVM(MVC微创新)

(1)Model:模板、数据

(2)View:视图、模板(视图和模型是分离的)

(3)ViewModel:连接Model和View


  • 关于ViewModel

如何实现MVVM


vue如何实现响应式

(1)关键是理解Object.defineProperty

(2)将data的属性代理到vm上

  • 什么是响应式

(1)修改data属性之后,vue立刻监听到

(2)data属性被代理到vm上

<script>
var obj = {
  name: '老王',
  age: '40'
}
console.log(obj.name) // 设置obj.name为静态的值类型
obj.name = '111' // 怎么样能监听到
console.log(obj.name) // 怎么样能监听到

var obj = {}
var name = '张三'
Object.defineProperty(obj, "name", { // 当使用Object.defineProperty后设置的name为一个属性
  // 将属性的获取、设置都定义为了一个函数 并可以加入自己的逻辑
  get: function () {
    console.log('get')
    return name
  },
  set: function (newVal) {
    console.log('set')
    name = newVal
  }
})
obj.name = '111' // 可以监听到
console.log(obj.name) // 可以监听到
</script>复制代码

  • 模拟

var vm = new Vue({
  el: '#app',
  data: {
    price: 10,
    name: '老王'
  }
})
// 模拟上面的vue实例
var vm = {}
var data = {
  price: 10,
  name: '老王'
}
var key, val
for (key in data) {
  // 命中闭包 新建一个函数,保证key的独立作用域
  (function (key) { // 把当时的key 保留下来
    Object.defineProperty(vm, key, {
      get: function() {
        console.log('get') // 监听
        return data[key]
      },
      set: function(newVal) {
        console.log('set') // 监听
        data[key] = newVal
      }
    })
  })(key)
}复制代码

vue如何解析模板

  • 模板是什么?

    <div id="app">
        <div>
          <input type="text" v-model="title">
          <button @click="add">submit</button>
        </div>
        <div>
          <ul>
            <li v-for="(item, index) in list" :key="index">{{item}}</li>
          </ul>
        </div>
    </div>复制代码

(1)本质:字符串

(2)有逻辑: 如v-if v-for等

(3)与html格式很像,但又很大的区别

(4)最终还是要转换html显示:1、模板最终必须转换成JS代码,因为有逻辑(v-if、v-for),必须用JS才能实现(图灵完备);2、转换为html渲染页面,必须用JS才能实现;3、模板最终转换成一个JS函数(render函数)

  • render函数(模板中所有的信息)

(1)模板中所有信息都包含在了render函数中

(2)this即vm

(3)price 即this.price即vm.price,即data中的price

(4)_c即this._c即vm._c

<body>
    <div id="app">
        <p>{{price}}</p>
    </div>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                price: 100
            }
        })

        function render() {
            with(this) {  // this 就是 vm
                return _c(
                    'div',
                    {
                        attrs: {'id': 'app'}
                    },
                    [
                        _c('p', [_v(_s(price))])
                    ]
                )
            }
        }

        function render1() {
            return vm._c(
                'div',
                {
                    attrs: {'id': 'app'}
                },
                [
                    vm._c('p', [vm._v(vm._s(vm.price))])
                ]
            )
        }

    </script>
</body>复制代码

<body>
    <div id="app">
        <div>
            <input v-model="title">
            <button v-on:click="add">submit</button>
        </div>
        <div>
            <ul>
                <li v-for="item in list">{{item}}</li>
            </ul>
        </div>
    </div>

    <script type="text/javascript">
        // data 独立
        var data = {
            title: '',
            list: []
        }
        // 初始化 Vue 实例
        var vm = new Vue({
            el: '#app',
            data: data,
            methods: {
                add: function () {
                    this.list.push(this.title)
                    this.title = ''
                }
            }
        })

        // render 函数
        with(this){  // this 就是 vm
            return _c(
                'div',
                {
                    attrs:{"id":"app"}
                },
                [
                    _c(
                        'div',
                        [
                            _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
                                    }
                                },
                                [_v("submit")]
                            )
                        ]
                    ),
                    _v(" "),
                    _c('div',
                        [
                            _c(
                                'ul',
                                _l((list),function(item){return _c('li',[_v(_s(item))])})
                            )
                        ]
                    )
                ]
            )
        }

    </script>
</body>复制代码

  • render函数-with的用法(vue用到,不推荐日常使用)

var obj = {
  name: '老王',
  age: '40',
  getAddress: function() {
    alert('1111')
  }
}

// 不用with
function fn() {
  alert(obj.name)
  alert(obj.age)
  obj.getAddress()
}
fn()

// 使用with 可读性不高
function fn1() {
  with(obj) {
    alert(name)
    alert(age)
    getAddress()
  }
}
fn1()复制代码

  • render函数与vdom(render函数返回的就是vdom)

(1)updateComponent中实现了vdom的patch

(2)页面首次渲染执行updateComponent(把vnode渲染到容器中)

(3)data中每次修改属性,都会执行updateCompoent


介绍vue的实现流程

  • 解析模板成render函数

(1)with的用法

(2)模板中的所有信息都被render函数包含

(3)模板中用到的data中的属性,都变成了JS变量

(4)模板中的v-model v-for v-on 都变成了JS逻辑

(5)render函数返回vnode

  • 响应式开始监听

(1)Object.defineProperty

(2)将data的属性代理到vm上

  • 首次渲染,显示页面,且绑定依赖

(1)初次渲染,执行updateComponent,执行vm._render()

(2)执行render函数,会访问到vm.list和vm.title(data变量)

(3)会被响应式的get方法监听到

为什么要监听get,直接监听set不行吗?

data中有很多属性,有些被用到,有些可能不被用到;被用到的会走到get,不被用到的不会走到get;未走到get中的属性,set的时候我们也无需关心;避免不必要的重复渲染

(4)执行updateComponent,会走到vdom的patch方法

(5)patch 将vnode渲染成DOM,初次渲染完成

  • data属性变化,触发render

(1)修改属性,被响应式的set监听到

(2)set中执行updateComponent

(3)updateComponent重新执行vm._render()

(4)生成vnode和prevVnode,通过patch进行对比

(5)渲染到html中


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值