0
点赞
收藏
分享

微信扫一扫

Linux/centos上如何配置管理samba服务器?

得一道人 2023-08-08 阅读 60

初始化数据

vue中最核心的我们都知道那就是响应式数据,数据的变化视图自动更新。那么我们来new一个我们自己的vue

index.html文件下加入如下代码,这也是vue最常见的基本结构。data已经有了下面我们来获取data的数据

 <script src="./vue.js"></script>
 <script>
    const vm=new MVue({
         data(){
             return{
                 name:"zhangsan",
                 age:"16"
             }
         }
    })
 </script>

首先我们在src/main.js文件下加入如下代码

// 创建MVue构造函数
function MVue(options) {      // options就是我们接受到用户的选项,选项式api
    
}

// 将构造函数导出
export default MVue

为了更能的扩展功能和方便维护,我们需要一个专门做初始化的方法。所以我们在src下创建init.js文件加入如下代码

export function init(MVue){
    // 给MVue原型对象上挂载_init()方法
    MVue.prototype._init = function(options){

    }
}

main.js文件下如果这个方法,并且调用

import { init } from "./init"

// 创建MVue构造函数
function MVue(options) {      // options就是我们接受到用户的选项,选项式api
    // 当vue被new的时候调用_init()方法
    this._init(options)
}

init(MVue)

// 将构造函数导出
export default MVue

下面我们就可以写我们的初始化方法了,init.js文件下加入如下代码。可能你会好奇这个init_state()方法是那里的。由于用户选项有很多比如data,watch,computed…所以我们最好创建一个文件统一管理。在src文件下创建state.js文件

import { init_state } from "./state"

export function init(MVue){
    // 给MVue原型对象上挂载_init()方法
    MVue.prototype._init = function(options){

        // 在用户选项挂载到实例上
        const vm=this
        vm.$options=options

        // 初始化状态
        init_state(vm)
    }
}

state.js文件下加入如下代码

export function init_state(vm){
    // 获取实例上挂载的选项
    const opts=vm.$options;

    // 选项上如果存在data初始化data
    if(opts.data){
        init_data(vm);
    }
}
function init_data(vm){
    let data=vm.$options.data;

    // 判断data是对象还是函数并且重新赋值
    data=typeof data==='function'?data.call(vm):data;

    console.log(data);
}

到这里,输入打包命令打开index.html如果在游览器下看到如下图所示,我们就成功获取到了data里面的数据

pnpm run build

在这里插入图片描述


实现对象的响应式原理

下面我们首先来实现只有一层对象的数据劫持。state.js文件下加入如下代码

import { observe } from "./observe/index";

export function init_state(vm){
    // 获取实例上挂载的选项
    const opts=vm.$options;

    // 选项上如果存在data初始化data
    if(opts.data){
        init_data(vm);
    }
}
function init_data(vm){
    let data=vm.$options.data;

    // 判断data是对象还是函数并且重新赋值
    data=typeof data==='function'?data.call(vm):data;

    // 将data劫持重新定义data
    observe(data)
}

src文件下创建observe/index.js文件并且加入如下代码

class Observer {
    constructor(data) {
        /* 
            这里注意,Object.defineProperty只能劫持已经存在的属性,新增或删除的无法劫持
            这也是为什么vue2中新增了,$set和$delete方法这类方法的原因
        */
        this.walk(data)
    }
    walk(data) {
        // 循环对象keys依次劫持,重新定义属性
        Object.keys(data).forEach(key => {
            define_reactive(data, key, data[key])
        })
        
        // 这里重新定义data后我们打印看下data是否都加入了get和set方法
        console.log(data);
    }

}

// 这里会存在一个闭包,get和set方法存放了函数外部的变量value
export function define_reactive(data, key, value) {
    Object.defineProperty(data, key, {
        get() {
            return value
        },
        set(newValue){
            if(value!=newValue){
                value=newValue
            }
        }
    })
}


export function observe(data) {

    // 对对象劫持
    if (typeof data !== 'object' || data === null) {
        return;
    }

    // 如果一个对象被劫持过就不需要再次劫持,我们可以通过一个观察类判断是否被劫持过
    return new Observer(data)
}

如果你的游览器打印了如下图所示,那么恭喜你只有一层对象的data你重新定义完成了

在这里插入图片描述
说起data,vue2中一直有个属性_data属性。这上面挂载了我们所有在data中定义的属性。下面我们来实现它

state.js文件下修改如下代码。没错就是这么简单要加入vm._data=data这行代码就完成了。由于这是引用值。所有对data的修改也会影响到_data

function init_data(vm){
    let data=vm.$options.data;

    // 判断data是对象还是函数并且重新赋值
    data=typeof data==='function'?data.call(vm):data;

    // 实例上挂载_data
    vm._data=data

    // 将data劫持重新定义data
    observe(data)
}

下面我们在index.html下打印vm看看是否有我们的_data属性

在这里插入图片描述

到这里,其实我们的_data属性并不完美,你通过vm获取属性的时候发现每次都要加上_data,
vm._data.name。但是vue2中并不是这样的而是直接vm.name就可以获取并且修改。下面我们来解决这个问题

state.js文件下加入如下代码。我们将将vm._data代理给vm就可以解决这个问题

function proxy(vm,source,key){
    Object.defineProperty(vm,key,{
        get(){
            return vm[source][key]
        },
        set(newValue){
            if(vm[source][key]!=newValue){
                vm[source][key]=newValue;
            }
        }
    })
}

function init_data(vm){
    let data=vm.$options.data;

    // 判断data是对象还是函数并且重新赋值
    data=typeof data==='function'?data.call(vm):data;

    // 实例上挂载_data
    vm._data=data

    // 将data劫持重新定义data
    observe(data)

    // 将vm._data代理给vm
    for(let key in data){
        proxy(vm,'_data',key)
    }
}

下面我们在看我们的vm实例会发现多了name和age属性。并且可以通过vm访问到和修改

在这里插入图片描述
到这里不知你们还记得我们最早说过的,这只是一个只有一层对象的数据劫持。如果多层就代理不到了
我们修改index.html代码如下

       const vm=new MVue({
            data(){
                return{
                    name:"zhangsan",
                    age:"16",
                    address:{
                        city:"地球村    "
                    }
                }
            }
       })
       console.log(vm);

在游览器上。我们会看到address并且没有get和set方法。下面我们来解决这个问题

在这里插入图片描述

observe/index.js文件下修改如下代码

// 这里会存在一个闭包,get和set方法存放了函数外部的变量value
export function define_reactive(data, key, value) {
    observe(value)		// 递归调用我们的observe方法

    Object.defineProperty(data, key, {
        get() {
            return value
        },
        set(newValue){
            if(value!=newValue){
                value=newValue
            }
        }
    })
}

再次看我们的address就会发现get和set方法已经出现了。这说明我们的多级对象代理已经完成了

在这里插入图片描述

用户可能会存在这样的赋值,现在我们是没办法办法代理到的

const vm = new MVue({
    data() {
        return {
            name: "zhangsan",
            age: "16",
           
        }
    }
})
vm.address = {
    city: "地球村"
}

所以我们在observe/index.js文件下define_reactive方法中的set修改如下。如果直接通过vm赋值对象,给这些属性同样代理

set(newValue){
    if(value!=newValue){
        observe(newValue)
        value=newValue
    }
}
举报

相关推荐

0 条评论