[js&vue] Combinado con gtp para imitar un marco vue simple para aprender JavaScript en profundidad

Utilice gtp para aprender el principio del ciclo de vida de Vue

ciclo de vida.js

function Vue(options) {
    // 将选项保存到实例的 $options 属性中
    this.$options = options;

    // 若存在 beforeCreate 钩子函数,则调用之
    if (typeof options.beforeCreate === 'function') {
        options.beforeCreate.call(this);
    }

    // 判断并保存 data 数据对象
    this._data = typeof options.data === 'function' ? options.data() : options.data;

    // 将 data 对象中的属性代理到 Vue 实例上
    this._proxyData();

    // 若存在 created 钩子函数,则调用之
    if (typeof options.created === 'function') {
        options.created.call(this);
    }

    // 执行挂载操作
    this.$mount(options.el);
}

Vue.prototype.$mount = function(el) {
    // 将目标元素保存到实例的 $el 属性中
    this.$el = document.querySelector(el);

    // 若存在 beforeMount 钩子函数,则调用之
    if (typeof this.$options.beforeMount === 'function') {
        this.$options.beforeMount.call(this);
    }

    // 调用 render 方法渲染模板
    this.render();

    // 若存在 mounted 钩子函数,则调用之
    if (typeof this.$options.mounted === 'function') {
        this.$options.mounted.call(this);
    }
};

Vue.prototype._proxyData = function() {
    var self = this;
    // 遍历 data 对象的属性,并将其代理到 Vue 实例上
    Object.keys(this._data).forEach(function(key) {
        Object.defineProperty(self, key, {
            get: function() {
                return self._data[key];
            },
            set: function(newValue) {
                self._data[key] = newValue;
                // 若存在 beforeUpdate 钩子函数,则调用之
                if (typeof self.$options.beforeUpdate === 'function') {
                    self.$options.beforeUpdate.call(self);
                }
                // 重新渲染模板
                self.render();
                // 若存在 updated 钩子函数,则调用之
                if (typeof self.$options.updated === 'function') {
                    self.$options.updated.call(self);
                }
            }
        });
    });
};

Vue.prototype.render = function() {
    // 调用 render 函数生成模板字符串,并更新目标元素的内容
    if (typeof this.$options.render === 'function') {
        this.$el.innerHTML = this.$options.render.call(this);
    }
};

// 使用示例
var app = new Vue({
    el: '#app',  // Vue 实例挂载的目标元素
    data: {      // 数据对象
        message: 'Hello, Vue!'    // 文本数据
    },
    beforeCreate: function() {
        console.log('beforeCreate hook');
    },
    created: function() {
        console.log('created hook');
    },
    beforeMount: function() {
        console.log('beforeMount hook');
    },
    mounted: function() {
        console.log('mounted hook');
    },
    beforeUpdate: function() {
        console.log('beforeUpdate hook');
    },
    updated: function() {
        console.log('updated hook');
    },
    render: function() {
        return '<p>' + this.message + '</p>';
    }
});

Nota:
¿Cuál es la diferencia entre this.$options.beforeMount.call(this); y this.$options.beforeMount();:

  • call(this) La función es thispasar el objeto actual () como parámetro al  beforeMount método, de modo que  beforeMount se pueda acceder  this al contexto del objeto actual dentro del método.
  • El método fue llamado directamente  beforeMount sin especificar el contexto. 

índice.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="./lifecycle.js"></script>
  </body>
</html>

Ver los resultados de la representación en el navegador y ver la salida del registro en la consola

Además, podemos  app.message = 'ChatGPT' verificar el enlace de datos y el mecanismo de actualización de la página en la entrada de control.

Representación:

Utilice gtp para aprender los principios de la sintaxis y las instrucciones de las plantillas de Vue

