Web フロントエンド インタビュー高頻度テスト サイト - Vue 原則 (diff アルゴリズム、テンプレートのコンパイル、コンポーネントのレンダリングと更新、JS 実装のルーティング)

シリーズ記事ディレクトリ

コンテンツ 参考リンク
Vueの基本的な使い方 Vue の基本的な使い方 (Vue の最も基本的な知識ポイントをマスターするための 1 つの記事)
Vue通信と高度な機能 Vue コンポーネントと高度な機能間の通信 (さまざまなコンポーネント、カスタム v-model、nextTick、スロット間の通信)
Vue の高度な機能 Vue の高度な機能 (動的コンポーネント、非同期ロード、キープアライブ、ミックスイン、Vuex、Vue-Router)
ビューの原則 1 Vue の原理 (MVVM モデルの理解、データ変更の詳細/監視、配列変更の監視、仮想 DOM の詳細な理解)
ビューの原則 2 Vue の原則 (diff アルゴリズム、テンプレートのコンパイル、コンポーネントのレンダリングと更新、JS 実装のルーティング)
Vue インタビューの質問 Web フロントエンド面接高頻度テストサイト - Vue 面接の質問


1. 仮想 DOM の概要 - diff アルゴリズム

差分アルゴリズムの参照リンク

  • diff アルゴリズムは、vdom のコアであり、最も重要な部分です。
  • diff アルゴリズムは、vue react (キーなど) の日常的な使用に反映できます。

差分アルゴリズムの概要:

  • diff は対照であり、Linux の diff コマンド、git diff コマンドなどの広い概念です。
  • 2 つの js オブジェクトでも diff を実行できます
  • vdom diff のように、2 つのツリーが diff を実行します。

ソース: https://coding.imooc.com/lesson/419.html#mid=33875

ここに画像の説明を挿入
ツリー差分の時間計算量は O(n^3) です

  • まず、tree1 をトラバースします。
  • 次に、tree2 をトラバースします。
  • 第三に、並べ替え
  • 100 ノード、100 万回計算するには、アルゴリズムは使用できません

時間の複雑さを O(n) に最適化する

  • レベル間ではなく、同じレベルのみを比較する
  • タグが同じでない場合は、直接削除して再構築し、詳細な比較を行わない
  • タグとキーが同じ場合、それらは同じノードと見なされ、それ以上の比較は必要ありません。

ソース: https://coding.imooc.com/lesson/419.html#mid=33875
ここに画像の説明を挿入

2. テンプレートのコンパイル

1. テンプレートのコンパイル - 構文付き

  • テンプレートは、vue 開発の最も一般的に使用される部分、つまり、使用に関連する原則です。
  • html ではなく、ディレクティブ、補間、JS 式が含まれています。

テンプレートのコンパイル:

  • 前提条件: JS と構文
  • vue テンプレート コンパイラは、テンプレートをレンダリング関数にコンパイルします
  • render 関数を実行して vnode を生成する

構文:

  • 検索する obj 属性として、{} の自由変数の検索ルールを変更します
  • 一致する obj プロパティが見つからない場合、エラーが報告されます
  • with は注意して使用する必要があります。スコープ規則に違反し、読みにくくなります。

例: with がないと、オブジェクトの undefined プロパティは undefined です

const obj = {
    
    a: 100, b: 200}

console.log(obj.a) // 100
console.log(obj.b) // 200
console.log(obj.c) // undefined

with を使用すると、オブジェクトで定義されていないプロパティはエラーを報告します

const obj = {
    
    a: 100, b: 200}

// 使用 with,能改变 {} 内自由变量的查找方式
// 将 {} 内自由变量,当作 obj 的属性来查找
with (obj) {
    
    
    console.log(a) // 100
    console.log(b) // 200
    console.log(c) // Uncaught ReferenceError: c is not defined
}

2. コンパイルされた vue テンプレートは何ですか?

テンプレートのコンパイル:

  • テンプレートは html ではなく、命令、補間、JS 表現があり、判定とループを実現できます。
  • HTMLはタグ言語、判定とループを実現できるのはJSだけ
  • したがって、テンプレートをある種の JS コードに変換する必要があります。つまり、テンプレートのコンパイルです。

