lifecycle.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 '
'
+ this.message + ''; - }
- });
注解:
this.$options.beforeMount.call(this);与 this.$options.beforeMount();有什么区别:
call(this)
的作用是将当前对象(this
)作为参数传递给 beforeMount
方法,使得在 beforeMount
方法内部可以通过 this
访问到当前对象的上下文beforeMount
方法,没有指定上下文 index.html
- html>
- <html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>Vuetitle>
- head>
- <body>
- <div id="app">div>
- <script src="./lifecycle.js">script>
- body>
- html>
在浏览器查看渲染结果,并在控制台查看日志输出
另外,我们可以在控制输入 app.message = 'ChatGPT'
来验证数据绑定以及页面更新机制
效果图:
index.html
- html>
- <html lang="en">
-
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Documenttitle>
- 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: // 模板字符串
- `
-
-
{{ message }}
-
-
-
- `
- });
- script>
- body>
-
- html>
效果图:
注解:
with
语句的作用是简化代码,使得可以在该作用域内直接访问对象的属性和方法,而无需重复使用对象名字的前缀
- 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!
- }
是一个正则表达式替换的方法,用于处理模板中的双花括号表达式 {{expression}},
回调函数接收两个参数:
match
:匹配到的整个字符串,即 {{expression}}
。
expression
:匹配到的表达式,即 expression
。
index.html
- html>
- <html lang="en">
-
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Documenttitle>
- 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>
效果图:
- html>
- <html lang="en">
-
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Documenttitle>
- 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>
- html>
- <html lang="en">
-
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Documenttitle>
- 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: `
-
-
{{ name }}
-
-
- `
- };
-
- // 创建 Vue 实例
- var app = new Vue({
- el: '#app',
- data: {
- message: 'Hello, Vue!'
- },
- components: {
- HelloComponent
- },
- template: `
-
-
{{ message }}
-
- `
- });
- script>
- body>
-
- html>