índice.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app"></div>
    <script>
        // 定义 Vue 类
        function Vue(options) {
            // 保存选项为实例的属性
            this.$options = options;
            // 判断传入的 data 是函数还是对象,并保存到 _data 属性上
            this._data = typeof options.data === 'function' ? options.data() : options.data;
            // 调用编译模板的方法
            this._compileTemplate();
        }

        // 原型方法:编译模板
        Vue.prototype._compileTemplate = function () {
            var self = this;
            // 获取模板字符串
            var template = this.$options.template || '';

            // 定义一个函数用于对表达式进行求值
            var evalExpression = function (expression) {
                // 使用 with 关键字将 data 对象的属性添加到作用域中,并求解表达式
                with (self._data) return eval(expression);
            }

            // 将模板中的双括号表达式替换成 data 对应属性的值
            var compiledTemplate = template.replace(/\{\{(.*?)\}\}/g, function (match, expression) {
                var value = evalExpression(expression);
                return value !== undefined ? value : '';
            });

            // 获取目标元素,并将编译后的模板插入其中
            var element = document.querySelector(this.$options.el);
            element.innerHTML = compiledTemplate.trim();

            // 处理带有 v-model 属性的元素,实现数据的双向绑定
            element.querySelectorAll('[v-model]').forEach(function (element) {
                var value = element.getAttribute('v-model');
                element.value = self._data[value];
                element.addEventListener('input', function (event) {
                    self._data[value] = event.target.value;
                });
            });

            // 处理带有 v-text 属性的元素,实现数据的单向绑定
            element.querySelectorAll('[v-text]').forEach(function (element) {
                var value = element.getAttribute('v-text');
                element.textContent = self._data[value];
                // 使用 defineProperty 方法定义 data 对象对应属性的 getter 和 setter
                Object.defineProperty(self._data, value, {
                    get: function () {
                        return this[value]
                    },
                    set: function (newValue) {
                        element.textContent = newValue;
                    }
                });
            });
        };

        // 使用示例
        var app = new Vue({
            el: '#app',  // Vue 实例挂载的目标元素
            data: {      // 数据对象
                message: 'Hello, Vue!',    // 文本数据
                inputValue: 'ChatGPT'      // 输入数据
            },
            template:     // 模板字符串
                `
          <div>
            <p>{
   
   { message }}</p>
            <input v-model="inputValue" type="text">
            <p v-text="inputValue"></p>
         </div>
         `
        });
    </script>
</body>

</html>

Representación:

anotación:

  • El papel de la declaración with en js

withEl propósito de la declaración es simplificar el código para que se pueda acceder directamente a las propiedades y métodos del objeto dentro del alcance sin reutilizar el prefijo del nombre del objeto.

var person = {
  name: 'Alice',
  age: 25,
  greet: function() {
    console.log('Hello, ' + this.name + '!');
  }
};

with (person) {
  console.log(name);  // 直接访问属性,输出: Alice
  console.log(age);   // 直接访问属性,输出: 25
  greet();            // 直接调用方法,输出: Hello, Alice!
}
  • plantilla.replace(/\{\{(.*?)\}\}/g, función (coincidencia, expresión) {... })

Es un método de reemplazo de expresiones regulares que se utiliza para procesar expresiones de doble llave en plantillas. { {expression}},La función de devolución de llamada recibe dos parámetros:

  match: toda la cadena coincide, es decir  { {expression}}.

  expression: La expresión coincidente, es decir  expression.

 Utilice gtp para aprender los principios del monitoreo de datos de Vue y las propiedades calculadas