例:

(1) インストールvue-テンプレート-コンパイラ

npm i vue-template-compiler --save

(2) index.js ファイルを作成する

const compiler = require('vue-template-compiler')

......

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

(3) デモ (以下のデモは index.js ファイルにあります...)

補間:

  • 印刷結果は次のとおりです。p タグを作成します。子要素は文字列である TextVNode です。
  • _c: createElement、要素の作成
  • _v: createTextVNode、テキストノードを作成
  • _s: toString、文字列型に変換
  • this: const vm = new Vue({…})、これは vm インスタンスです
// 插值
const template = `<p>{
     
     {message}}</p>`
// with(this){return _c('p',['p',[_v(_s(message))]])}
// h -> vnode
// createElement -> vnode

表現:

  • テンプレート内の式は JS コードとして実行されます
// 表达式
const template = `<p>{
     
     {flag ? message : 'no message found'}}</p>`
//with(this){return _c('p',[_v(_s(flag ? message : 'no message found'))])}

プロパティと動的プロパティ:

  • コンテナ、div1 は静的文字列であるため、コンパイル後に引用符で囲む必要があります
  • imgUrl は動的な属性であり、変数であるため、コンパイル後に引用符で囲まれていません。
// 属性和动态属性
const template = `
     <div id="div1" class="container">
         <img :src="imgUrl"/>
     </div>
 `
// with(this){return _c('div',
//      {staticClass:"container",attrs:{"id":"div1"}},
//      [_c('img',{attrs:{"src":imgUrl}})]
// )}

調子:

  • 三項式に変換する
// 条件
const template = `
    <div>
        <p v-if="flag === 'a'">A</p>
        <p v-else>B</p>
    </div>
`
// with(this){return _c('div',[(flag === 'a')?_c('p',[_v("A")]):_c('p',[_v("B")])])}

サイクル:

  • _l: renderList、レンダー リスト
  • 2 番目の戻り値。返される最初のパラメーターはタグ、2 番目のパラメーターは属性、3 番目のパラメーターは子要素です。
// 循环
const template = `
    <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))])}),0)}

イベント:

  • on にイベントがあり、関数の名前は引用符なしの変数です。
// 事件
const template = `
    <button @click="clickHandler">submit</button>
