JavaScript 篇
一、JavaScript 内置对象
JavaScript 提供了许多内置对象,用于处理数据、执行操作和管理程序逻辑。以下是常见的内置对象及其用途:
1. 全局对象
Object
:所有对象的基类,提供创建和操作对象的方法。Function
:函数的构造函数,用于创建函数对象。Array
:用于创建和操作数组。String
:用于创建和操作字符串。Number
:用于创建和操作数字。Boolean
:用于创建和操作布尔值。Date
:用于处理日期和时间。Math
:提供数学运算的属性和方法。RegExp
:用于创建和操作正则表达式。Error
:用于处理错误。
2. 其他内置对象
JSON
:用于解析和序列化 JSON 数据。Promise
:用于处理异步操作。Map
和Set
:用于存储键值对和唯一值。Symbol
:用于创建唯一的标识符。Proxy
:用于定义对象行为的自定义操作。Reflect
:提供操作对象的静态方法。
二、浏览器缓存的存储方式与区别
浏览器缓存是浏览器存储数据的一种机制,用于提高页面加载速度和减少服务器请求。以下是常见的浏览器缓存存储方式及其区别:
1. Cookie
-
特点 :
- 存储大小:约 4KB。
- 生命周期:可设置过期时间,默认关闭浏览器后失效。
- 作用域:可设置
domain
和path
,限制作用范围。 - 自动发送:每次请求都会携带 Cookie。
-
用途 :
- 存储用户会话信息(如登录状态)。
- 跟踪用户行为。
-
示例 :
javascriptdocument.cookie = "username=John; expires=Thu, 18 Dec 2025 12:00:00 UTC; path=/";
2. LocalStorage
-
特点 :
- 存储大小:约 5MB。
- 生命周期:永久存储,除非手动清除。
- 作用域:同源页面共享。
- 不自动发送:不会随请求发送。
-
用途 :
- 存储长期数据(如用户偏好设置)。
-
示例 :
javascriptlocalStorage.setItem('key', 'value'); const value = localStorage.getItem('key');
3. SessionStorage
-
特点 :
- 存储大小:约 5MB。
- 生命周期:会话结束时清除(关闭浏览器标签页)。
- 作用域:同一标签页内共享。
- 不自动发送:不会随请求发送。
-
用途 :
- 存储临时数据(如表单数据)。
-
示例 :
javascriptsessionStorage.setItem('key', 'value'); const value = sessionStorage.getItem('key');
4. IndexedDB
-
特点 :
- 存储大小:理论上无限制,通常为 50MB 以上。
- 生命周期:永久存储,除非手动清除。
- 作用域:同源页面共享。
- 不自动发送:不会随请求发送。
-
用途 :
- 存储大量结构化数据(如离线应用数据)。
-
示例 :
javascriptconst request = indexedDB.open('myDatabase', 1); request.onsuccess = (event) => { const db = event.target.result; const transaction = db.transaction('store', 'readwrite'); const store = transaction.objectStore('store'); store.add({ id: 1, name: 'John' }); };
5. Cache API
-
特点 :
- 存储大小:取决于浏览器,通常为 50MB 以上。
- 生命周期:永久存储,除非手动清除。
- 作用域:同源页面共享。
- 不自动发送:不会随请求发送。
-
用途 :
- 存储网络请求的响应(如 PWA 的离线资源)。
-
示例 :
javascriptcaches.open('my-cache').then(cache => { cache.add('/index.html'); });
三、浏览器缓存存储方式的区别
特性 | Cookie | LocalStorage | SessionStorage | IndexedDB | Cache API |
---|---|---|---|---|---|
存储大小 | 4KB | 5MB | 5MB | 50MB+ | 50MB+ |
生命周期 | 可设置过期时间 | 永久存储 | 会话结束清除 | 永久存储 | 永久存储 |
作用域 | 可设置 domain 和 path |
同源页面共享 | 同一标签页内共享 | 同源页面共享 | 同源页面共享 |
自动发送 | 是 | 否 | 否 | 否 | 否 |
用途 | 会话管理、用户跟踪 | 长期数据存储 | 临时数据存储 | 大量结构化数据存储 | 网络请求响应缓存 |
四、总结
- JavaScript 内置对象 :包括
Object
、Array
、String
、Promise
等,用于处理数据和执行操作。 - 浏览器缓存存储方式 :
- Cookie:适合存储小量会话数据。
- LocalStorage:适合长期存储数据。
- SessionStorage:适合临时存储数据。
- IndexedDB:适合存储大量结构化数据。
- Cache API:适合缓存网络请求响应。
ES6新特性
一、变量声明
1. let
和 const
-
let
:用于声明块级作用域的变量,解决了var
的变量提升问题。javascriptif (true) { let x = 10; } console.log(x); // 报错:x 未定义
-
const
:用于声明常量,值不可重新赋值。javascriptconst PI = 3.14; PI = 3.14159; // 报错:常量不可重新赋值
二、箭头函数
2. 箭头函数
-
简化函数定义,自动绑定
this
。javascriptconst add = (a, b) => a + b; console.log(add(1, 2)); // 3
-
this
绑定 :箭头函数的this
指向定义时的上下文,而非调用时的上下文。javascriptconst obj = { value: 10, getValue: function() { setTimeout(() => { console.log(this.value); // 10 }, 1000); } }; obj.getValue();
三、模板字符串
3. 模板字符串
-
使用反引号(`````)定义字符串,支持多行文本和嵌入表达式。
javascriptconst name = 'John'; const message = `Hello, ${name}! Welcome to ES6.`; console.log(message);
四、解构赋值
4. 解构赋值
-
从数组或对象中提取值并赋值给变量。
javascript// 数组解构 const [a, b] = [1, 2]; console.log(a, b); // 1 2 // 对象解构 const { name, age } = { name: 'John', age: 30 }; console.log(name, age); // John 30
五、默认参数
5. 默认参数
-
为函数参数设置默认值。
javascriptfunction greet(name = 'Guest') { console.log(`Hello, ${name}!`); } greet(); // Hello, Guest! greet('John'); // Hello, John!
六、扩展运算符与剩余参数
6. 扩展运算符(...
)
-
用于展开数组或对象。
javascriptconst arr1 = [1, 2, 3]; const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5] const obj1 = { a: 1, b: 2 }; const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }
7. 剩余参数(...
)
-
用于将剩余的参数收集到一个数组中。
javascriptfunction sum(...numbers) { return numbers.reduce((acc, num) => acc + num, 0); } console.log(sum(1, 2, 3)); // 6
七、对象字面量增强
8. 对象字面量增强
-
简化对象属性和方法的定义。
javascriptconst name = 'John'; const age = 30; const person = { name, age, greet() { console.log('Hello!'); } }; console.log(person); // { name: 'John', age: 30, greet: [Function: greet] }
八、类(Class)
9. 类
-
提供更清晰的面向对象编程语法。
javascriptclass Person { constructor(name, age) { this.name = name; this.age = age; } greet() { console.log(`Hello, my name is ${this.name}`); } } const john = new Person('John', 30); john.greet(); // Hello, my name is John
九、模块化
10. 模块化
-
使用
import
和export
实现模块化。javascript// math.js export const add = (a, b) => a + b; export const subtract = (a, b) => a - b; // main.js import { add, subtract } from './math.js'; console.log(add(1, 2)); // 3
十、Promise
11. Promise
-
用于处理异步操作,避免回调地狱。
javascriptconst fetchData = () => { return new Promise((resolve, reject) => { setTimeout(() => resolve('Data fetched'), 1000); }); }; fetchData().then(data => console.log(data)); // Data fetched
十一、迭代器与生成器
12. 迭代器(Iterator)
-
提供统一的遍历接口。
javascriptconst arr = [1, 2, 3]; const iterator = arr[Symbol.iterator](); console.log(iterator.next()); // { value: 1, done: false }
13. 生成器(Generator)
-
使用
function*
定义生成器函数,通过yield
暂停执行。javascriptfunction* generateSequence() { yield 1; yield 2; yield 3; } const generator = generateSequence(); console.log(generator.next()); // { value: 1, done: false }
十二、Set 和 Map
14. Set
-
存储唯一值的集合。
javascriptconst set = new Set([1, 2, 3, 3]); console.log(set); // Set { 1, 2, 3 }
15. Map
-
存储键值对的集合,键可以是任意类型。
javascriptconst map = new Map(); map.set('name', 'John'); console.log(map.get('name')); // John
十三、Symbol
16. Symbol
-
创建唯一的标识符。
javascriptconst id = Symbol('id'); const obj = { [id]: 123 }; console.log(obj[id]); // 123
十四、Proxy 和 Reflect
17. Proxy
-
用于定义对象行为的自定义操作。
javascriptconst target = { name: 'John' }; const handler = { get(target, prop) { return prop in target ? target[prop] : 'Unknown'; } }; const proxy = new Proxy(target, handler); console.log(proxy.name); // John console.log(proxy.age); // Unknown
18. Reflect
-
提供操作对象的静态方法。
javascriptconst obj = { name: 'John' }; console.log(Reflect.get(obj, 'name')); // John
十五、其他特性
19. for...of
循环
-
用于遍历可迭代对象(如数组、字符串、Set、Map)。
javascriptconst arr = [1, 2, 3]; for (const num of arr) { console.log(num); // 1, 2, 3 }
20. Array.from
和 Array.of
-
Array.from
:将类数组对象或可迭代对象转换为数组。javascriptconst arrayLike = { 0: 'a', 1: 'b', length: 2 }; const arr = Array.from(arrayLike); // ['a', 'b']
-
Array.of
:将一组值转换为数组。javascriptconst arr = Array.of(1, 2, 3); // [1, 2, 3]
总结
ES6 引入了许多强大的新特性,如 let
/const
、箭头函数、模板字符串、解构赋值、类、模块化、Promise 等,极大地提升了 JavaScript 的开发效率和代码可读性。 $attrs
是 Vue 提供的一个特殊属性,用于访问父组件传递给子组件的非 Prop 属性 (即未被组件显式声明为 props
的属性)。这些属性可以是 HTML 属性(如 class
、style
等)或自定义属性。
vue相关
1. $attrs
的作用
- 访问非 Prop 属性 :父组件传递给子组件的属性,如果子组件没有在
props
中声明,这些属性会被收集到$attrs
中。 - 透传属性 :可以将
$attrs
传递给子组件的子组件,实现属性的透传。
2. $attrs
的使用场景
- 透传属性 :当子组件需要将父组件传递的属性继续传递给它的子组件时,可以使用
$attrs
。 - 动态绑定属性 :当子组件需要动态绑定父组件传递的属性时,可以使用
$attrs
。 - 处理原生 HTML 属性 :当子组件需要处理父组件传递的原生 HTML 属性(如
class
、style
等)时,可以使用$attrs
。
3. $attrs
的特性
- 自动收集 :所有未被
props
声明的属性都会被收集到$attrs
中。 - 不包含
class
和style
:在 Vue 2 中,$attrs
不包含class
和style
,它们会被单独处理。在 Vue 3 中,$attrs
包含class
和style
。 - 透传 :可以通过
v-bind="$attrs"
将$attrs
传递给子组件的子组件。
4. 示例代码
Vue 2 示例
vue
<!-- 父组件 -->
<template>
<ChildComponent class="parent-class" style="color: red" data-custom="123" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
vue
<!-- 子组件 ChildComponent -->
<template>
<div>
<!-- 使用 $attrs 绑定属性 -->
<div v-bind="$attrs">子组件内容</div>
<p>非 Prop 属性: {{ $attrs }}</p>
</div>
</template>
<script>
export default {
// 未声明 props
};
</script>
输出结果:
$attrs
包含data-custom="123"
,但不包含class
和style
。div
元素会继承data-custom="123"
属性。
Vue 3 示例
在 Vue 3 中,$attrs
包含 class
和 style
。
vue
<!-- 父组件 -->
<template>
<ChildComponent class="parent-class" style="color: red" data-custom="123" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
vue
<!-- 子组件 ChildComponent -->
<template>
<div>
<!-- 使用 $attrs 绑定属性 -->
<div v-bind="$attrs">子组件内容</div>
<p>非 Prop 属性: {{ $attrs }}</p>
</div>
</template>
<script>
export default {
// 未声明 props
};
</script>
输出结果:
$attrs
包含class="parent-class"
、style="color: red"
和data-custom="123"
。div
元素会继承class
、style
和data-custom
属性。
5. inheritAttrs
选项
- 作用 :控制是否将
$attrs
中的属性自动绑定到组件的根元素上。 - 默认值 :
true
,即自动绑定。 - 设置为
false
:禁止自动绑定,可以手动通过v-bind="$attrs"
绑定到指定元素。
示例代码
vue
<!-- 子组件 ChildComponent -->
<template>
<div>
<!-- 手动绑定 $attrs -->
<div v-bind="$attrs">子组件内容</div>
<p>非 Prop 属性: {{ $attrs }}</p>
</div>
</template>
<script>
export default {
inheritAttrs: false // 禁止自动绑定到根元素
};
</script>
6. useAttrs
(Vue 3 Composition API)
在 Vue 3 的 Composition API 中,可以使用 useAttrs
来访问 $attrs
。
示例代码
vue
<!-- 子组件 ChildComponent -->
<template>
<div>
<div v-bind="attrs">子组件内容</div>
<p>非 Prop 属性: {{ attrs }}</p>
</div>
</template>
<script>
import { useAttrs } from 'vue';
export default {
setup() {
const attrs = useAttrs();
return { attrs };
}
};
</script>
7. 总结
$attrs
:用于访问父组件传递的非 Prop 属性。- 透传属性 :通过
v-bind="$attrs"
将属性传递给子组件的子组件。 inheritAttrs
:控制是否自动绑定$attrs
到根元素。- Vue 3 :
$attrs
包含class
和style
,并且可以使用useAttrs
访问。
通过 $attrs
,可以更灵活地处理父组件传递的属性,尤其是在开发高阶组件或封装通用组件时非常有用。 在 Vue 中,获取 DOM 元素的常用钩子函数是 mounted
。mounted
是 Vue 生命周期钩子之一,表示组件已经被挂载到 DOM 中,此时可以安全地访问和操作 DOM 元素。
1. mounted
钩子函数
- 作用:在组件挂载到 DOM 后调用,此时可以访问 DOM 元素。
- 使用场景:获取 DOM 元素、初始化第三方库(如图表库、地图库)、绑定事件监听器等。
示例代码:
vue
<template>
<div ref="myElement">这是一个DOM元素</div>
</template>
<script>
export default {
mounted() {
// 通过 ref 获取 DOM 元素
const element = this.$refs.myElement;
console.log(element); // 输出 DOM 元素
element.style.color = 'red'; // 修改 DOM 样式
}
}
</script>
2. updated
钩子函数
- 作用:在组件更新后调用,此时 DOM 已经重新渲染。
- 使用场景:在 DOM 更新后执行某些操作,比如根据新的数据调整 DOM。
示例代码:
vue
<template>
<div ref="myElement">{{ message }}</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello Vue!'
};
},
updated() {
// 在 DOM 更新后获取元素
const element = this.$refs.myElement;
console.log('DOM 已更新:', element);
},
methods: {
changeMessage() {
this.message = 'Updated Message!';
}
},
mounted() {
// 模拟数据更新
setTimeout(() => {
this.changeMessage();
}, 2000);
}
}
</script>
3. nextTick
- 作用:在 DOM 更新后执行回调,确保操作的是最新的 DOM。
- 使用场景:在数据更新后立即操作 DOM。
示例代码:
vue
<template>
<div ref="myElement">{{ message }}</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello Vue!'
};
},
methods: {
updateMessage() {
this.message = 'Updated Message!';
this.$nextTick(() => {
const element = this.$refs.myElement;
console.log('DOM 已更新:', element);
});
}
},
mounted() {
this.updateMessage();
}
}
</script>
4. beforeUpdate
钩子函数
- 作用:在组件更新之前调用,此时 DOM 还未重新渲染。
- 使用场景:在 DOM 更新前执行某些操作。
示例代码:
vue
<template>
<div ref="myElement">{{ message }}</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello Vue!'
};
},
beforeUpdate() {
console.log('DOM 即将更新');
},
methods: {
changeMessage() {
this.message = 'Updated Message!';
}
},
mounted() {
setTimeout(() => {
this.changeMessage();
}, 2000);
}
}
</script>
5. ref
属性
- 作用 :用于标记 DOM 元素或子组件,方便在 Vue 实例中通过
this.$refs
访问。 - 使用场景:获取 DOM 元素或调用子组件的方法。
示例代码:
vue
<template>
<div>
<input ref="myInput" type="text" placeholder="输入内容" />
<button @click="focusInput">聚焦输入框</button>
</div>
</template>
<script>
export default {
methods: {
focusInput() {
// 通过 ref 获取 input 元素并聚焦
this.$refs.myInput.focus();
}
}
}
</script>
总结
mounted
:最常用的获取 DOM 的钩子函数,组件挂载后调用。updated
:在 DOM 更新后调用,适合在数据变化后操作 DOM。nextTick
:确保在 DOM 更新后执行操作。beforeUpdate
:在 DOM 更新前调用。ref
:用于标记 DOM 元素或子组件,通过this.$refs
访问。
根据具体需求选择合适的钩子函数和方式获取和操作 DOM 元素。
防抖与节流、深拷贝与浅拷贝详解
一、防抖(Debounce)与节流(Throttle)
防抖(Debounce)
概念:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
特点:
- 适用于频繁触发但只需处理最后一次的场景
- 比如搜索框输入、窗口大小调整
实现代码:
javascript
function debounce(fn, delay) {
let timer = null;
return function() {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
};
}
节流(Throttle)
概念:规定在一个单位时间内,只能触发一次函数执行,如果这个单位时间内触发多次,只有一次生效。
特点:
- 适用于频繁触发但需要均匀执行的场景
- 比如滚动事件、按钮频繁点击
实现代码:
javascript
function throttle(fn, delay) {
let lastTime = 0;
return function() {
const now = Date.now();
if (now - lastTime >= delay) {
fn.apply(this, arguments);
lastTime = now;
}
};
}
两者区别
特性 | 防抖 | 节流 |
---|---|---|
执行时机 | 停止触发后执行 | 固定间隔执行 |
适用场景 | 输入验证、搜索建议 | 滚动加载、按钮防重复点击 |
效果 | 合并多次为一次 | 稀释执行频率 |
二、深拷贝(Deep Copy)与浅拷贝(Shallow Copy)
浅拷贝
概念:只复制对象的第一层属性,对于引用类型的属性,复制的是内存地址。
实现方式:
Object.assign()
- 展开运算符
...
Array.prototype.slice()
Array.prototype.concat()
示例:
javascript
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };
shallowCopy.b.c = 3; // 会影响原对象
console.log(obj.b.c); // 输出 3
深拷贝
概念:完全复制一个对象,包括对象内部的嵌套对象,新对象与原对象完全独立。
实现方式:
JSON.parse(JSON.stringify(obj))
(有局限性)- 递归实现
- 使用第三方库如lodash的
_.cloneDeep()
递归实现示例:
javascript
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (hash.has(obj)) return hash.get(obj);
const clone = Array.isArray(obj) ? [] : {};
hash.set(obj, clone);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], hash);
}
}
return clone;
}
两者区别
特性 | 浅拷贝 | 深拷贝 |
---|---|---|
复制层级 | 仅第一层 | 所有层级 |
引用类型处理 | 共享内存地址 | 创建新内存空间 |
性能 | 较高 | 较低 |
适用场景 | 简单对象复制 | 需要完全独立的对象 |
注意事项
-
JSON
方法深拷贝的局限性:- 不能处理函数、Symbol、undefined
- 不能处理循环引用
- 会丢失对象的constructor
-
循环引用处理:
- 使用WeakMap存储已拷贝对象
- 遇到已拷贝对象直接返回
-
特殊对象处理:
- Date、RegExp等需要特殊处理
- DOM节点通常不适合深拷贝
理解这些概念对于编写高效、无副作用的JavaScript代码非常重要,特别是在处理复杂对象和频繁事件时。
小程序高频面试题
基础概念
-
什么是小程序?它与传统App有什么区别?
- 小程序是一种不需要下载安装即可使用的应用,它实现了应用"触手可及"的梦想
- 区别:开发成本低、无需安装、即用即走、依赖平台生态、功能受限
-
小程序的优势和劣势是什么?
- 优势:开发成本低、用户获取成本低、跨平台、即用即走
- 劣势:功能受限、依赖平台政策、留存率较低
-
小程序的生命周期有哪些?
- onLoad: 页面加载时触发
- onShow: 页面显示/切入前台时触发
- onReady: 页面初次渲染完成时触发
- onHide: 页面隐藏/切入后台时触发
- onUnload: 页面卸载时触发
开发相关
-
小程序的双线程模型是什么?
- 渲染层(WebView线程): 负责页面渲染
- 逻辑层(JavaScript线程): 负责业务逻辑处理
- 两者通过Native进行通信,提高安全性但增加了通信成本
-
小程序的页面路由有哪些方式?有什么区别?
- wx.navigateTo: 保留当前页面,跳转到新页面
- wx.redirectTo: 关闭当前页面,跳转到新页面
- wx.reLaunch: 关闭所有页面,打开新页面
- wx.switchTab: 跳转到tabBar页面
- wx.navigateBack: 返回上一页面
-
小程序如何实现数据绑定和事件绑定?
- 数据绑定: 使用
{{}}
语法 - 事件绑定: bind/catch + 事件名,如
bindtap
、catchtap
- 数据绑定: 使用
-
小程序如何实现组件化开发?
- 使用Component构造器创建自定义组件
- 通过properties定义组件属性
- 通过methods定义组件方法
- 通过slot实现插槽功能
性能优化
-
小程序性能优化有哪些方法?
- 减少setData的数据量
- 合理使用onPageScroll
- 图片懒加载
- 使用分包加载
- 合理使用缓存
- 避免频繁的页面跳转
-
小程序的分包加载是什么?如何实现?
- 将小程序分成多个包,按需加载
- 配置app.json中的subPackages字段
- 主包包含核心页面和公共资源,分包包含特定功能模块
-
如何优化小程序的启动速度?
- 减少主包体积
- 延迟非必要请求
- 使用缓存策略
- 优化代码执行效率
- 使用按需注入和用时注入
网络与存储
-
小程序的网络请求有哪些限制?
- 必须使用HTTPS
- 需要配置合法域名
- 并发请求数有限制
- 请求超时时间有限制
-
小程序的数据存储方式有哪些?
- 本地缓存: wx.setStorage/wx.getStorage
- 数据库: 云开发数据库
- 文件存储: wx.saveFile/wx.getFileSystemManager
- 全局变量: getApp().globalData
-
如何实现小程序的上传下载功能?
- 上传: wx.uploadFile
- 下载: wx.downloadFile
- 需要配置uploadFile和downloadFile合法域名
跨平台开发
-
如何实现小程序的多端适配?
- 使用uni-app、Taro等跨平台框架
- 条件编译处理平台差异
- 抽象公共业务逻辑
- 针对不同平台优化UI
-
小程序与H5如何通信?
- 通过URL参数传递数据
- 使用web-view组件的postMessage
- 通过本地存储共享数据
安全与权限
-
小程序如何保证用户数据安全?
- 使用HTTPS传输
- 敏感数据加密存储
- 合理设置权限范围
- 使用微信提供的安全接口
-
小程序如何获取用户授权?
- 使用wx.authorize提前获取授权
- 使用button组件的open-type触发授权
- 使用wx.getSetting查询授权状态
实际开发问题
-
如何处理小程序的兼容性问题?
- 检查基础库版本
- 使用条件编译
- 提供降级方案
- 测试不同设备和系统版本
-
小程序如何实现分享功能?
- 配置onShareAppMessage
- 设置分享标题、路径和图片
- 自定义button的open-type="share"
-
如何调试小程序?
- 使用开发者工具的调试功能
- 使用console.log输出日志
- 使用wx.getLogManager管理日志
- 使用真机调试功能
高级话题
-
小程序如何与原生应用交互?
- 使用开放能力如小程序跳转App
- 通过URL Scheme或Universal Link
- 使用插件功能
-
小程序的插件开发流程是怎样的?
- 创建插件项目
- 开发插件功能
- 上传发布插件
- 在小程序中引用插件
-
如何实现小程序的国际化?
- 维护多语言资源文件
- 根据系统语言动态切换
- 使用第三方库如i18n
- 考虑RTL语言布局
-
小程序如何实现动画效果?
- 使用CSS动画
- 使用wx.createAnimation API
- 使用WXS响应事件
- 使用canvas绘制复杂动画
-
小程序云开发有哪些优势?
- 无需搭建服务器
- 集成数据库、存储和云函数
- 简化开发流程
- 提供丰富的后端能力
在小程序中,将路由参数传递到组件内部接收,可以通过以下几种方式实现:
1. 通过 properties
接收参数(推荐)
在页面中通过 properties
将路由参数传递给组件,组件内部通过 properties
接收。
步骤:
-
页面获取路由参数
在页面的
onLoad
生命周期中获取路由参数:javascriptPage({ data: { queryParams: {} // 存储路由参数 }, onLoad(options) { this.setData({ queryParams: options // 接收路由参数 }); } });
-
页面向组件传递参数
在页面的 WXML 中,通过
properties
将参数传递给组件:xml<my-component queryParams="{{queryParams}}"></my-component>
-
组件内部接收参数
在组件的
properties
中定义接收参数:javascriptComponent({ properties: { queryParams: { type: Object, value: {} } }, attached() { console.log(this.data.queryParams); // 获取传递的参数 } });
2. 通过 storage
传递参数(适用于复杂数据)
如果参数较大或需要跨页面共享,可以使用 wx.setStorage
存储,组件内部通过 wx.getStorage
获取。
步骤:
-
页面存储参数
javascriptPage({ onLoad(options) { wx.setStorageSync('queryParams', options); // 存储到本地缓存 } });
-
组件获取参数
javascriptComponent({ attached() { const queryParams = wx.getStorageSync('queryParams'); console.log(queryParams); // 获取存储的参数 } });
3. 通过 eventBus
或全局变量传递(适用于跨组件通信)
如果多个组件需要共享参数,可以使用全局变量或事件总线(EventBus)方式传递。
步骤:
-
在
app.js
定义全局变量javascriptApp({ globalData: { queryParams: null } });
-
页面存储参数
javascriptconst app = getApp(); Page({ onLoad(options) { app.globalData.queryParams = options; // 存入全局变量 } });
-
组件获取参数
javascriptconst app = getApp(); Component({ attached() { console.log(app.globalData.queryParams); // 获取全局参数 } });
4. 通过 observers
监听参数变化(动态更新)
如果参数可能动态变化,可以使用 observers
监听 properties
变化。
步骤:
javascript
Component({
properties: {
queryParams: Object
},
observers: {
'queryParams': function(newVal) {
console.log('参数变化:', newVal); // 监听参数变化
}
}
});
总结
方式 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
properties |
父子组件传参 | 直接、清晰 | 需要逐层传递 |
storage |
跨页面共享数据 | 数据持久化 | 需要手动清理 |
globalData |
全局共享数据 | 简单易用 | 非响应式 |
observers |
监听参数变化 | 响应式更新 | 仅限组件内部 |
推荐方式:
- 简单传参 → 使用
properties
(最常用) - 复杂/跨页面数据 → 使用
storage
或globalData
- 动态监听参数 → 使用
observers
这样,你就可以在组件内部灵活接收路由参数了! 🚀 在 uni-app 开发小程序时,会涉及到 页面生命周期 和 组件生命周期,同时由于 uni-app 的跨平台特性,部分生命周期与原生小程序有所不同。以下是常用的生命周期及其使用场景:
📌 一、页面生命周期(Page Lifecycle)
1. onInit
(仅支付宝小程序)
- 触发时机 :页面初始化时触发(早于
onLoad
) - 用途:支付宝小程序专用,可用于提前初始化数据。
2. onLoad(options)
-
触发时机:页面加载时触发(仅触发一次)
-
参数 :
options
可获取路由参数(如pages/index/index?id=123
中的id
) -
用途 :获取页面参数、初始化数据、发送请求。
javascriptonLoad(options) { console.log('页面参数:', options.id); // 123 this.loadData(); }
3. onShow()
-
触发时机:页面显示/切入前台时触发(每次进入页面都会触发)
-
用途 :刷新数据、监听页面显示(如从后台返回时)。
javascriptonShow() { console.log('页面显示'); this.refreshData(); }
4. onReady()
-
触发时机:页面初次渲染完成(仅触发一次)
-
用途 :操作 DOM、初始化地图/图表等需要渲染完成才能执行的逻辑。
javascriptonReady() { console.log('页面渲染完成'); this.initMap(); }
5. onHide()
-
触发时机:页面隐藏/切入后台时触发(如跳转到其他页面或返回)
-
用途 :清除定时器、暂停动画等。
javascriptonHide() { console.log('页面隐藏'); clearInterval(this.timer); }
6. onUnload()
-
触发时机 :页面卸载时(如
wx.redirectTo
或关闭页面) -
用途 :释放资源、取消事件监听。
javascriptonUnload() { console.log('页面卸载'); this.removeEventListeners(); }
7. onPullDownRefresh()
-
触发时机:用户下拉刷新时触发
-
用途 :实现下拉刷新逻辑。
javascriptonPullDownRefresh() { console.log('下拉刷新'); this.refreshData().then(() => { uni.stopPullDownRefresh(); // 停止刷新动画 }); }
8. onReachBottom()
-
触发时机:页面滚动到底部时触发
-
用途 :实现上拉加载更多(分页)。
javascriptonReachBottom() { console.log('触底加载'); this.loadMoreData(); }
9. onPageScroll(e)
-
触发时机:页面滚动时触发
-
参数 :
e.scrollTop
可获取滚动距离 -
用途 :监听滚动事件(如吸顶效果)。
javascriptonPageScroll(e) { console.log('滚动距离:', e.scrollTop); if (e.scrollTop > 100) { this.setData({ showBackTop: true }); } }
10. onShareAppMessage()
-
触发时机:用户点击右上角分享时触发
-
用途 :自定义分享内容。
javascriptonShareAppMessage() { return { title: '分享标题', path: '/pages/index/index?id=123' }; }
📌 二、组件生命周期(Component Lifecycle)
1. created()
- 触发时机 :组件实例刚被创建(此时
data
未初始化) - 用途:一般较少使用,可初始化非响应式数据。
2. mounted()
(相当于小程序的 attached
)
-
触发时机:组件挂载到 DOM 后触发
-
用途 :访问 DOM、发送请求。
javascriptmounted() { console.log('组件挂载完成'); this.fetchData(); }
3. updated()
- 触发时机:数据更新导致 DOM 变化后触发
- 用途:监听数据变化后的操作(如更新图表)。
4. beforeDestroy()
(相当于小程序的 detached
)
-
触发时机:组件销毁前触发
-
用途 :清除定时器、取消订阅。
javascriptbeforeDestroy() { console.log('组件即将销毁'); clearInterval(this.timer); }
📌 三、uni-app 特有的生命周期
1. onBackPress(options)
-
触发时机:用户点击返回按钮时触发(仅 App 和 H5 支持)
-
用途 :拦截返回操作(如提示保存数据)。
javascriptonBackPress() { if (this.hasUnsavedChanges) { uni.showModal({ title: '提示', content: '是否放弃修改?', success: (res) => { if (res.confirm) { uni.navigateBack(); } } }); return true; // 阻止默认返回行为 } }
2. onNavigationBarButtonTap(e)
-
触发时机:点击导航栏按钮时触发
-
用途 :自定义导航栏按钮事件。
javascriptonNavigationBarButtonTap(e) { if (e.index === 0) { // 第一个按钮 console.log('点击了分享按钮'); } }
📌 四、总结
常用页面生命周期
生命周期 | 触发时机 | 用途 |
---|---|---|
onLoad |
页面加载 | 获取参数、初始化数据 |
onShow |
页面显示 | 刷新数据 |
onReady |
页面渲染完成 | 操作 DOM |
onHide |
页面隐藏 | 清除定时器 |
onUnload |
页面卸载 | 释放资源 |
onPullDownRefresh |
下拉刷新 | 刷新数据 |
onReachBottom |
滚动到底部 | 加载更多 |
onPageScroll |
页面滚动 | 吸顶效果 |
onShareAppMessage |
点击分享 | 自定义分享 |
常用组件生命周期
生命周期 | 触发时机 | 用途 |
---|---|---|
mounted |
组件挂载 | 请求数据 |
updated |
数据更新 | 更新视图 |
beforeDestroy |
组件销毁 | 清理资源 |
uni-app 特有生命周期
生命周期 | 触发时机 | 用途 |
---|---|---|
onBackPress |
点击返回 | 拦截返回 |
onNavigationBarButtonTap |
点击导航按钮 | 自定义按钮事件 |
🚀 最佳实践
onLoad
+onShow
配合使用onLoad
获取参数,onShow
刷新数据(适用于返回页面时更新数据)。
onReachBottom
实现分页加载- 结合
page
和pageSize
实现上拉加载更多。
- 结合
onBackPress
防止误操作- 在表单页面拦截返回,提示用户保存数据。
beforeDestroy
释放资源- 清除定时器、取消网络请求,避免内存泄漏。
这些生命周期能覆盖 90% 的小程序开发场景,合理使用可以让代码更清晰、性能更优! 🎯