<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        基于JavaScript實現一個簡單的Vue

        來源:懂視網 責編:小采 時間:2020-11-27 22:06:58
        文檔

        基于JavaScript實現一個簡單的Vue

        基于JavaScript實現一個簡單的Vue:Object.defineProperty() 實現之前我們得先看一下Object.defineProperty的實現,因為vue主要是通過數據劫持來實現的,通過get、set來完成數據的讀取和更新。 var obj = {name:'wclimb'} var age = 24 Object.definePro
        推薦度:
        導讀基于JavaScript實現一個簡單的Vue:Object.defineProperty() 實現之前我們得先看一下Object.defineProperty的實現,因為vue主要是通過數據劫持來實現的,通過get、set來完成數據的讀取和更新。 var obj = {name:'wclimb'} var age = 24 Object.definePro

        Object.defineProperty()

        實現之前我們得先看一下Object.defineProperty的實現,因為vue主要是通過數據劫持來實現的,通過get、set來完成數據的讀取和更新。

        var obj = {name:'wclimb'}
        var age = 24
        Object.defineProperty(obj,'age',{
        enumerable: true, // 可枚舉
        configurable: false, // 不能再define
        get () {
        return age
        },
        set (newVal) {
        console.log('我改變了',age +' -> '+newVal);
        age = newVal
        }
        })
        > obj.age
        > 24
        > obj.age = 25;
        > 我改變了 24 -> 25
        > 25

        從上面可以看到通過get獲取數據,通過set監聽到數據變化執行相應操作,還是不明白的話可以去看看Object.defineProperty文檔。

        流程圖

         

        html代碼結構

        <div id="wrap"> 
         <p v-html="test"></p>
         <input type="text" v-model="form">
         <input type="text" v-model="form">
         <button @click="changeValue">改變值</button>
         {{form}}
        </div>

        Vue結構

        class Vue{
        constructor(){}
        proxyData(){}
        observer(){}
        compile(){}
        compileText(){}
        }
        class Watcher{
        constructor(){}
        update(){}
        }

        Vue constructor 構造函數主要是數據的初始化

        proxyData 數據代理

        observer 劫持監聽所有數據

        compile 解析dom

        compileText 解析dom里處理純雙花括號的操作

        Watcher 更新視圖操作

        Vue constructor 初始化

        class Vue{
        constructor(options = {}){
        this.$el = document.querySelector(options.el);
        let data = this.data = options.data;
        // 代理data,使其能直接this.xxx的方式訪問data,正常的話需要this.data.xxx
        Object.keys(data).forEach((key)=> {
        this.proxyData(key);
        });
        this.methods = obj.methods // 事件方法
        this.watcherTask = {}; // 需要監聽的任務列表
        this.observer(data); // 初始化劫持監聽所有數據
        this.compile(this.$el); // 解析dom
        }
        }

        上面主要是初始化操作,針對傳過來的數據進行處理

        proxyData 代理data

        class Vue{
        constructor(options = {}){
        ......
        }
        proxyData(key){
        let that = this;
        Object.defineProperty(that, key, {
        configurable: false,
        enumerable: true,
        get () {
        return that.data[key];
        },
        set (newVal) {
        that.data[key] = newVal;
        }
        });
        }
        }

        上面主要是代理data到最上層,this.xxx的方式直接訪問data

        observer 劫持監聽

        class Vue{
        constructor(options = {}){
        ......
        }
        proxyData(key){
        ......
        }
        observer(data){
        let that = this
        Object.keys(data).forEach(key=>{
        let value = data[key]
        this.watcherTask[key] = []
        Object.defineProperty(data,key,{
        configurable: false,
        enumerable: true,
        get(){
        return value
        },
        set(newValue){
        if(newValue !== value){
        value = newValue
        that.watcherTask[key].forEach(task => {
        task.update()
        })
        }
        }
        })
        })
        }
        }

        同樣是使用Object.defineProperty來監聽數據,初始化需要訂閱的數據。

        把需要訂閱的數據到push到watcherTask里,等到時候需要更新的時候就可以批量更新數據了。??下面就是;

        遍歷訂閱池,批量更新視圖。

        set(newValue){
        if(newValue !== value){
        value = newValue
        // 批量更新視圖
        that.watcherTask[key].forEach(task => {
        task.update()
        })
        }
        }

        compile 解析dom

        class Vue{
        constructor(options = {}){
        ......
        }
        proxyData(key){
        ......
        }
        observer(data){
        ......
        }
        compile(el){
        var nodes = el.childNodes;
        for (let i = 0; i < nodes.length; i++) {
        const node = nodes[i];
        if(node.nodeType === 3){
        var text = node.textContent.trim();
        if (!text) continue;
        this.compileText(node,'textContent')
        }else if(node.nodeType === 1){
        if(node.childNodes.length > 0){
        this.compile(node)
        }
        if(node.hasAttribute('v-model') && (node.tagName === 'INPUT' || node.tagName === 'TEXTAREA')){
        node.addEventListener('input',(()=>{
        let attrVal = node.getAttribute('v-model')
        this.watcherTask[attrVal].push(new Watcher(node,this,attrVal,'value'))
        node.removeAttribute('v-model')
        return () => {
        this.data[attrVal] = node.value
        }
        })())
        }
        if(node.hasAttribute('v-html')){
        let attrVal = node.getAttribute('v-html');
        this.watcherTask[attrVal].push(new Watcher(node,this,attrVal,'innerHTML'))
        node.removeAttribute('v-html')
        }
        this.compileText(node,'innerHTML')
        if(node.hasAttribute('@click')){
        let attrVal = node.getAttribute('@click')
        node.removeAttribute('@click')
        node.addEventListener('click',e => {
        this.methods[attrVal] && this.methods[attrVal].bind(this)()
        })
        }
        }
        }
        },
        compileText(node,type){
        let reg = /{{(.*)}}/g, txt = node.textContent;
        if(reg.test(txt)){
        node.textContent = txt.replace(reg,(matched,value)=>{
        let tpl = this.watcherTask[value] || []
        tpl.push(new Watcher(node,this,value,type))
        return value.split('.').reduce((val, key) => {
        return this.data[key];
        }, this.$el);
        })
        }
        }
        }

        這里代碼比較多,我們拆分看你就會覺得很簡單了

        首先我們先遍歷el元素下面的所有子節點,node.nodeType === 3 的意思是當前元素是文本節點,node.nodeType === 1 的意思是當前元素是元素節點。因為可能有的是純文本的形式,如純雙花括號就是純文本的文本節點,然后通過判斷元素節點是否還存在子節點,如果有的話就遞歸調用compile方法。下面重頭戲來了,我們拆開看:

        if(node.hasAttribute('v-html')){
        let attrVal = node.getAttribute('v-html');
        this.watcherTask[attrVal].push(new Watcher(node,this,attrVal,'innerHTML'))
        node.removeAttribute('v-html')
        }

        上面這個首先判斷node節點上是否有v-html這種指令,如果存在的話,我們就發布訂閱,怎么發布訂閱呢?只需要把當前需要訂閱的數據push到watcherTask里面,然后到時候在設置值的時候就可以批量更新了,實現雙向數據綁定,也就是下面的操作

        that.watcherTask[key].forEach(task => {
        task.update()
        })

        然后push的值是一個Watcher的實例,首先他new的時候會先執行一次,執行的操作就是去把純雙花括號 -> 1,也就是說把我們寫好的模板數據更新到模板視圖上。

        最后把當前元素屬性剔除出去,我們用Vue的時候也是看不到這種指令的,不剔除也不影響

        至于Watcher是什么,看下面就知道了

        Watcher

        that.watcherTask[key].forEach(task => {
        task.update()
        })

        之前發布訂閱之后走了這里面的操作,意思就是把當前元素如:node.innerHTML = '這是data里面的值'、node.value = '這個是表單的數據'

        那么我們為什么不直接去更新呢,還需要update做什么,不是多此一舉嗎?

        其實update記得嗎?我們在訂閱池里面需要批量更新,就是通過調用Watcher原型上的update方法。

        總結

        以上所述是小編給大家介紹的基于JavaScript實現一個簡單的Vue,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        基于JavaScript實現一個簡單的Vue

        基于JavaScript實現一個簡單的Vue:Object.defineProperty() 實現之前我們得先看一下Object.defineProperty的實現,因為vue主要是通過數據劫持來實現的,通過get、set來完成數據的讀取和更新。 var obj = {name:'wclimb'} var age = 24 Object.definePro
        推薦度:
        標簽: 一個 有一個 簡易
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 性生大片视频免费观看一级| 一级毛片视频免费观看| 亚洲AV噜噜一区二区三区| 亚欧免费视频一区二区三区 | 国产一区二区视频免费| 国产aⅴ无码专区亚洲av麻豆| 国产成人亚洲午夜电影| www.亚洲色图| 一级毛片在线完整免费观看| www国产亚洲精品久久久日本| 四虎国产精品永免费| 亚洲自偷自偷偷色无码中文| 久久国产精品国产自线拍免费| 成人免费无码视频在线网站| 亚洲中文字幕无码亚洲成A人片| 最近更新免费中文字幕大全| 成人免费网站在线观看| 亚洲AV网一区二区三区| 99久久国产热无码精品免费 | 亚洲无线一二三四区手机| 国产精品hd免费观看| 国产美女做a免费视频软件| 91亚洲国产在人线播放午夜| 青娱乐免费在线视频| 亚洲va久久久噜噜噜久久男同| 午夜亚洲国产精品福利| 亚洲一区二区女搞男| 最近2019中文字幕免费大全5| 久久精品亚洲AV久久久无码| 免费国产a国产片高清网站| 91精品成人免费国产| 亚洲人成电影网站| 97国产在线公开免费观看| 亚洲综合激情五月丁香六月| 亚洲欧洲精品成人久久曰影片| 国产成人无码区免费网站| 国产亚洲AV夜间福利香蕉149| 免费国产黄网站在线观看| 4444亚洲国产成人精品| 在线免费观看中文字幕| 国产亚洲玖玖玖在线观看|