`
// with(this){return _c('button',{on:{"click":clickHandler}},[_v("submit")])}

v-モデル:

// v-model
const template = `<input type="text" v-model="name">`
// 主要看 input 事件
// 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}}})}

テンプレートをコンパイルします。

  • テンプレートはレンダリング関数にコンパイルされ、レンダリング関数が実行されて vnode が返されます
  • vnode に基づいて patch と diff を実行する
  • webpack vue-loader を使用して、テンプレートは開発環境でコンパイルされます

3. vue コンポーネントでテンプレートの代わりに render を使用する

  • いくつかの複雑なケースでは、テンプレートを使用できず、レンダリングを考慮することができます
  • React は常に render を使用してきました (テンプレートなし)
Vue.component('heading', {
    
    
    // template: `xxx`,
    render: function (createElement) {
    
    
        return createElement(
            'h' + this.level,
            [
                createElement('a', {
    
    
                    attrs: {
    
    
                        name: 'headerId',
                        href: '#' + 'headerId'
                    }
                }, 'this is a tag')
            ]
        )
    }
})

要約:

  • 構文付き
  • 関数をレンダリングするためのテンプレート、vnode へ、レンダリングおよび更新するためのテンプレート
  • Vue コンポーネントはテンプレートの代わりに render を使用できます

4. コンポーネントのレンダリング/更新プロセスの要約

  • コンポーネントがページにレンダリングされ、データを変更すると更新がトリガーされます (データ駆動型ビュー)
  • その理由と、押さえておきたいポイントとは?
  • プロセスの理解の包括性を調べる

3 つの知識ポイント:

  • レスポンシブ: データ プロパティのゲッター セッターをリッスンします。
  • テンプレートのコンパイル: テンプレートからレンダリング関数、次に vnode へ
  • vdom:patch(elem,vnode) 和 patch(vnode, newVnode)

3 つのプロセス:

  • 初期レンダリング プロセス
  • 更新プロセス
  • 非同期レンダリング

3. vue コンポーネントがどのようにレンダリングおよび更新されるか

1. 最初のレンダリング プロセス

  • テンプレートをレンダリング関数に解析します (または開発環境で完成した vue-loader )。
  • トリガー応答、データ プロパティ ゲッター セッターをリッスン
  • render 関数を実行して vnode, patch(elem, vnode) を生成する

2. render 関数を実行すると、getter がトリガーされます

  • テンプレートで使用されているものは get をトリガーします
  • テンプレートで使用されていないものは、ビューとは関係がないため、get をトリガーしません。
<p>{
    
    {
    
    message}}</p>

export default {
    
    
  data() {
    
    
    return {
    
    
      message: '杂货铺', // 会触发 get
      city: '北京' // 不会触发 get,因为模板没用到,即和视图没关系
    }
  }
}

3. 更新プロセス

  • データを変更してセッターをトリガーします(以前はゲッターで監視されていました)
  • render 関数を再実行して newVnode を生成する
  • patch(vnode, newVnode)

ここに画像の説明を挿入

4. vue コンポーネントで非同期にレンダリングする方法

  • $nextTick は非同期です
  • データの変更を要約し、一度にビューを更新します
  • DOM 操作の数を減らし、パフォーマンスを向上させる

4.JSでハッシュルーティングを実装する方法

  • vue-router のルーティング モード: ハッシュ モード、H5 履歴

1. ウェブページの URL の構成要素

http://127.0.0.1:8881/01-hash.html?a=100&b=20#/aaa/bbb

location.protocol // 'http:' 【协议】
location.hostname // '127.0.0.1' 【IP地址/域名】
location.host // '127.0.0.1:8881' 【IP地址带端口】
location.port // '8881' 【端口】
location.pathname // '/01-hash.html' 【文件路径名】
location.search // '?a=100&b=20' 【参数】
location.hash // '#/aaa/bbb' 【#及后面的部分】

2. ハッシュの特徴

  • ハッシュの変更により、Web ページのジャンプ、つまりブラウザの前後のジャンプがトリガーされます
  • ハッシュの変更は、SPA の必要な機能であるページを更新しません。
  • ハッシュがサーバー側に送信されることはありません (フロントエンドはそれ自体で対処します)

3. ハッシュ変更の例

  • onhashchange: ハッシュ値の変更を監視するために使用されます
  • href 属性は、現在表示されているドキュメントの完全な URL を設定または返す読み取りおよび書き込み可能な文字列です。
<p>hash test</p>
<button id="btn1">修改 hash</button>

// 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'
})

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

5. JS で H5 履歴ルーティングを実装する方法

  • URL指定でルーティングしますが、ジャンプ時にページを更新しません
  • history.pushState
  • window.onpopstate

1.例

  • history.pushState(状態、タイトル、URL)
  • state: 指定された URL に関連する状態オブジェクト popstate イベントがトリガーされると、オブジェクトはコールバック関数に渡されます。このオブジェクトが必要ない場合は、ここに null を入力できます
  • title: 新しいページのタイトルですが、現在すべてのブラウザがこの値を無視するため、ここに null を入力できます
  • url: 新しい URL。現在のページと同じドメインにある必要があります。ブラウザのアドレス バーにこの URL が表示されます
<p>history API test</p>
<button id="btn1">修改 url</button>

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

// 打开一个新的路由
// 【注意】用 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)
}

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

2. 選び方

  • B (企業または特定のユーザー グループ向け) システムでは、使いやすく、URL の仕様に左右されないハッシュを使用することをお勧めします。
  • C (個人消費者向け) システムには、H5 履歴の選択を検討できますが、サーバー サポートが必要です。
  • シンプルなものを選択できる、複雑なものを使用しない、コストとメリットを考慮できる

不积跬步无以至千里,不积小流无以成江海

クリックしてフォローし、迷子にならないように、更新を続けてください...

おすすめ

転載: blog.csdn.net/qq_45902692/article/details/126565768