diff --git a/vue2-tutorials/import-script/1-模板语法.md b/vue2-tutorials/import-script/1-模板语法.md new file mode 100644 index 0000000..323e896 --- /dev/null +++ b/vue2-tutorials/import-script/1-模板语法.md @@ -0,0 +1,21 @@ +## Vue2 模板语法详解 + +在 Vue2 中,使用双大括号 `{{}}` 的语法称为插值语法(Mustache 语法),它用于在模板中显示数据。 + +### 基本用法 +```html +

你好:{{name}}

+``` + +### 实现原理 +当 Vue 实例创建时,会将 data 对象中的属性转换为 getter/setter,使其成为响应式数据。当数据变化时,视图会自动更新。 + +```javascript +new Vue({ + el: "#app", + data: { + name: "Bunny", // 响应式数据 + url: "https://v2.cn.vuejs.org/" + } +}) +``` diff --git a/vue2-tutorials/import-script/2-数据绑定.md b/vue2-tutorials/import-script/2-数据绑定.md new file mode 100644 index 0000000..efc0d50 --- /dev/null +++ b/vue2-tutorials/import-script/2-数据绑定.md @@ -0,0 +1,95 @@ +# Vue2 数据绑定 + +本示例展示了 Vue2 中的两种数据绑定方式: +- 单向数据绑定 (`v-bind`) +- 双向数据绑定 (`v-model`) + +## 核心概念详解 + +### 1. 数据绑定类型 + +| 类型 | 指令 | 特点 | 示例 | +| -------- | --------- | ----------------- | ----------------------------- | +| 单向绑定 | `v-bind` | 数据→视图单向流动 | `` | +| 双向绑定 | `v-model` | 数据⇄视图双向同步 | `` | + +### 2. Vue 实例创建方式 + +```javascript +// 推荐写法 (ES6简写) +data() { + return { + name: "数据绑定" + } +} + +// 等价于 +data: function() { + return { + name: "数据绑定" + } +} + +// 不推荐在组件中使用 +data: { + name: "数据绑定" +} +``` + +### 3. 动态挂载机制 + +```javascript +// 延迟挂载示例 +setTimeout(() => { + v.$mount("#app"); // 手动挂载到#app +}, 1000); + +// 实例销毁与重建 +setTimeout(() => { + v.$destroy(); // 销毁旧实例 + + const v2 = new Vue({ // 创建新实例 + data: { name: "新数据绑定" } + }); + v2.$mount("#root"); // 挂载到新位置 +}, 2000); +``` + +1. **数据绑定选择**: + - 表单元素使用 `v-model` 实现双向绑定 + - 普通属性使用 `v-bind` 实现单向绑定 + +2. **实例管理**: + - 避免在同一个元素上重复挂载不同实例 + - 切换挂载目标时务必先销毁旧实例 + +3. **数据定义**: + - 组件中必须使用函数形式返回data对象 + - 根实例可以使用对象形式 + +4. **性能优化**: + - 大量数据绑定时考虑使用计算属性 + - 复杂场景可使用自定义指令优化 + +## 扩展说明 + +### 1. `v-model` 原理 +`v-model` 本质上是语法糖,等价于: +```html + +``` + +### 2. 挂载方式对比 +| 方式 | 示例 | 适用场景 | +| ---------- | ------------------- | -------------------- | +| el选项 | `el: "#app"` | 初始化时确定挂载点 | +| $mount方法 | `vm.$mount("#app")` | 需要延迟或条件挂载时 | + +### 3. 实例生命周期 +- `new Vue()` 创建实例 +- `$mount()` 触发挂载流程 +- `$destroy()` 触发销毁流程 + +通过本文档,您可以全面了解 Vue2 的数据绑定机制和实例管理方法,为实际开发提供参考。 diff --git a/vue2-tutorials/import-script/3-Object.defineProperty.md b/vue2-tutorials/import-script/3-Object.defineProperty.md new file mode 100644 index 0000000..c82d760 --- /dev/null +++ b/vue2-tutorials/import-script/3-Object.defineProperty.md @@ -0,0 +1,76 @@ +# `Object.defineProperty` 方法 + +## 一、基本概念 + +`Object.defineProperty()` 是 JavaScript 中用于直接在一个对象上定义一个新属性,或者修改一个对象的现有属性的方法。它允许精确控制属性的行为特性。 + +## 属性描述符详解 + +### 1. 数据描述符(已注释部分) +```javascript +{ + value: 18, // 属性值 + enumerable: true, // 是否可枚举(for...in或Object.keys()) + writable: true, // 是否可修改 + configurable: true // 是否可删除或修改特性 +} +``` + +### 2. 存取描述符(实际使用部分) +```javascript +{ + get() { + // 读取属性时调用 + return age; + }, + set(value) { + // 设置属性时调用 + age = value; + } +} +``` + +## 特性说明 + +| 特性 | 类型 | 默认值 | 描述 | +| ------------ | ---- | --------- | ------------------------ | +| configurable | 布尔 | false | 是否可删除属性或修改特性 | +| enumerable | 布尔 | false | 是否出现在枚举属性中 | +| value | 任意 | undefined | 属性值 | +| writable | 布尔 | false | 是否可被赋值运算符改变 | +| get | 函数 | undefined | 读取属性时调用的函数 | +| set | 函数 | undefined | 设置属性时调用的函数 | + +## 使用场景 + +1. **实现数据响应式**(如Vue2的核心实现) +2. **创建私有属性**(通过getter/setter控制访问) +3. **属性访问拦截**(在读取或设置时执行额外操作) +4. **定义不可枚举属性**(如内置对象的一些方法) + +## 注意事项 + +1. 数据描述符(value, writable)和存取描述符(get, set)不能同时使用 +2. 默认情况下,通过defineProperty添加的属性不可枚举、不可写、不可配置 +3. 在严格模式下,setter必须设置一个参数,否则会抛出错误 +4. getter不应有副作用(如修改其他属性值) + +**实现简单响应式** + +```javascript +function defineReactive(obj, key, val) { + Object.defineProperty(obj, key, { + get() { + console.log(`读取 ${key}: ${val}`); + return val; + }, + set(newVal) { + console.log(`设置 ${key}: ${newVal}`); + val = newVal; + } + }); +} + +const data = {}; +defineReactive(data, 'message', 'Hello'); +``` diff --git a/vue2-tutorials/import-script/4-理解数据代理.md b/vue2-tutorials/import-script/4-理解数据代理.md new file mode 100644 index 0000000..60ecf09 --- /dev/null +++ b/vue2-tutorials/import-script/4-理解数据代理.md @@ -0,0 +1,104 @@ +# JavaScript 数据代理实现文档 + +## 一、基本概念 + +数据代理是指通过一个对象(代理对象)间接访问和操作另一个对象(目标对象)的属性。本示例展示了如何使用 `Object.defineProperty` 实现简单的数据代理。 + +## 二、代码实现解析 + +```javascript +let obj1 = { x: 100 }; // 目标对象(被代理对象) +let obj2 = { y: 200 }; // 代理对象 + +// 在obj2上定义x属性的代理 +Object.defineProperty(obj2, "x", { + get() { + return obj1.x; // 读取时返回obj1的x属性 + }, + set(value) { + obj1.x = value; // 设置时修改obj1的x属性 + } +}); +``` + +## 三、核心机制说明 + +1. **代理原理**: + - 通过 `Object.defineProperty` 在代理对象(obj2)上定义新属性 + - 使用 getter/setter 方法实现对目标对象(obj1)属性的间接访问 + +2. **访问流程**: + - 读取 `obj2.x` → 触发 getter → 返回 `obj1.x` 的值 + - 设置 `obj2.x` → 触发 setter → 将值赋给 `obj1.x` + +3. **特性**: + - 透明的属性访问(使用者无需知道代理存在) + - 可以在访问前后执行额外逻辑(如验证、日志等) + +## 四、应用场景 + +| 场景 | 说明 | 示例 | +| -------- | -------------------- | ------------------------------ | +| 属性转发 | 跨对象访问属性 | 本示例实现 | +| 数据验证 | 设置属性前检查有效性 | setter中添加验证逻辑 | +| 访问控制 | 限制某些属性的访问 | getter中添加权限检查 | +| 日志记录 | 跟踪属性访问 | getter/setter中添加console.log | + +## 五、扩展实现 + +### 1. 多属性代理 +```javascript +function proxyProperties(target, source, props) { + props.forEach(prop => { + Object.defineProperty(target, prop, { + get() { + return source[prop]; + }, + set(value) { + source[prop] = value; + } + }); + }); +} + +// 使用示例 +proxyProperties(obj2, obj1, ['x', 'a', 'b']); +``` + +### 2. Vue2 风格的数据代理 +```javascript +function observe(obj) { + const handler = { + get(target, prop) { + console.log(`读取 ${prop}`); + return target[prop]; + }, + set(target, prop, value) { + console.log(`设置 ${prop} 为 ${value}`); + target[prop] = value; + return true; + } + }; + return new Proxy(obj, handler); +} + +const observed = observe(obj1); +``` + +## 六、注意事项 + +1. **性能考虑**: + - 每个代理属性都会增加访问开销 + - 避免在性能关键路径上过度使用 + +2. **引用关系**: + - 代理对象和目标对象保持独立 + - 修改代理属性会影响原始对象 + +3. **枚举特性**: + - 默认情况下代理属性不可枚举 + - 需要显式设置 `enumerable: true` + +4. **兼容性**: + - `Object.defineProperty` 是 ES5 特性 + - 现代开发可考虑使用 ES6 Proxy diff --git a/vue2-tutorials/import-script/5-Vue中的数据代理.html b/vue2-tutorials/import-script/5-Vue中的数据代理.html new file mode 100644 index 0000000..61a8338 --- /dev/null +++ b/vue2-tutorials/import-script/5-Vue中的数据代理.html @@ -0,0 +1,30 @@ + + + + + + + + Vue中的数据代理 + + + +
+ Vue中的数据代理: {{name}} +
+ + + + + \ No newline at end of file diff --git a/vue2-tutorials/import-script/5-Vue中的数据代理.md b/vue2-tutorials/import-script/5-Vue中的数据代理.md new file mode 100644 index 0000000..aa3200d --- /dev/null +++ b/vue2-tutorials/import-script/5-Vue中的数据代理.md @@ -0,0 +1,146 @@ +# Vue2 数据代理机制详解 + +## 一、核心概念 + +Vue2 中的数据代理是指 Vue 实例(vm)代理其 `data` 对象中属性的访问和修改操作。通过这种机制,我们可以直接通过 `vm.xxx` 访问 `data` 中的属性,而不需要写 `vm._data.xxx`。 + +## 二、代码示例解析 + +```html +
+ Vue中的数据代理: {{name}} +
+ + +``` + +## 三、实现原理 + +### 1. 数据存储结构 +- 原始 `data` 对象被存储在 `vm._data` 属性中 +- 通过 `Object.defineProperty` 将 `data` 的属性代理到 Vue 实例上 + +### 2. 验证方法 +```javascript +// 验证代理关系 +const externalData = { name: "代理..." }; +const vm = new Vue({ + el: "#app", + data: externalData +}); + +console.log(vm._data === externalData); // true +console.log(vm.name === vm._data.name); // true +``` + +### 3. 代理实现机制 +Vue 内部大致执行了以下操作: +```javascript +// 伪代码展示代理原理 +Object.keys(data).forEach(key => { + Object.defineProperty(vm, key, { + get() { + return vm._data[key]; + }, + set(value) { + vm._data[key] = value; + } + }); +}); +``` + +## 四、数据流图示 + +``` +模板访问 + ↓ +vm.name (代理访问) + ↓ +vm._data.name (实际数据存储) + ↓ +数据劫持 (响应式系统) +``` + +## 五、关键特性 + +| 特性 | 说明 | 示例 | +| ---------- | ---------------------- | ------------------------------ | +| 直接访问 | 省略 `_data` 前缀 | `vm.name` 代替 `vm._data.name` | +| 响应式绑定 | 代理属性也是响应式的 | 修改 `vm.name` 会触发视图更新 | +| 数据隔离 | `_data` 保存原始数据 | 防止直接修改破坏响应式 | +| 统一入口 | 提供一致的数据访问方式 | 简化模板和方法的编写 | + +## 六、与数据劫持的关系 + +1. **数据代理**: + - 解决的是访问便捷性问题(`vm.xxx` vs `vm._data.xxx`) + - 通过 `Object.defineProperty` 实现属性转发 + +2. **数据劫持**: + - 解决的是响应式问题(数据变化触发视图更新) + - 在 `vm._data` 上实现,通过重写 getter/setter + +3. **协作流程**: + - 模板访问 `{{name}}` → 触发代理 getter + - 代理 getter 访问 `_data.name` → 触发劫持 getter + - 建立依赖收集关系 + +## 七、注意事项 + +1. **新增属性**: + - 直接 `vm.newProp = value` 不会成为响应式 + - 必须使用 `Vue.set` 或预先声明 + +2. **性能影响**: + - 每个代理属性都会产生一定的内存开销 + - 大型项目应考虑分模块管理数据 + +3. **调试技巧**: + - 通过 `vm._data` 查看原始数据 + - 使用 Vue Devtools 观察数据变化 + +4. **与 Vue3 区别**: + - Vue3 使用 Proxy 实现更完善的代理 + - 可以检测属性添加/删除操作 + +## 八、扩展应用 + +### 1. 自定义代理逻辑 +```javascript +// 在Vue实例上添加自定义代理 +created() { + Object.defineProperty(this, 'fullName', { + get() { + return `${this.firstName} ${this.lastName}`; + }, + set(value) { + const parts = value.split(' '); + this.firstName = parts[0]; + this.lastName = parts[1] || ''; + } + }); +} +``` + +### 2. 代理模式应用 +```javascript +// 实现组件间的数据代理 +const proxyMixin = { + methods: { + proxy(prop) { + return { + get: () => this[prop], + set: (val) => this[prop] = val + }; + } + } +}; +``` + diff --git a/vue2-tutorials/import-script/6-事件处理.html b/vue2-tutorials/import-script/6-事件处理.html new file mode 100644 index 0000000..1cce0f2 --- /dev/null +++ b/vue2-tutorials/import-script/6-事件处理.html @@ -0,0 +1,37 @@ + + + + + + + + 事件处理 + + + +
+

Vue2-事件处理

+ + +
+ + + + + \ No newline at end of file diff --git a/vue2-tutorials/import-script/6-事件处理.md b/vue2-tutorials/import-script/6-事件处理.md new file mode 100644 index 0000000..ac7891f --- /dev/null +++ b/vue2-tutorials/import-script/6-事件处理.md @@ -0,0 +1,158 @@ +# Vue2 事件处理机制文档 + +## 一、基本概念 + +Vue2 提供了 `v-on` 指令(简写为 `@`)用于监听 DOM 事件并执行相应的 JavaScript 代码。本示例展示了 Vue2 中事件处理的基本用法,包括不传参和传参两种场景。 + +## 二、代码示例解析 + +```html +
+

Vue2-事件处理

+ + +
+ + +``` + +## 三、核心特性说明 + +### 1. 事件绑定语法 + +| 语法形式 | 示例 | 说明 | +| -------- | ---------------------- | ----------------- | +| 完整写法 | `v-on:click="handler"` | 使用 `v-on:` 前缀 | +| 简写形式 | `@click="handler"` | 更简洁的写法 | + +### 2. 方法定义位置 + +所有事件处理函数应定义在 Vue 实例的 `methods` 选项中: +```javascript +methods: { + handler1() { /* ... */ }, + handler2() { /* ... */ } +} +``` + +### 3. 参数传递方式 + +| 场景 | 示例 | 说明 | +| -------------- | ------------------------------- | ------------------------------ | +| 不传参 | `@click="showinfo1"` | 自动传入事件对象 | +| 传参 | `@click="showinfo2($event,66)"` | 使用 `$event` 传递原生事件对象 | +| 仅传自定义参数 | `@click="showinfo2(66)"` | 事件对象将不可用 | + +## 四、事件对象详解 + +### 1. 获取事件对象的方式 +- **不传参时**:自动作为第一个参数传入 + ```javascript + methods: { + showinfo1(event) { + // event 可用 + } + } + ``` + +- **传参时需要**:必须显式传递 `$event` + ```html + + ``` + +### 2. 常用事件对象属性 +| 属性/方法 | 类型 | 说明 | +| ----------------------- | -------- | -------------- | +| event.target | Element | 触发事件的元素 | +| event.currentTarget | Element | 绑定事件的元素 | +| event.preventDefault() | Function | 阻止默认行为 | +| event.stopPropagation() | Function | 停止事件冒泡 | + +## 五、最佳实践建议 + +1. **方法命名**: + - 使用动词开头(如 `handleClick`、`submitForm`) + - 保持名称语义化 + +2. **参数处理**: + - 需要事件对象时确保正确传递 `$event` + - 复杂参数建议使用对象形式: + ```html + + ``` + +3. **方法组织**: + - 相关功能的方法放在一起 + - 大型组件可考虑按功能分模块 + +## 六、扩展应用 + +### 1. 事件修饰符 +Vue 提供了特殊的事件修饰符: + +```html + +
+ + +
+ + + + + + +``` + +![image-20250614180522000](./images/image-20250614180522000.png) + +### 2. 自定义事件 + +组件间通信时使用: + +```javascript +// 子组件 +this.$emit('my-event', payload); + +// 父组件 + +``` + +### 3. 原生事件绑定到组件 +使用 `.native` 修饰符: + +```html + +``` + +## 七、注意事项 + +1. **避免内联计算**: + ```html + + + + + + ``` + +2. **this 指向**: + - methods 中的方法自动绑定到 Vue 实例 + - 避免使用箭头函数定义方法,会导致 this 指向错误 + +3. **性能考虑**: + - 频繁触发的事件(如 scroll)建议使用防抖/节流 + - 大量事件监听应考虑事件委托 diff --git a/vue2-tutorials/import-script/7-键盘事件.html b/vue2-tutorials/import-script/7-键盘事件.html new file mode 100644 index 0000000..bcb04fc --- /dev/null +++ b/vue2-tutorials/import-script/7-键盘事件.html @@ -0,0 +1,31 @@ + + + + + + + + 键盘事件 + + + +
+ 键盘事件: +
+ + + + + \ No newline at end of file diff --git a/vue2-tutorials/import-script/7-键盘事件.md b/vue2-tutorials/import-script/7-键盘事件.md new file mode 100644 index 0000000..8c6af2e --- /dev/null +++ b/vue2-tutorials/import-script/7-键盘事件.md @@ -0,0 +1,153 @@ +# Vue2 键盘事件处理文档 + +## 一、基本概念 + +Vue2 提供了对键盘事件的支持,允许开发者监听特定的按键操作。本示例展示了如何自定义键盘事件别名并处理回车键事件。 + +## 二、代码示例解析 + +```html +
+ 键盘事件: +
+ + +``` + +## 三、核心机制说明 + +### 1. 键盘事件绑定语法 + +| 语法形式 | 示例 | 说明 | +| ---------- | --------------------------- | ------------------ | +| 基础写法 | `@keydown="handler"` | 监听所有按键 | +| 按键修饰符 | `@keydown.enter="handler"` | 仅监听回车键 | +| 自定义别名 | `@keydown.huiche="handler"` | 使用自定义按键别名 | + +### 2. 按键修饰符类型 + +Vue 提供了这些常用内置按键别名: +- `.enter` +- `.tab` +- `.delete` (捕获"删除"和"退格"键) +- `.esc` +- `.space` +- `.up` +- `.down` +- `.left` +- `.right` + +### 3. 自定义按键别名 + +通过 `Vue.config.keyCodes` 对象添加: +```javascript +// 语法 +Vue.config.keyCodes.自定义名称 = 按键keyCode; + +// 示例:将F1键(112)别名为help +Vue.config.keyCodes.help = 112; +``` + +## 四、键盘事件对象 + +在方法中可以访问原生事件对象: +```javascript +methods: { + showinfo(event) { + console.log(event.key); // 按键名称(如'Enter') + console.log(event.keyCode); // 按键代码(如13) + console.log(event.target); // 触发事件的元素 + } +} +``` + +## 五、最佳实践建议 + +1. **优先使用内置别名**: + - 提高代码可读性 + - 避免记忆keyCode数字 + +2. **复杂按键组合**: + ```html + + + + + + ``` + +3. **系统修饰键**: + - `.ctrl` + - `.alt` + - `.shift` + - `.meta` (Mac是Command键,Windows是Windows键) + +## 六、扩展应用 + +### 1. 自动聚焦示例 +```html + + +methods: { + nextInput() { + this.$refs.nextInput.focus(); + } +} +``` + +### 2. 表单提交优化 +```html +
+ + +
+``` + +### 3. 游戏控制示例 +```javascript +// 监听方向键控制游戏角色 +created() { + window.addEventListener('keyup', this.handleKeyup); +}, +methods: { + handleKeyup(e) { + switch(e.keyCode) { + case 37: this.moveLeft(); break; + case 38: this.moveUp(); break; + // ... + } + } +} +``` + +## 七、注意事项 + +1. **keyCode已废弃**: + - 现代浏览器建议使用 `event.key` 代替 + - Vue3 已移除对keyCode的支持 + +2. **输入法问题**: + - 某些输入法下可能无法正确触发事件 + - 中文输入时考虑使用 `@keyup` 代替 `@keydown` + +3. **移动端适配**: + - 虚拟键盘行为可能不一致 + - 建议配合触摸事件使用 + +4. **事件冒泡**: + - 使用 `.stop` 修饰符阻止冒泡 + ```html +
+ ``` diff --git a/vue2-tutorials/import-script/images/image-20250614180522000.png b/vue2-tutorials/import-script/images/image-20250614180522000.png new file mode 100644 index 0000000..2736013 Binary files /dev/null and b/vue2-tutorials/import-script/images/image-20250614180522000.png differ