MOOC 1299 フロントエンド面接の質問 - vue2 モジュールには原則が含まれています

VUE2関連

私のブログはズームインしたワイドスクリーンで表示する必要があるかもしれませんが、画像のバランスが取れません。申し訳ありません。

1. 命令、補間

ここに画像の説明を挿入
ここに画像の説明を挿入

2. 計算して監視する

ここに画像の説明を挿入

計算された計算された属性、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>

ウォッチモニター、リファレンスタイプ、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. クラスとスタイル

ここに画像の説明を挿入
ここに画像の説明を挿入

4. 条件付きレンダリング

ここに画像の説明を挿入
ここに画像の説明を挿入

ここに画像の説明を挿入

5. ループリスト v-for

ここに画像の説明を挿入

ここに画像の説明を挿入
ここに画像の説明を挿入

6. イベントイベント

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

  • 1. イベント イベントはネイティブです。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 モデル

ここに画像の説明を挿入

ここに画像の説明を挿入

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. スロットの複数使用

  • 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.キープアライブキャッシュコンポーネント

ここに画像の説明を挿入

<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. ミックスインの使用

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

ここに画像の説明を挿入

17. VUEX

ここに画像の説明を挿入

ここに画像の説明を挿入

ここに画像の説明を挿入

18. ビュールーター

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

ここに画像の説明を挿入
ここに画像の説明を挿入

ここに画像の説明を挿入

上級者、準備をしてみましょう

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: { { {}}} ように、常にオブザーバー(値)に移動し、最後まで再帰されます。
    ここに画像の説明を挿入

4. 仮想 DOM (Virtual DOM) と diff アルゴリズム

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

ここに画像の説明を挿入

ここに画像の説明を挿入
github で詳しく説明されている snabbdom の記事を参照してください。
ここに画像の説明を挿入
ここに画像の説明を挿入

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

ハッシュルート(#)

ここに画像の説明を挿入

ここに画像の説明を挿入

<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. このイベントは、URL ハッシュが変更されたときにページ全体をリロードせずにページ コンテンツを更新するシングル ページ アプリケーション (SPA) を構築するためによく使用されます。
    ここに画像の説明を挿入

履歴ルーティング

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

<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>

サーバーの協力が必要です、リンクを参照してください
ここに画像の説明を挿入
ここに画像の説明を挿入

ここに画像の説明を挿入
ここに画像の説明を挿入

Vue の実際のテストのウォークスルー

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

  • 赤いボックス内のデータを確認すると、関数はオブジェクトを返し、看似デフォルトの是一个对象,实际上.vue ファイルをエクスポートします。在被编译出来以后,这个vue实际上是一个class是一个类,vue组件是一个class,在每个地方使用这个组件时,相当于对class进行了一个实例化,在实例化时执行这个data,如果这个data不是一个函数的话,那每一个组件的实例都一样了就共享了,那就麻烦了。
  • 如果在这个组件实例化一个,在其他组件实例化一个,data が関数ではない場合那在这个组件改了data 内の名前,那其他组件的name也会随之改变。
  • したがって、データが関数の場合、左側と右側に 1 つずつインスタンスを作成すると、この関数が実行され、両方のデータがクロージャ内にあるため、2 つの極 (コンポーネント) は互いに影響しません。データ内容の変更のいずれかが他のコンポーネントのデータに影響することはありません。したがって、データは関数でなければなりません。

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

ここに画像の説明を挿入

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

ここに画像の説明を挿入
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/weixin_46426412/article/details/130817590