índice.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app"></div>
    <script>
        // 定义 Vue 类
        function Vue(options) {
            // 将 data、computed 和 watch 选项保存到实例中
            this._data = options.data;
            this._computed = options.computed;
            this._watch = options.watch;

            // 数据代理
            this._proxyData();
            // 创建计算属性
            this._createComputed();
            // 创建监听器
            this._createWatchers();
        }

        // 数据代理,将 data 中的属性代理到 Vue 实例上,实现直接访问和修改数据
        Vue.prototype._proxyData = function () {
            var self = this;
            Object.keys(this._data).forEach(function (key) {
                Object.defineProperty(self, key, {
                    get: function () {
                        return self._data[key];
                    },
                    set: function (newValue) {
                        self._data[key] = newValue;
                    }
                });
            });
        };

        // 创建计算属性
        Vue.prototype._createComputed = function () {
            var self = this;
            var computed = this._computed || {};

            Object.keys(computed).forEach(function (key) {
                Object.defineProperty(self, key, {
                    get: function () {
                        return computed[key].call(self);
                    }
                });
            });
        };

        // 创建监听器
        Vue.prototype._createWatchers = function () {
            var self = this;
            var watch = this._watch || {};

            Object.keys(watch).forEach(function (key) {
                var callback = watch[key];
                var value = self._data[key];

                Object.defineProperty(self._data, key, {
                    get: function () {
                        return value;
                    },
                    set: function (newValue) {
                        value = newValue;
                        callback.call(self, newValue);
                    }
                });
            });
        };

        // 使用示例
        // 创建一个 Vue 实例
        var app = new Vue({
            // 初始化数据
            data: {
                message: 'Hello, Vue!',
                firstName: 'John',
                lastName: 'Doe'
            },
            // 定义计算属性
            computed: {
                fullName: function () {
                    return this.firstName + ' ' + this.lastName;
                }
            },
            // 定义监听器
            watch: {
                message: function (newValue) {
                    console.log('Message changed:', newValue);
                }
            }
        });

        console.log(app.message);       // 输出: Hello, Vue!
        app.message = 'Hello, Vue.js!'; // 输出: Message changed: Hello, Vue.js!
        console.log(app.message);       // 输出: Hello, Vue.js!
        console.log(app.fullName);      // 输出: John Doe
        app.message = 'New message';    // 输出: Message changed: New message
    </script>
</body>

</html>

Representación:

Utilice gtp para aprender los principios y métodos del manejo de eventos de Vue

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app"></div>
    <script>
        // 定义事件总线类
        function EventBus() {
            this._events = {};
        }

        // 事件总线订阅方法,用于注册事件回调函数
        EventBus.prototype.on = function (eventName, callback) {
            if (!this._events[eventName]) {
                this._events[eventName] = [];
            }
            this._events[eventName].push(callback);
        };

        // 事件总线触发方法,用于触发事件并调用相应的回调函数
        EventBus.prototype.emit = function (eventName, payload) {
            if (this._events[eventName]) {
                this._events[eventName].forEach(function (callback) {
                    callback(payload);
                });
            }
        };

        // 定义 Vue 类
        function Vue(options) {
            // 初始化数据
            this._data = typeof options.data === 'function' ? options.data() : options.data;
            // 记录方法
            this._methods = options.methods;
            // 创建事件总线实例
            this._eventBus = new EventBus();

            // 对数据进行代理,使得可以直接通过 this.xxx 访问和修改数据
            this._proxyData();
            // 对方法进行代理,使得可以通过 this.xxx 调用方法
            this._proxyMethods();
        }

        // 数据代理,将 data 中的属性添加到 Vue 实例中,实现直接访问和修改数据
        Vue.prototype._proxyData = function () {
            var self = this;
            Object.keys(this._data).forEach(function (key) {
                Object.defineProperty(self, key, {
                    get: function () {
                        return self._data[key];
                    },
                    set: function (newValue) {
                        self._data[key] = newValue;
                    }
                });
            });
        };

        // 方法代理,将 methods 中的方法添加到 Vue 实例中,实现通过 this.xxx 调用方法
        Vue.prototype._proxyMethods = function () {
            var self = this;
            var methods = this._methods;
            if (methods) {
                Object.keys(methods).forEach(function (key) {
                    self[key] = methods[key].bind(self);
                });
            }
        };

        // 发布事件,触发相应的事件回调函数
        Vue.prototype.$emit = function (eventName, payload) {
            this._eventBus.emit(eventName, payload);
        };

        // 订阅事件,注册事件回调函数
        Vue.prototype.$on = function (eventName, callback) {
            this._eventBus.on(eventName, callback);
        };

        // 创建一个 Vue 实例
        var app = new Vue({
            // 初始化数据
            data: {
                message: 'Hello, Vue!'
            },
            // 定义方法
            methods: {
                greet: function () {
                    this.$emit('greet', this.message);
                },
                updateMessage: function (newMessage) {
                    this.message = newMessage;
                }
            },
        });

        // 注册 greet 事件的回调函数
        app.$on('greet', function (message) {
            console.log('Greet:', message);
        });

        // 调用 greet 方法,触发 greet 事件
        app.greet(); // 输出: Greet: Hello, Vue!

        // 调用 updateMessage 方法,修改 message 的值
        app.updateMessage('Hello, World!');

        // 再次调用 greet 方法,触发 greet 事件,并输出修改后的 message
        app.greet(); // 输出: Greet: Hello, World!
    </script>
