前端知识库【合集】

480 阅读19分钟

JavaScript 篇

一、JavaScript 内置对象

JavaScript 提供了许多内置对象,用于处理数据、执行操作和管理程序逻辑。以下是常见的内置对象及其用途:

1. 全局对象

  • Object:所有对象的基类,提供创建和操作对象的方法。
  • Function:函数的构造函数,用于创建函数对象。
  • Array:用于创建和操作数组。
  • String:用于创建和操作字符串。
  • Number:用于创建和操作数字。
  • Boolean:用于创建和操作布尔值。
  • Date:用于处理日期和时间。
  • Math:提供数学运算的属性和方法。
  • RegExp:用于创建和操作正则表达式。
  • Error:用于处理错误。

2. 其他内置对象

  • JSON:用于解析和序列化 JSON 数据。
  • Promise:用于处理异步操作。
  • MapSet:用于存储键值对和唯一值。
  • Symbol:用于创建唯一的标识符。
  • Proxy:用于定义对象行为的自定义操作。
  • Reflect:提供操作对象的静态方法。

二、浏览器缓存的存储方式与区别

浏览器缓存是浏览器存储数据的一种机制,用于提高页面加载速度和减少服务器请求。以下是常见的浏览器缓存存储方式及其区别:

1. Cookie

  • 特点
    • 存储大小:约 4KB。
    • 生命周期:可设置过期时间,默认关闭浏览器后失效。
    • 作用域:可设置 domainpath,限制作用范围。
    • 自动发送:每次请求都会携带 Cookie。
  • 用途
    • 存储用户会话信息(如登录状态)。
    • 跟踪用户行为。
  • 示例
    document.cookie = "username=John; expires=Thu, 18 Dec 2025 12:00:00 UTC; path=/";
    

2. LocalStorage

  • 特点
    • 存储大小:约 5MB。
    • 生命周期:永久存储,除非手动清除。
    • 作用域:同源页面共享。
    • 不自动发送:不会随请求发送。
  • 用途
    • 存储长期数据(如用户偏好设置)。
  • 示例
    localStorage.setItem('key', 'value');
    const value = localStorage.getItem('key');
    

3. SessionStorage

  • 特点
    • 存储大小:约 5MB。
    • 生命周期:会话结束时清除(关闭浏览器标签页)。
    • 作用域:同一标签页内共享。
    • 不自动发送:不会随请求发送。
  • 用途
    • 存储临时数据(如表单数据)。
  • 示例
    sessionStorage.setItem('key', 'value');
    const value = sessionStorage.getItem('key');
    

4. IndexedDB

  • 特点
    • 存储大小:理论上无限制,通常为 50MB 以上。
    • 生命周期:永久存储,除非手动清除。
    • 作用域:同源页面共享。
    • 不自动发送:不会随请求发送。
  • 用途
    • 存储大量结构化数据(如离线应用数据)。
  • 示例
    const 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 的离线资源)。
  • 示例
    caches.open('my-cache').then(cache => {
      cache.add('/index.html');
    });
    

三、浏览器缓存存储方式的区别

特性CookieLocalStorageSessionStorageIndexedDBCache API
存储大小4KB5MB5MB50MB+50MB+
生命周期可设置过期时间永久存储会话结束清除永久存储永久存储
作用域可设置 domainpath同源页面共享同一标签页内共享同源页面共享同源页面共享
自动发送
用途会话管理、用户跟踪长期数据存储临时数据存储大量结构化数据存储网络请求响应缓存

四、总结

  1. JavaScript 内置对象:包括 ObjectArrayStringPromise 等,用于处理数据和执行操作。
  2. 浏览器缓存存储方式
    • Cookie:适合存储小量会话数据。
    • LocalStorage:适合长期存储数据。
    • SessionStorage:适合临时存储数据。
    • IndexedDB:适合存储大量结构化数据。
    • Cache API:适合缓存网络请求响应。

ES6新特性

一、变量声明

