慕课1299前端面试题-vue2模块包含原理

VUE2相关

我的博客可能需要缩款宽屏幕观看,图片无法均衡,很抱歉。

1. 指令、插值

在这里插入图片描述
在这里插入图片描述

2. computed 和 watch

在这里插入图片描述

computed 计算属性,v-model要有get 和 set

<template>
  <div>
    <p>num :{
    
    {
    
     num }} 答案: 20</p>
    <p>double1 {
    
    {
    
     double1 }} 答案: 40</p>
    <input v-model="double2" />
  </div>
</template>

<script>
export default {
    
    
  data() {
    
    
    return {
    
    
      num: 20,
    }
  },
  computed: {
    
    
    double1() {
    
    
      return this.num * 2
    },
    double2: {
    
     // v-model使用一定要有 get和set 
      get() {
    
      // 如果只有一个 get 或 set 会报错
        return this.num * 2
      },
      set(val) {
    
    
        this.num = val / 2
      },
    },
  },
}
</script>

watch监听,引用类型, 拿不到 oldVal。

<template>
  <div>
    <input v-model="name" />
    <input v-model="info.city" />
  </div>
</template>

<script>
export default {
    
    
  data() {
    
    
    return {
    
    
      name: 'watch监听',
      info: {
    
    
        city: '北京',
      },
    }
  },
  watch: {
    
    
    // watch监听
    name(oldVal, val) {
    
    
      // 值类型,可正常拿到 oldVal 和 val
      console.log('watch name', oldVal, val)
    },
    info: {
    
    
      handler(oldVal, val) {
    
    
        // 引用类型, 拿不到 oldVal 。 因为指针相同,此时已经指向了新的 val
        console.log('watch info', oldVal, val)
      },
      deep: true, // 深度监听
    },
  },
}
</script>

3. class 和 style

在这里插入图片描述
在这里插入图片描述

4. 条件渲染

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

5. 循环列表 v-for

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

6. 事件 event

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1. event 事件是原生的。 2. 事件被挂载到当前元素。
    在这里插入图片描述

7. 事件修饰符

在这里插入图片描述
在这里插入图片描述

8. 表单

在这里插入图片描述

<template>
  <div>
    <p>输入框 : {
    
    {
    
     name }}</p>
    <!-- 1. trime 截取前后空格
         2. lazy 类似防抖效果
         3. number 转换为数字 -->
    <input type="text" v-model.trim="name" />
    <input type="text" v-model.lazy="name" />
    <input type="text" v-model.number="age" />

    <p>多行文本 : {
    
    {
    
     desc }}</p>
    <textarea v-model="desc"></textarea>
    <!-- 注意,<textarea> {
    
    {
    
     desc }} </textarea> 是不允许的!!!-->

    <p>复选框 {
    
    {
    
     checked }}</p>
    <input type="checkbox" v-model="checkbox" />

    <p>多个复选框 {
    
    {
    
     checkedNames }}</p>
    <input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
    <label for="jack">Jack</label>
    <input type="checkbox" id="join" value="John" v-model="checkedNames" />
    <label for="john">John</label>
    <input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
    <label for="mike">Mike</label>

    <p>单选{
    
    {
    
     gender }}</p>
    <input type="radio" id="male" value="male" v-model="gender" />
    <label for="male"></label>
    <input type="radio" id="female" value="female" v-model="gender" />
    <label for="female"></label>

    <p>下拉列表选择 {
    
    {
    
     selected }}</p>
    <select v-model="selected">
      <option disabled value="">请选择</option>
      <option>A</option>
      <option>B</option>
      <option>C</option>
    </select>

    <p>下拉列表选择 (多选) {
    
    {
    
     selectedList }}</p>
    <select v-model="selectedList" multiple>
      <option disabled value="">请选择</option>
      <option>A</option>
      <option>B</option>
      <option>C</option>
    </select>
  </div>
</template>

<script>
export default {
    
    
  data() {
    
    
    return {
    
    
      name: '德玛西亚',
      age: 18,
      desc: '自我介绍',

      checked: true, // 单个复选框
      checkedNames: [], // 多个复选框

      gender: 'male', // 性别

      selected: '', // 下拉列表单选
      selectedList: [], // 下拉列表多选
    }
  },
}
</script>