</body>

</html>

Utilice gtp para aprender el principio de la ranura Vue (ranura)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app"></div>
    <script>
        // 定义 Vue 构造函数
        function Vue(options) {
            this.$options = options;
            this._data = typeof options.data === 'function' ? options.data() : options.data;
            this._components = options.components || {};

            // 代理 data 属性到 Vue 实例上
            this._proxyData();

            // 编译模板
            this._compileTemplate();

            // 代理组件
            this._proxyComponents();
        }

        // 将 data 对象的属性代理到 Vue 实例上
        Vue.prototype._proxyData = function () {
            var self = this;
            Object.keys(this._data).forEach(function (key) {
                Object.defineProperty(self, key, {
                    get: function () {
                        return self._data[key];
                    },
                    set: function (newValue) {
                        self._data[key] = newValue;
                    }
                });
            });
        };

        // 编译模板
        Vue.prototype._compileTemplate = function () {
            var self = this;
            var el = this.$options.el;
            var template = this.$options.template || '';

            // 使用 evalExpression 函数执行模板中的表达式
            var evalExpression = function (expression) {
                with (self) return eval(expression);
            }

            // 替换模板中的双花括号表达式为对应的数据值
            var compiledTemplate = template.replace(/\{\{(.*?)\}\}/g, function (match, expression) {
                var value = evalExpression(expression);
                return value !== undefined ? value : '';
            });

            // 将编译后的模板插入目标元素中
            var element = el ? document.querySelector(el) : document.createElement('div');
            element.innerHTML = compiledTemplate.trim();
            this.$el = el ? element : element.childNodes[0];
        };

        // 代理组件
        Vue.prototype._proxyComponents = function () {
            var self = this;
            var components = this._components;

            // 遍历组件对象,创建组件实例并进行代理
            Object.keys(components).forEach(function (componentName) {
                var component = new Vue(components[componentName]);

                // 查询所有组件标签,并将子组件的内容替换到对应的插槽中
                self.$el.querySelectorAll(componentName).forEach(function (element) {
                    component.$el.querySelectorAll('slot').forEach(function (slot) {
                        slot.innerHTML = element.innerHTML;
                    });
                    element.innerHTML = component.$el.outerHTML;
                });
            });
        };

        // 使用示例
        var HelloComponent = {
            data: function () {
                return {
                    name: 'John'
                };
            },
            template: `
    <div>
      <h1>{
   
   { name }}</h1>
      <slot></slot>
    </div>
  `
        };

        // 创建 Vue 实例
        var app = new Vue({
            el: '#app',
            data: {
                message: 'Hello, Vue!'
            },
            components: {
                HelloComponent
            },
            template: `
    <HelloComponent>
      <p>{
   
   { message }}</p>
    </HelloComponent>
  `
        });
    </script>
</body>

</html>

Supongo que te gusta

Origin blog.csdn.net/weixin_52479803/article/details/132290331
Recomendado
Clasificación