1. letconst

  • let:用于声明块级作用域的变量,解决了 var 的变量提升问题。
    if (true) {
      let x = 10;
    }
    console.log(x); // 报错:x 未定义
    
  • const:用于声明常量,值不可重新赋值。
    const PI = 3.14;
    PI = 3.14159; // 报错:常量不可重新赋值
    

二、箭头函数

2. 箭头函数

  • 简化函数定义,自动绑定 this
    const add = (a, b) => a + b;
    console.log(add(1, 2)); // 3
    
  • this 绑定:箭头函数的 this 指向定义时的上下文,而非调用时的上下文。
    const obj = {
      value: 10,
      getValue: function() {
        setTimeout(() => {
          console.log(this.value); // 10
        }, 1000);
      }
    };
    obj.getValue();
    

三、模板字符串

3. 模板字符串

  • 使用反引号(`)定义字符串,支持多行文本和嵌入表达式。
    const name = 'John';
    const message = `Hello, ${name}!
    Welcome to ES6.`;
    console.log(message);
    

四、解构赋值

4. 解构赋值

  • 从数组或对象中提取值并赋值给变量。
    // 数组解构
    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. 默认参数

  • 为函数参数设置默认值。
    function greet(name = 'Guest') {
      console.log(`Hello, ${name}!`);
    }
    greet(); // Hello, Guest!
    greet('John'); // Hello, John!
    

六、扩展运算符与剩余参数

6. 扩展运算符(...

  • 用于展开数组或对象。
    const 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. 剩余参数(...

  • 用于将剩余的参数收集到一个数组中。
    function sum(...numbers) {
      return numbers.reduce((acc, num) => acc + num, 0);
    }
    console.log(sum(1, 2, 3)); // 6
    

七、对象字面量增强

8. 对象字面量增强

  • 简化对象属性和方法的定义。
    const 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.

  • 提供更清晰的面向对象编程语法。
    class 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. 模块化

  • 使用 importexport 实现模块化。
    // 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

  • 用于处理异步操作,避免回调地狱。
    const fetchData = () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => resolve('Data fetched'), 1000);
      });
    };
    fetchData().then(data => console.log(data)); // Data fetched
    

十一、迭代器与生成器

12. 迭代器(Iterator)

  • 提供统一的遍历接口。
    const arr = [1, 2, 3];
    const iterator = arr[Symbol.iterator]();
    console.log(iterator.next()); // { value: 1, done: false }
    

13. 生成器(Generator)

  • 使用 function* 定义生成器函数,通过 yield 暂停执行。
    function* generateSequence() {
      yield 1;
      yield 2;
      yield 3;
    }
    const generator = generateSequence();
    console.log(generator.next()); // { value: 1, done: false }
    

十二、Set 和 Map

14. Set

  • 存储唯一值的集合。
    const set = new Set([1, 2, 3, 3]);
    console.log(set); // Set { 1, 2, 3 }
    

15. Map

  • 存储键值对的集合,键可以是任意类型。
    const map = new Map();
    map.set('name', 'John');
    console.log(map.get('name')); // John
    

十三、Symbol

16. Symbol

  • 创建唯一的标识符。
    const id = Symbol('id');
    const obj = { [id]: 123 };
    console.log(obj[id]); // 123
    

十四、Proxy 和 Reflect

17. Proxy

  • 用于定义对象行为的自定义操作。
    const 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

  • 提供操作对象的静态方法。
    const obj = { name: 'John' };
    console.log(Reflect.get(obj, 'name')); // John
    

十五、其他特性

19. for...of 循环

  • 用于遍历可迭代对象(如数组、字符串、Set、Map)。
    const arr = [1, 2, 3];
    for (const num of arr) {
      console.log(num); // 1, 2, 3
    }
    

20. Array.fromArray.of

  • Array.from:将类数组对象或可迭代对象转换为数组。
    const arrayLike = { 0: 'a', 1: 'b', length: 2 };
    const arr = Array.from(arrayLike); // ['a', 'b']
    
  • Array.of:将一组值转换为数组。
    const arr = Array.of(1, 2, 3); // [1, 2, 3]
    

总结

ES6 引入了许多强大的新特性,如 let/const、箭头函数、模板字符串、解构赋值、类、模块化、Promise 等,极大地提升了 JavaScript 的开发效率和代码可读性。 $attrs 是 Vue 提供的一个特殊属性,用于访问父组件传递给子组件的非 Prop 属性(即未被组件显式声明为 props 的属性)。这些属性可以是 HTML 属性(如 classstyle 等)或自定义属性。


vue相关

1. $attrs 的作用

  • 访问非 Prop 属性:父组件传递给子组件的属性,如果子组件没有在 props 中声明,这些属性会被收集到 $attrs 中。
  • 透传属性:可以将 $attrs 传递给子组件的子组件,实现属性的透传。

2. $attrs 的使用场景

  • 透传属性:当子组件需要将父组件传递的属性继续传递给它的子组件时,可以使用 $attrs
  • 动态绑定属性:当子组件需要动态绑定父组件传递的属性时,可以使用 $attrs
  • 处理原生 HTML 属性:当子组件需要处理父组件传递的原生 HTML 属性(如 classstyle 等)时,可以使用 $attrs

3. $attrs 的特性

  • 自动收集:所有未被 props 声明的属性都会被收集到 $attrs 中。
  • 不包含 classstyle:在 Vue 2 中,$attrs 不包含 classstyle,它们会被单独处理。在 Vue 3 中,$attrs 包含 classstyle
  • 透传:可以通过 v-bind="$attrs"$attrs 传递给子组件的子组件。

4. 示例代码

Vue 2 示例
<!-- 父组件 -->
<template>
  <ChildComponent class="parent-class" style="color: red" data-custom="123" />
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  }
};
</script>
<!-- 子组件 ChildComponent -->
<template>
  <div>
    <!-- 使用 $attrs 绑定属性 -->
    <div v-bind="$attrs">子组件内容</div>
    <p>非 Prop 属性: {{ $attrs }}</p>
  </div>
</template>

<script>
export default {
  // 未声明 props
};
</script>

输出结果

  • $attrs 包含 data-custom="123",但不包含 classstyle
  • div 元素会继承 data-custom="123" 属性。
Vue 3 示例

在 Vue 3 中,$attrs 包含 classstyle

<!-- 父组件 -->
<template>
  <ChildComponent class="parent-class" style="color: red" data-custom="123" />
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  }
};
</script>
<!-- 子组件 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 元素会继承 classstyledata-custom 属性。

5. inheritAttrs 选项

  • 作用:控制是否将 $attrs 中的属性自动绑定到组件的根元素上。
  • 默认值true,即自动绑定。
  • 设置为 false:禁止自动绑定,可以手动通过 v-bind="$attrs" 绑定到指定元素。
示例代码
<!-- 子组件 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

示例代码
<!-- 子组件 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 包含 classstyle,并且可以使用 useAttrs 访问。

通过 $attrs,可以更灵活地处理父组件传递的属性,尤其是在开发高阶组件或封装通用组件时非常有用。 在 Vue 中,获取 DOM 元素的常用钩子函数是 mountedmounted 是 Vue 生命周期钩子之一,表示组件已经被挂载到 DOM 中,此时可以安全地访问和操作 DOM 元素。

1. mounted 钩子函数

  • 作用:在组件挂载到 DOM 后调用,此时可以访问 DOM 元素。
  • 使用场景:获取 DOM 元素、初始化第三方库(如图表库、地图库)、绑定事件监听器等。
示例代码:
<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。
示例代码:
<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。
示例代码:
<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 更新前执行某些操作。
示例代码:
<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 元素或调用子组件的方法。
示例代码:
<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秒内又被触发,则重新计时。

特点

  • 适用于频繁触发但只需处理最后一次的场景
  • 比如搜索框输入、窗口大小调整

实现代码

function debounce(fn, delay) {
  let timer = null;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, delay);
  };
}

节流(Throttle)

概念:规定在一个单位时间内,只能触发一次函数执行,如果这个单位时间内触发多次,只有一次生效。

特点

  • 适用于频繁触发但需要均匀执行的场景
  • 比如滚动事件、按钮频繁点击

实现代码

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)

浅拷贝

概念:只复制对象的第一层属性,对于引用类型的属性,复制的是内存地址。

实现方式

  1. Object.assign()
  2. 展开运算符 ...
  3. Array.prototype.slice()
  4. Array.prototype.concat()

示例

const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };

shallowCopy.b.c = 3; // 会影响原对象
console.log(obj.b.c); // 输出 3

深拷贝

概念:完全复制一个对象,包括对象内部的嵌套对象,新对象与原对象完全独立。

实现方式

  1. JSON.parse(JSON.stringify(obj)) (有局限性)
  2. 递归实现
  3. 使用第三方库如lodash的_.cloneDeep()

递归实现示例

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;
}

两者区别

特性浅拷贝深拷贝
复制层级仅第一层所有层级
引用类型处理共享内存地址创建新内存空间
性能较高较低
适用场景简单对象复制需要完全独立的对象

注意事项

  1. JSON方法深拷贝的局限性:

    • 不能处理函数、Symbol、undefined
    • 不能处理循环引用
    • 会丢失对象的constructor
  2. 循环引用处理:

    • 使用WeakMap存储已拷贝对象
    • 遇到已拷贝对象直接返回
  3. 特殊对象处理:

    • Date、RegExp等需要特殊处理
    • DOM节点通常不适合深拷贝

理解这些概念对于编写高效、无副作用的JavaScript代码非常重要,特别是在处理复杂对象和频繁事件时。

小程序高频面试题

基础概念

  1. 什么是小程序?它与传统App有什么区别?

    • 小程序是一种不需要下载安装即可使用的应用,它实现了应用"触手可及"的梦想
    • 区别:开发成本低、无需安装、即用即走、依赖平台生态、功能受限
  2. 小程序的优势和劣势是什么?

    • 优势:开发成本低、用户获取成本低、跨平台、即用即走
    • 劣势:功能受限、依赖平台政策、留存率较低
  3. 小程序的生命周期有哪些?

    • onLoad: 页面加载时触发
    • onShow: 页面显示/切入前台时触发
    • onReady: 页面初次渲染完成时触发
    • onHide: 页面隐藏/切入后台时触发
    • onUnload: 页面卸载时触发

开发相关

  1. 小程序的双线程模型是什么?

    • 渲染层(WebView线程): 负责页面渲染
    • 逻辑层(JavaScript线程): 负责业务逻辑处理
    • 两者通过Native进行通信,提高安全性但增加了通信成本
  2. 小程序的页面路由有哪些方式?有什么区别?

    • wx.navigateTo: 保留当前页面,跳转到新页面
    • wx.redirectTo: 关闭当前页面,跳转到新页面
    • wx.reLaunch: 关闭所有页面,打开新页面
    • wx.switchTab: 跳转到tabBar页面
    • wx.navigateBack: 返回上一页面
  3. 小程序如何实现数据绑定和事件绑定?

    • 数据绑定: 使用{{}}语法
    • 事件绑定: bind/catch + 事件名,如bindtapcatchtap
  4. 小程序如何实现组件化开发?

    • 使用Component构造器创建自定义组件
    • 通过properties定义组件属性
    • 通过methods定义组件方法
    • 通过slot实现插槽功能

性能优化

  1. 小程序性能优化有哪些方法?

    • 减少setData的数据量
    • 合理使用onPageScroll
    • 图片懒加载
    • 使用分包加载
    • 合理使用缓存
    • 避免频繁的页面跳转
  2. 小程序的分包加载是什么?如何实现?

    • 将小程序分成多个包,按需加载
    • 配置app.json中的subPackages字段
    • 主包包含核心页面和公共资源,分包包含特定功能模块
  3. 如何优化小程序的启动速度?

    • 减少主包体积
    • 延迟非必要请求
    • 使用缓存策略
    • 优化代码执行效率
    • 使用按需注入和用时注入

网络与存储

  1. 小程序的网络请求有哪些限制?

    • 必须使用HTTPS
    • 需要配置合法域名
    • 并发请求数有限制
    • 请求超时时间有限制
  2. 小程序的数据存储方式有哪些?

    • 本地缓存: wx.setStorage/wx.getStorage
    • 数据库: 云开发数据库
    • 文件存储: wx.saveFile/wx.getFileSystemManager
    • 全局变量: getApp().globalData
  3. 如何实现小程序的上传下载功能?

    • 上传: wx.uploadFile
    • 下载: wx.downloadFile
    • 需要配置uploadFile和downloadFile合法域名

跨平台开发

  1. 如何实现小程序的多端适配?

    • 使用uni-app、Taro等跨平台框架
    • 条件编译处理平台差异
    • 抽象公共业务逻辑
    • 针对不同平台优化UI
  2. 小程序与H5如何通信?

    • 通过URL参数传递数据
    • 使用web-view组件的postMessage
    • 通过本地存储共享数据

安全与权限

  1. 小程序如何保证用户数据安全?

    • 使用HTTPS传输
    • 敏感数据加密存储
    • 合理设置权限范围
    • 使用微信提供的安全接口
  2. 小程序如何获取用户授权?

    • 使用wx.authorize提前获取授权
    • 使用button组件的open-type触发授权
    • 使用wx.getSetting查询授权状态

实际开发问题

  1. 如何处理小程序的兼容性问题?

    • 检查基础库版本
    • 使用条件编译
    • 提供降级方案
    • 测试不同设备和系统版本
  2. 小程序如何实现分享功能?

    • 配置onShareAppMessage
    • 设置分享标题、路径和图片
    • 自定义button的open-type="share"
  3. 如何调试小程序?

    • 使用开发者工具的调试功能
    • 使用console.log输出日志
    • 使用wx.getLogManager管理日志
    • 使用真机调试功能

高级话题

  1. 小程序如何与原生应用交互?

    • 使用开放能力如小程序跳转App
    • 通过URL Scheme或Universal Link
    • 使用插件功能
  2. 小程序的插件开发流程是怎样的?

    • 创建插件项目
    • 开发插件功能
    • 上传发布插件
    • 在小程序中引用插件
  3. 如何实现小程序的国际化?

    • 维护多语言资源文件
    • 根据系统语言动态切换
    • 使用第三方库如i18n
    • 考虑RTL语言布局
  4. 小程序如何实现动画效果?

    • 使用CSS动画
    • 使用wx.createAnimation API
    • 使用WXS响应事件
    • 使用canvas绘制复杂动画
  5. 小程序云开发有哪些优势?

    • 无需搭建服务器
    • 集成数据库、存储和云函数
    • 简化开发流程
    • 提供丰富的后端能力

在小程序中,将路由参数传递到组件内部接收,可以通过以下几种方式实现:


1. 通过 properties 接收参数(推荐)

在页面中通过 properties 将路由参数传递给组件,组件内部通过 properties 接收。

步骤:
  1. 页面获取路由参数
    在页面的 onLoad 生命周期中获取路由参数:

    Page({
      data: {
        queryParams: {} // 存储路由参数
      },
      onLoad(options) {
        this.setData({
          queryParams: options // 接收路由参数
        });
      }
    });
    
  2. 页面向组件传递参数
    在页面的 WXML 中,通过 properties 将参数传递给组件:

    <my-component queryParams="{{queryParams}}"></my-component>
    
  3. 组件内部接收参数
    在组件的 properties 中定义接收参数:

    Component({
      properties: {
        queryParams: {
          type: Object,
          value: {}
        }
      },
      attached() {
        console.log(this.data.queryParams); // 获取传递的参数
      }
    });
    

2. 通过 storage 传递参数(适用于复杂数据)

如果参数较大或需要跨页面共享,可以使用 wx.setStorage 存储,组件内部通过 wx.getStorage 获取。

步骤:
  1. 页面存储参数

    Page({
      onLoad(options) {
        wx.setStorageSync('queryParams', options); // 存储到本地缓存
      }
    });
    
  2. 组件获取参数

    Component({
      attached() {
        const queryParams = wx.getStorageSync('queryParams');
        console.log(queryParams); // 获取存储的参数
      }
    });
    

3. 通过 eventBus 或全局变量传递(适用于跨组件通信)

如果多个组件需要共享参数,可以使用全局变量或事件总线(EventBus)方式传递。

步骤:
  1. app.js 定义全局变量

    App({
      globalData: {
        queryParams: null
      }
    });
    
  2. 页面存储参数

    const app = getApp();
    Page({
      onLoad(options) {
        app.globalData.queryParams = options; // 存入全局变量
      }
    });
    
  3. 组件获取参数

    const app = getApp();
    Component({
      attached() {
        console.log(app.globalData.queryParams); // 获取全局参数
      }
    });
    

4. 通过 observers 监听参数变化(动态更新)

如果参数可能动态变化,可以使用 observers 监听 properties 变化。

步骤:
Component({
  properties: {
    queryParams: Object
  },
  observers: {
    'queryParams': function(newVal) {
      console.log('参数变化:', newVal); // 监听参数变化
    }
  }
});

总结

方式适用场景优点缺点
properties父子组件传参直接、清晰需要逐层传递
storage跨页面共享数据数据持久化需要手动清理
globalData全局共享数据简单易用非响应式
observers监听参数变化响应式更新仅限组件内部

推荐方式:

  • 简单传参 → 使用 properties(最常用)
  • 复杂/跨页面数据 → 使用 storageglobalData
  • 动态监听参数 → 使用 observers

这样,你就可以在组件内部灵活接收路由参数了! 🚀 在 uni-app 开发小程序时,会涉及到 页面生命周期组件生命周期,同时由于 uni-app 的跨平台特性,部分生命周期与原生小程序有所不同。以下是常用的生命周期及其使用场景:


📌 一、页面生命周期(Page Lifecycle)

1. onInit(仅支付宝小程序)

  • 触发时机:页面初始化时触发(早于 onLoad
  • 用途:支付宝小程序专用,可用于提前初始化数据。

2. onLoad(options)

  • 触发时机:页面加载时触发(仅触发一次)
  • 参数options 可获取路由参数(如 pages/index/index?id=123 中的 id
  • 用途:获取页面参数、初始化数据、发送请求。
    onLoad(options) {
      console.log('页面参数:', options.id); // 123
      this.loadData();
    }
    

3. onShow()

  • 触发时机:页面显示/切入前台时触发(每次进入页面都会触发)
  • 用途:刷新数据、监听页面显示(如从后台返回时)。
    onShow() {
      console.log('页面显示');
      this.refreshData();
    }
    

4. onReady()

  • 触发时机:页面初次渲染完成(仅触发一次)
  • 用途:操作 DOM、初始化地图/图表等需要渲染完成才能执行的逻辑。
    onReady() {
      console.log('页面渲染完成');
      this.initMap();
    }
    

5. onHide()

  • 触发时机:页面隐藏/切入后台时触发(如跳转到其他页面或返回)
  • 用途:清除定时器、暂停动画等。
    onHide() {
      console.log('页面隐藏');
      clearInterval(this.timer);
    }
    

6. onUnload()

  • 触发时机:页面卸载时(如 wx.redirectTo 或关闭页面)
  • 用途:释放资源、取消事件监听。
    onUnload() {
      console.log('页面卸载');
      this.removeEventListeners();
    }
    

7. onPullDownRefresh()

  • 触发时机:用户下拉刷新时触发
  • 用途:实现下拉刷新逻辑。
    onPullDownRefresh() {
      console.log('下拉刷新');
      this.refreshData().then(() => {
        uni.stopPullDownRefresh(); // 停止刷新动画
      });
    }
    

8. onReachBottom()

  • 触发时机:页面滚动到底部时触发
  • 用途:实现上拉加载更多(分页)。
    onReachBottom() {
      console.log('触底加载');
      this.loadMoreData();
    }
    

9. onPageScroll(e)

  • 触发时机:页面滚动时触发
  • 参数e.scrollTop 可获取滚动距离
  • 用途:监听滚动事件(如吸顶效果)。
    onPageScroll(e) {
      console.log('滚动距离:', e.scrollTop);
      if (e.scrollTop > 100) {
        this.setData({ showBackTop: true });
      }
    }
    

10. onShareAppMessage()

  • 触发时机:用户点击右上角分享时触发
  • 用途:自定义分享内容。
    onShareAppMessage() {
      return {
        title: '分享标题',
        path: '/pages/index/index?id=123'
      };
    }
    

📌 二、组件生命周期(Component Lifecycle)

1. created()

  • 触发时机:组件实例刚被创建(此时 data 未初始化)
  • 用途:一般较少使用,可初始化非响应式数据。

2. mounted()(相当于小程序的 attached

  • 触发时机:组件挂载到 DOM 后触发
  • 用途:访问 DOM、发送请求。
    mounted() {
      console.log('组件挂载完成');
      this.fetchData();
    }
    

3. updated()

  • 触发时机:数据更新导致 DOM 变化后触发
  • 用途:监听数据变化后的操作(如更新图表)。

4. beforeDestroy()(相当于小程序的 detached

  • 触发时机:组件销毁前触发
  • 用途:清除定时器、取消订阅。
    beforeDestroy() {
      console.log('组件即将销毁');
      clearInterval(this.timer);
    }
    

📌 三、uni-app 特有的生命周期

1. onBackPress(options)

  • 触发时机:用户点击返回按钮时触发(仅 App 和 H5 支持)
  • 用途:拦截返回操作(如提示保存数据)。
    onBackPress() {
      if (this.hasUnsavedChanges) {
        uni.showModal({
          title: '提示',
          content: '是否放弃修改?',
          success: (res) => {
            if (res.confirm) {
              uni.navigateBack();
            }
          }
        });
        return true; // 阻止默认返回行为
      }
    }
    

2. onNavigationBarButtonTap(e)

  • 触发时机:点击导航栏按钮时触发
  • 用途:自定义导航栏按钮事件。
    onNavigationBarButtonTap(e) {
      if (e.index === 0) { // 第一个按钮
        console.log('点击了分享按钮');
      }
    }
    

📌 四、总结

常用页面生命周期

生命周期触发时机用途
onLoad页面加载获取参数、初始化数据
onShow页面显示刷新数据
onReady页面渲染完成操作 DOM
onHide页面隐藏清除定时器
onUnload页面卸载释放资源
onPullDownRefresh下拉刷新刷新数据
onReachBottom滚动到底部加载更多
onPageScroll页面滚动吸顶效果
onShareAppMessage点击分享自定义分享

常用组件生命周期

生命周期触发时机用途
mounted组件挂载请求数据
updated数据更新更新视图
beforeDestroy组件销毁清理资源

uni-app 特有生命周期

生命周期触发时机用途
onBackPress点击返回拦截返回
onNavigationBarButtonTap点击导航按钮自定义按钮事件

🚀 最佳实践

  1. onLoad + onShow 配合使用
    • onLoad 获取参数,onShow 刷新数据(适用于返回页面时更新数据)。
  2. onReachBottom 实现分页加载
    • 结合 pagepageSize 实现上拉加载更多。
  3. onBackPress 防止误操作
    • 在表单页面拦截返回,提示用户保存数据。
  4. beforeDestroy 释放资源
    • 清除定时器、取消网络请求,避免内存泄漏。

这些生命周期能覆盖 90% 的小程序开发场景,合理使用可以让代码更清晰、性能更优! 🎯