9. VUE组件使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

10. 自定义 v-model

在这里插入图片描述

在这里插入图片描述

11. $nextTick

<template>
  <div id="app">
    <ul ref="ul1">
      <li v-for="(item, index) in list" :key="index">
        {
    
    {
    
     item }}
      </li>
    </ul>
    <button @click="addItem">添加一项</button>
  </div>
</template>

<script>
export default {
    
    
  name: 'app',
  data() {
    
    
    return {
    
    
      list: ['a', 'b', 'c'],
    }
  },
  methods: {
    
    
    addItem() {
    
    
      this.list.push(`${
      
      Date.now()}`)
      this.list.push(`${
      
      Date.now()}`)
      this.list.push(`${
      
      Date.now()}`)

      // 获取 DOM 元素
      const ulElem = this.$refs.ul1
      
      console.log(ulElem.childNodes.length)
    },
  },
}
</script>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

12. slot多种用法

  • 1. 默认插槽
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 2.具名插槽
    如果我们需要在同一个组件使用多个插槽,那么就需要使用具名插槽
    在这里插入图片描述
    在这里插入图片描述
  • 3. 作用域插槽
    在这里插入图片描述
  • 作用域插槽
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

13. 动态组件

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

<template>
  <div>
    <!-- 动态组件 -->
    <component :is="NextTickName"></component>
    <!-- 动态组件 -->
    <div v-for="(val, key) in newsData" :key="key">
      <component :is="val.type"></component>
    </div>
  </div>
</template>

<script>
import NextTick from './NextTick'
export default {
    
    
  components: {
    
    
    // 注册组件
    NextTick,
  },
  data() {
    
    
    return {
    
    
      // 动态组件
      NextTickName: 'NextTick',
      // 动态组件
      newsData: {
    
    
        1: {
    
    
          type: 'text',
        },
        2: {
    
    
          type: 'text',
        },
        3: {
    
    
          type: 'image',
        },
      },
    }
  },
}
</script>

14. 异步组件

在这里插入图片描述
在这里插入图片描述

15. Keep-alive 缓存组件

在这里插入图片描述

<template>
  <div>
    <button @click="changeState('A')">A</button>
    <button @click="changeState('B')">B</button>
    <button @click="changeState('C')">C</button>

    <KeepAliveStageA v-if="state === 'A'" />
    <KeepAliveStageB v-if="state === 'B'" />
    <KeepAliveStageC v-if="state === 'C'" />
  </div>
</template>
<script>
import KeepAliveStageA from './KeepAliveStateA' // 引入组件
import KeepAliveStageB from './KeepAliveStateB'
import KeepAliveStageC from './KeepAliveStateC'
export default {
    
    
  components: {
    
    
    KeepAliveStageA,
    KeepAliveStageB,
    KeepAliveStageC, // 注册组件
  },
  data() {
    
    
    return {
    
    
      state: 'A', // 默认显示 A 组件
    }
  },
  methods: {
    
    
    // 点击事件,动态传值,修改 data中的state,从而改变组件
    changeState(state) {
    
    
      this.state = state
    },
  },
}
</script>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

16. mixin 的使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

17. VUEX

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

18. vue-router

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

高阶,做好准备,Let’s see

1. vue原理

在这里插入图片描述

2. 如何理解MVVM

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. Vue响应式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

// 触发更新视图
function updateView() {
    
    
  console.log('视图更新');
}

// 监听数组,需要重新定义数组的原型
const oldArrayProperty = Array.prototype
// 创建新对象,原型指向 oldArrayProperty, 再扩展新的方法不会影响原型
const arrProto = Object.create(oldArrayProperty)
// methodName 其实就是 push,pop等 这些名字
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
    
    
  // 对每个方法都进行一个 定义
  arrProto[methodName] = function () {
    
    
    updateView() // 触发视图更新
    oldArrayProperty[methodName].call(this, ...arguments)
    // oldArrayProperty 方法就是 Array.prototype.call(this,...arguments)
  }
})

// 重新定义属性,监听起来   
// (target 就是data , key 就是data中的name或age , value 就是name的值zhangsan 或 age 的值20)
function defineReactive(target, key, value) {
    
    
  // 深度监听,针对 info 层级比较深的 结构
  observer(value)

  // 核心 API
  Object.defineProperty(target, key, {
    
    
    get() {
    
     // 获取
      return value
    },
    set(newValue) {
    
     // 设置
      // 例如 data.name = '测试名字' 就会走这里
      if (newValue !== value) {
    
    
        // 针对 info 也需要深度监听
        observer(newValue)

        // 设置新值
        // 注意,value 一直在闭包中,此处设置完之后,再get时也是会获取最新的数据
        value = newValue

        //触发更新视图
        updateView()
      }
    }
  })
}

// 监听对象属性
function observer(target) {
    
    
  if (typeof target !== 'object' || target === null) {
    
    
    //监听不是对象或数组,返回
    return target
  }

  // 污染全局 Array 原型 (一定不可以!!!) 
  // 必须重新定义原型 不可污染全局 Array 原型
  // Array.prototype.push = function () {
    
    
  //   updateView()
  //   ...
  // }

  // 如果是数组
  if (Array.isArray(target)) {
    
    
    target._proto_ = arrProto
  }

  // 重新定义各个属性 (for in  也可以遍历数组)
  for (let key in target) {
    
    
    defineReactive(target, key, target[key])
  }
}

// 准备数据
const data = {
    
    
  name: 'zhangsan',
  age: 20,
  // 针对 info 来说target 就是data , key 就是info , age 就是对象{}   
  info: {
    
    
    address: '北京' // 需要深度监听
  },
  nums: [10, 20, 30]
}

// 监听数据
observer(data)

// 测试
data.name = '测试名字'
data.age = 25
// console.log('age', data.age); // 打印结果'age', 25
// data.x = '100' // 新增属性,监听不到 -- 所以有 Vue..set
// delete data.name // 删除属性,监听不到 -- 所以有 Vue.delete
data.info.address = '上海' // 深度监听
data.nums.push(4) // 监听数组

在这里插入图片描述

  • 拿代码中 info 举例,如果 info: { { {}}} 像这样层级较深,它会一直走observer(value),一直递归到底
    在这里插入图片描述

4. 虚拟 DOM (Virtual DOM)和 diff算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
看此篇文章snabbdom在github讲解很详细
在这里插入图片描述
在这里插入图片描述

5. 模版编译

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

// 依赖 vue-template-compiler 转换模版
const compiler = require('vue-template-compiler')

// 插值
const template = `<p>{
     
     {message}</p>`
with (this) {
    
     return _c('p', [_v(_s(message))]) }
// with (this) { return createElement('p', [createTextNode(toString(message))]) }
// h 函数 执行返回的 是 vnode
// createElement 执行返回的也是 vnode

// 表达式
const template1 = `<p>{
     
     { flag? message: 'no message found' }}</p>`
with (this) {
    
     return _c('p', [_v(_s(flag ? message : 'no message found'))]) }
with (this) {
    
     return createElement('p', [createTextNode(toString(flag ? message : 'no message found'))]) }

// 属性 和 动态属性
const template2 = `
   <div id='div' class="container">
        <img :src = "imgUrl"/>
   </div> `
// staticClass 原先是 className ,再 vue 编译完后变成了staticClass
with (this) {
    
     return _c('div'), {
    
     staticClass: "container", attrs: {
    
     "id": "div1" } }, [_c('img')] }
with (this) {
    
     return createElement('div'), {
    
     staticClass: "container", Attributes: {
    
     "id": "div1" } }, [createElement('img')] }

// 条件编译
const template3 = `
    <div>
        <p v-if="flag ==='a'">A</p>
        <p v-else>B</p>
    </div>
`
with (this) {
    
     return _c('div', ['div', [(flag === 'a') ? _c('p', [_v("A")]) : _c('p', [_v("B")])]]) }
with (this) {
    
     return createElement('div', ['div', [(flag === 'a') ? createElement('p', [createTextNode("A")]) : createElement('p', [createTextNode("B")])]]) }

// 循环
const template4 = `
      <ul>
         <li v-for="item in list" :key="item.id">{
     
     {item.title}}</li>
      </ul> `
with (this) {
    
     return _c('ul', _l((list), function (item) {
    
     return _c('li', {
    
     key: item.id }, (_v(_s(item.title)))) })) }
with (this) {
    
     return createElement('ul', renderList((list), function (item) {
    
     return createElement('li', {
    
     key: item.id }, (createTextNode(toString(item.title)))) })) }

// 事件
const template5 = `<button @click = "clickHandler">submit</button>` // on代表所有的事件
with (this) {
    
     return _c('button', {
    
     on: {
    
     "click": clickHandler } }, [_v("submit")]) }
with (this) {
    
     return createElement('button', {
    
     on: {
    
     "click": clickHandler } }, [createTextNode("submit")]) }

// v-model
const template6 = `<input type="text" v-model="name">`
with (this) {
    
    
  return _c('input', {
    
    
    directives: [{
    
     name: "model", rawName: "v-model", value: (name), expression: "name" }],
    attrs: {
    
     "type": "text" }, domProps: {
    
     "value": (name) },
    on: {
    
     "input": function ($event) {
    
     if ($event.target.composing) return; name = $event.target.value } }
  })
}

// 上面都是 render 函数
// 执行 render 函数 返回 vnode

// 编译 
const res = compiler.compile(template)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6. 组件 渲染/更新 过程

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

7. 异步渲染,参考上面 $nextick

8. 路由vue-router原理

hash 路由 (#)

在这里插入图片描述

在这里插入图片描述

<body>
  <p>hash test</p>
  <button id="btn1">修改 hash</button>

  <script>
    // hash变化 :包括
    // a: JS 修改 url
    // b: 手动修改 url 的 hash , 不会触发刷新,不会触发前进后退
    // C: 浏览器前进、后退 , 不会触发刷新
    window.onhashchange = (event) => {
    
    
      console.log('old url', event.oldUrl);
      console.log('new url', event.newUrl);

      console.log('hash:', location.hash);
    }

    // 页面初次加载, 获取 hash
    document.addEventListener('DOMContentLoaded', () => {
    
    
      console.log('hash:', location.hash);
    })

    // JS 修改 url
    document.getElementById('btn1').addEventListener('click', () => {
    
    
      location.href = '#/user'
    })
  </script>
</body>
  • window.onhashchange 是 JavaScript 中的一个事件处理程序。
  1. 用于检测 URL 中的哈希值(即 # 号后面的内容)是否发生了变化。
  2. 当浏览器的历史记录中前进或后退时,此事件也会被触发。
  3. 该事件常用于构建单页面应用程序(SPA),以便在 URL 哈希值更改时更新页面内容而无需重新加载整个页面。
    在这里插入图片描述

history 路由

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<body>
  <p>history API test</p>
  <button id="btn1">修改 hash</button>

  <script>
    // 页面初次加载,获取 path
    document.addEventListener('DOMContentLoaded', () => {
    
    
      console.log('load', location.pathname); // index.html
    })
    // 【注意】 用 pushState 方式, 浏览不会刷新页面
    document.getElementById('btn1').addEventListener('click', () => {
    
    
      const state = {
    
     name: 'page1' }
      console.log('切换路由到', 'page1');
      history.pushState(state, '', 'page1') //重要!!
    })
    // 监听 浏览器前进、后退
    window.onpopstate = (event) => {
    
     // 重要!!
      console.log('onpopstate', event.state, location.pathname);

    }
  </script>
</body>

需要 server 端 配合,可参考链接
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

vue 真题演练

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 看红框内的data,函数return 一个对象,看似export default是一个对象,实际上.vue文件在被编译出来以后,这个vue实际上是一个class是一个类,vue组件是一个class,在每个地方使用这个组件时,相当于对class进行了一个实例化,在实例化时执行这个data,如果这个data不是一个函数的话,那每一个组件的实例都一样了就共享了,那就麻烦了。
  • 如果在这个组件实例化一个,在其他组件实例化一个,如果data不是函数的话,那在这个组件改了data中的name,那其他组件的name也会随之改变。
  • 所以说如果 data是一个函数,那在左边实例化一个,右边实例化一个,它都会执行这个函数,两个data都会在闭包当中,所以说两个杆(组件)就不会相互影响。其中一个data内容改变不会影响其他组件中的data。因此data必须是一个函数。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46426412/article/details/130817590
今日推荐