开发 -> 开发管理 -> 开发设置,获取所需的 AppId、AppSecret
稳定版本,常规安装,微信扫码登录
模拟器 机型 -> 显示比例 -> 自适应
切换主题:设置 -> 外观设置 -> 浅色
文件保存:设置-> 编辑器设置 -> 修改文件保存
允许非 HTTPS 请求:设置 -> 项目设置 -> 不校验合法域名
安装 vscode 插件: 设置 -> 编辑器设置 -> 更多编辑器设置 -> Font Size
{
// 微信小程序的应用ID。你需要在微信开放平台注册小程序,然后获取该ID。
"appid": "wx2ad70a9c3b41c9a5",
// 编译类型,此处指定为“miniprogram”意味着这是一个微信小程序项目。
"compileType": "miniprogram",
// 使用的微信小程序库的版本。
"libVersion": "3.1.2",
"packOptions": {
// 指定哪些文件或者文件夹应该被打包工具忽略。
"ignore": [],
// 指定哪些文件或者文件夹应该被打包工具包括,即使它们被忽略规则所排除。
"include": []
},
"setting": {
// 如果为true,则会支持cover-view相关的设置。cover-view是微信小程序中的一个组件,可以覆盖在其他组件之上。
"coverView": true,
// 如果为true,则启用ECMAScript 6语法支持。
"es6": true,
// 如果为true,则启用PostCSS,它是一个CSS处理工具。
"postcss": true,
// 如果为true,则会压缩JavaScript代码。
"minified": true,
// 如果为true,会增强某些功能或者对一些特性进行优化。
"enhance": true,
// 如果为true,在wxml面板中会显示ShadowRoot。这与Web组件的Shadow DOM有关。
"showShadowRootInWxmlPanel": true,
// 设置与NPM包关系的列表。
"packNpmRelationList": [],
"babelSetting": {
// Babel是一个JavaScript编译器,这里可以指定哪些文件或者文件夹不应该被Babel处理。
"ignore": [],
// 可以禁用某些Babel插件。
"disablePlugins": [],
// Babel的输出路径。
"outputPath": ""
}
},
// 设置条件编译的相关参数。
"condition": {},
"editorSetting": {
// 设置编辑器的缩进模式。此处为“insertSpaces”,表示使用空格进行缩进。
"tabIndent": "insertSpaces",
// 设置编辑器的缩进大小。此处为2,表示使用两个空格进行缩进。
"tabSize": 2
}
}
project.private.config.json
{
"description": "项目私有配置文件", // 说明:这是一个用于描述项目的私有配置文件。
"projectname": "miniclient", // 项目名称:这里的项目名称被设定为"miniclient"。
"setting": {
"compileHotReLoad": true, // 编译热重载设置:当设置为true时,项目在编译时会自动加载最新的更改,而无需每次更改后都重新编译。
"urlCheck": false // URL检查设置:当设置为false时,系统不会执行URL的合法性检查。
}
}
{
"pages": [
"pages/index/index",
"pages/interview/interview",
"pages/lesson/lesson",
"pages/profile/profile"
]
}
app.json
{
"pages": [
"pages/index/index", // 定义首页路径
"pages/interview/interview", // 定义面试题页面的路径
"pages/lesson/lesson", // 定义课程中心页面的路径
"pages/profile/profile" // 定义个人信息或个人中心页面的路径
],
"tabBar": {
"list": [
{
"pagePath": "pages/index/index", // 指定页面路径
"text": "首页", // 页签的文本
"iconPath": "images/home.png", // 页签的图标路径
"selectedIconPath": "images/home-selected.png" // 选中时的页签图标路径
},
{
"pagePath": "pages/interview/interview",
"text": "面试题",
"iconPath": "images/interview.png",
"selectedIconPath": "images/interview-selected.png"
},
{
"pagePath": "pages/lesson/lesson",
"text": "课程中心",
"iconPath": "images/lesson.png",
"selectedIconPath": "images/lesson-selected.png"
},
{
"pagePath": "pages/profile/profile",
"text": "我",
"iconPath": "images/profile.png",
"selectedIconPath": "images/profile-selected.png"
}
]
}
}
这个配置文件主要描述了小程序的页面路径及其底部的页签(tabBar)配置。
pages
字段列出了小程序中所有的页面路径,
而tabBar
字段则用于配置显示在小程序底部的页签,并为每个页签提供了正常与选中状态的图标。
在微信小程序开发中,添加编译模式可以让你快速预览或切换到某个特定的页面或场景,避免了每次都需要从首页进入。这在开发过程中尤其有用,尤其是当你的小程序有很多页面或者需要模拟特定的场景时。
以下是如何在微信开发者工具中添加编译模式的步骤:
打开微信开发者工具:首先确保你已经安装了微信开发者工具,并打开你的项目。
进入编译模式配置:
添加新的编译模式:
保存并使用编译模式:
管理编译模式:
这样,通过添加不同的编译模式,你可以更方便地在开发过程中预览或切换到不同的页面或场景,提高开发效率。
pages\profile\profile.wxml
<view class="profile-login">
<view class="profile-login-container">
<image class="profile-avatar" src="{{avatarUrl}}"></image>
<view class="profile-info">
<text class="login-prompt-text">未登录</text>
<button class="login-status-btn" bind:tap="loginUser">
点我快捷登录
</button>
</view>
</view>
</view>
pages\profile\profile.js
// 定义一个默认的头像URL常量
const defaultAvatarUrl = "/images/avatar.png";
// 定义页面对象
Page({
// 页面的初始数据
data: {
// 使用默认头像URL初始化avatarUrl
avatarUrl: defaultAvatarUrl,
},
});
const defaultAvatarUrl = "/images/avatar.png";
defaultAvatarUrl
,并赋予其一个字符串值"/images/avatar.png"
。这个字符串是一个相对路径,指向小程序项目中的一个默认头像图片。Page({ ... });
Page
是微信小程序的一个内置函数,用于定义一个页面。当你浏览到这个页面时,微信小程序会执行这个Page
函数,从而创建并显示页面。data: { ... },
Page
对象中,data
对象是一个特殊的对象。它定义了页面的初始数据。data
对象中的数据来渲染页面。例如,你可以在模板中使用{{avatarUrl}}
来引用这个avatarUrl
数据。avatarUrl: defaultAvatarUrl,
data
对象中定义了一个数据属性avatarUrl
,并将其初始化为defaultAvatarUrl
的值,即"/images/avatar.png"
。avatarUrl
的默认值会是"/images/avatar.png"
。如果你在 WXML 模板中有一个<image>
标签,如<image src="{{avatarUrl}}" />
,它会默认显示该默认头像。总结:这段代码定义了一个微信小程序的页面,该页面有一个初始数据avatarUrl
,其值默认为"/images/avatar.png"
。这很有可能用于显示用户的头像,而当用户没有上传头像时,程序会使用这个默认头像。
pages\profile\profile.wxss
.profile-login {
background: #1296db;
padding: 50rpx;
}
.profile-login-container {
height: 250rpx;
color: #fff;
display: flex;
align-items: center;
}
.profile-avatar {
width: 150rpx;
height: 150rpx;
border-radius: 50%;
}
.profile-info {
margin-left: 25rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.login-status-btn {
border-radius: 10rpx;
text-align: center;
margin-top: 30rpx;
line-height: 70rpx;
}
pages\profile\profile.wxml
<view class="profile-login">
<view class="profile-login-container">
<image class="profile-avatar" src="{{avatarUrl}}"></image>
+ <view class="profile-info" bind:tap="tapView">
<text class="login-prompt-text">未登录</text>
+ <button class="login-status-btn" bind:tap="tapButton">点我快捷登录</button>
</view>
</view>
</view>
pages\profile\profile.js
const defaultAvatarUrl = "/images/avatar.png";
Page({
data: {
avatarUrl: defaultAvatarUrl,
},
+ tapView() {
+ console.log("tapView");
+ },
+ tapButton() {
+ console.log("tapButton");
+ },
});
pages\profile\profile.wxml
<view class="profile-login">
<view class="profile-login-container">
<image class="profile-avatar" src="{{avatarUrl}}"></image>
<view class="profile-info">
<text class="login-prompt-text">点我快捷登录</text>
+ <button class="login-status-btn" bind:tap="loginUser">未登录</button>
</view>
</view>
</view>
pages\profile\profile.js
import { storeToken } from "../../utils/token";
import { get } from "../../utils/request";
const appInstance = getApp();
Page({
data: {
avatarUrl: appInstance.globalData.defaultAvatarUrl,
},
async loginUser() {
try {
const { code } = await new Promise((resolve, reject) => {
wx.login({
success: resolve,
fail: reject,
});
});
if (code) {
const {
data: { token, nickname, avatar },
} = await get("/login", {
data: { code },
});
storeToken(token);
}
} catch (error) {
wx.showToast({
title: error.message || "Login failed.",
icon: "error",
duration: 2000,
});
}
},
});
app.js
App({
globalData: {
defaultAvatarUrl: "/images/avatar.png",
baseURL: "http://localhost:3000",
},
});
App
是微信小程序提供的函数,用于定义整个小程序的生命周期函数和全局数据。当调用这个函数时,微信会基于提供的对象创建一个全新的小程序应用实例。globalData
是 App
对象的一个属性,它用于定义全局的数据,这些数据可以在小程序的任何页面中被访问。utils\token.js
export function fetchStoredToken() {
return wx.getStorageSync("authToken");
}
export function storeToken(token) {
wx.setStorageSync("authToken", token);
}
export function removeStoredToken() {
wx.removeStorageSync("authToken");
}
utils\request.js
import { fetchStoredToken, removeStoredToken } from "./token";
const appInstance = getApp();
function httpRequest(options) {
const token = fetchStoredToken();
if (token) {
options.header = {
...options.header,
Authorization: `Bearer ${token}`,
};
}
return new Promise((resolve, reject) => {
wx.request({
...options,
url: `${appInstance.globalData.baseURL}${options.url}`,
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else if (res.statusCode === 401) {
removeStoredToken();
wx.showModal({
title: "认证失败",
content: "请先登录",
showCancel: false,
success() {
wx.navigateTo({
url: "/pages/profile/profile",
});
},
});
} else {
reject(new Error(`Request failed with status ${res.statusCode}`));
}
},
fail: (err) => {
reject(err);
},
});
});
}
export function get(url, options = {}) {
return httpRequest({
url,
...options,
});
}
export function post(url, options = {}) {
return httpRequest({
url,
method: "POST",
...options,
});
}
export default httpRequest;
pages\profile\profile.js
+import {
+ storeToken,
+ fetchStoredToken,
+ removeStoredToken,
+} from "../../utils/token";
import { get } from "../../utils/request";
const appInstance = getApp();
Page({
data: {
avatarUrl: appInstance.globalData.defaultAvatarUrl,
+ nickname: "",
+ avatar: "",
+ isLogin: false,
},
+ onLoad() {
+ if (fetchStoredToken()) {
+ const { nickname, avatar } = wx.getStorageSync("user") || {};
+ this.setData({
+ nickname,
+ avatar,
+ isLogin: true,
+ });
+ }
+ },
+ logout() {
+ removeStoredToken();
+ wx.reLaunch({
+ url: "/pages/profile/profile",
+ });
+ },
async loginUser() {
try {
const { code } = await new Promise((resolve, reject) => {
wx.login({
success: resolve,
fail: reject,
});
});
if (code) {
const {
data: { token, nickname, avatar },
} = await get("/login", {
data: { code },
});
storeToken(token);
+ if (nickname) {
+ this.setData({
+ avatar,
+ nickname,
+ isLogin: true,
+ });
+ wx.setStorageSync("user", { nickname, avatar });
+ wx.showToast({ title: `登录成功`, duration: 1000 });
+ } else {
+ const confirm = await wx.showModal({
+ title: "登录成功,您还未完善信息",
+ content: "去完善信息吧",
+ confirmText: "去完善",
+ });
+ if (confirm) {
+ return wx.navigateTo({ url: "/pages/improve/improve" });
+ }
+ }
}
} catch (error) {
wx.showToast({
title: error.message || "Login failed.",
icon: "error",
duration: 2000,
});
}
},
});
pages\profile\profile.wxml
<view class="profile-login">
<view class="profile-login-container">
+ <image class="profile-avatar" src="{{isLogin? avatar: avatarUrl}}"></image>
+ <view class="profile-info" wx:if="{{isLogin}}">
+ <text>{{nickname}}</text>
+ </view>
+ <view class="profile-info" wx:else>
<text class="login-prompt-text">点我快捷登录</text>
<button class="login-status-btn" bind:tap="loginUser">未登录</button>
</view>
</view>
</view>
+<button bindtap="logout">退出</button>
pages\improve\improve.wxml
<form bindsubmit="submitUserInfo">
<button
class="avatar-wrapper"
open-type="chooseAvatar"
bind:chooseavatar="onChooseAvatar"
>
<image class="avatar" src="{{avatarUrl}}"></image>
</button>
<input name="nickname" type="nickname" placeholder="请输入昵称" />
<button form-type="submit">提交</button>
</form>
pages\improve\improve.wxss
.avatar-wrapper {
margin: 50rpx auto;
width: 200rpx;
height: 200rpx;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
}
.avatar {
width: 200rpx;
height: 200rpx;
}
pages\improve\improve.js
import { fetchStoredToken } from "../../utils/token";
const app = getApp();
Page({
data: {
avatarUrl: app.globalData.defaultAvatarUrl,
},
onChooseAvatar(event) {
const { avatarUrl } = event.detail;
this.setData({
avatarUrl,
});
},
submitUserInfo(event) {
const token = fetchStoredToken();
const { baseURL } = app.globalData;
if (!token) {
wx.showToast({
title: "未授权",
icon: "error",
});
return;
}
wx.uploadFile({
filePath: this.data.avatarUrl,
header: {
Authorization: `Bearer ${token}`,
},
name: "avatar",
url: `${baseURL}/upload`,
formData: {
nickname: event.detail.value.nickname,
},
fail: (err) => {
console.error("上传失败:", err);
wx.showToast({
title: "上传失败",
icon: "error",
});
},
success: (res) => {
try {
const { nickname, avatar } = JSON.parse(res.data);
wx.setStorageSync("user", { nickname, avatar });
wx.switchTab({
url: "/pages/profile/profile",
success() {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
currentPage.onLoad();
},
});
} catch (error) {
console.error("解析响应失败:", error);
wx.showToast({
title: "解析响应失败",
icon: "error",
});
}
},
});
},
});
工具 => 构建 npm
npm i @vant/weapp -S --production
pages\profile\profile.json
{
"usingComponents": {
"van-cell": "@vant/weapp/cell/index",
"van-cell-group": "@vant/weapp/cell-group/index"
}
}
pages\profile\profile.wxml
<view class="profile-login">
<view class="profile-login-container">
<image class="profile-avatar" src="{{isLogin? avatar: avatarUrl}}"></image>
<view class="profile-info" wx:if="{{isLogin}}">
<text>{{nickname}}</text>
</view>
<view class="profile-info" wx:else>
<text class="login-prompt-text">未登录</text>
<button class="login-status-btn" bind:tap="loginUser">点我快捷登录</button>
</view>
</view>
</view>
+<van-cell-group inset wx:if="{{isLogin}}" >
+ <van-cell title="退出" bind:click="logout" is-link/>
+ <van-cell title="收藏" is-link />
+</van-cell-group>
app.json
{
"pages": [
"pages/index/index",
"pages/interview/interview",
"pages/lesson/lesson",
"pages/profile/profile",
"pages/improve/improve"
],
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "images/home.png",
"selectedIconPath": "images/home-selected.png"
},
{
"pagePath": "pages/interview/interview",
"text": "面试题",
"iconPath": "images/interview.png",
"selectedIconPath": "images/interview-selected.png"
},
{
"pagePath": "pages/lesson/lesson",
"text": "课程中心",
"iconPath": "images/lesson.png",
"selectedIconPath": "images/lesson-selected.png"
},
{
"pagePath": "pages/profile/profile",
"text": "我",
"iconPath": "images/profile.png",
"selectedIconPath": "images/profile-selected.png"
}
]
},
+ "usingComponents": {
+ "van-button": "@vant/weapp/button/index"
+ }
}
pages\profile\profile.wxml
<view class="profile-login">
<view class="profile-login-container">
<image class="profile-avatar" src="{{isLogin? avatar: avatarUrl}}"></image>
<view class="profile-info" wx:if="{{isLogin}}">
<text>{{nickname}}</text>
</view>
<view class="profile-info" wx:else>
<text class="login-prompt-text">未登录</text>
<button class="login-status-btn" bind:tap="loginUser">点我快捷登录</button>
</view>
</view>
</view>
<van-cell-group inset wx:if="{{isLogin}}">
<van-cell title="退出" bind:click="logout" is-link />
<van-cell title="收藏" is-link />
</van-cell-group>
+<van-button type="info" block open-type="share">分享前端面试</van-button>
pages\profile\profile.js
import {
storeToken,
fetchStoredToken,
removeStoredToken,
} from "../../utils/token";
import { get } from "../../utils/request";
const appInstance = getApp();
Page({
data: {
avatarUrl: appInstance.globalData.defaultAvatarUrl,
nickname: "",
avatar: "",
isLogin: false,
},
onLoad() {
+ wx.showShareMenu({
+ withShareTicket: true,
+ menus: ["shareAppMessage", "shareTimeline"],
+ });
if (fetchStoredToken()) {
const { nickname, avatar } = wx.getStorageSync("user") || {};
this.setData({
nickname,
avatar,
isLogin: true,
});
}
},
+ onShareAppMessage() {
+ return {
+ title: "分享小程序",
+ path: "/pages/index/index",
+ success: function (res) {
+ console.log("分享成功", res);
+ },
+ fail: function (res) {
+ console.log("分享失败", res);
+ },
+ };
+ },
+ onShareTimeline() {
+ return {
+ title: "分享朋友圈"
+ };
+ },
logout() {
removeStoredToken();
wx.reLaunch({
url: "/pages/profile/profile",
});
},
async loginUser() {
try {
const { code } = await new Promise((resolve, reject) => {
wx.login({
success: resolve,
fail: reject,
});
});
if (code) {
const {
data: { token, nickname, avatar },
} = await get("/login", {
data: { code },
});
storeToken(token);
if (nickname) {
this.setData({
avatar,
nickname,
isLogin: true,
});
wx.setStorageSync("user", { nickname, avatar });
wx.showToast({ title: `登录成功`, duration: 1000 });
} else {
const confirm = await wx.showModal({
title: "登录成功,您还未完善信息",
content: "去完善信息吧",
confirmText: "去完善",
});
if (confirm) {
return wx.navigateTo({ url: "/pages/improve/improve" });
}
}
}
} catch (error) {
wx.showToast({
title: error.message || "Login failed.",
icon: "error",
duration: 2000,
});
}
},
});
app.json
{
"pages": [
"pages/index/index",
"pages/interview/interview",
"pages/lesson/lesson",
"pages/profile/profile",
"pages/improve/improve"
],
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "images/home.png",
"selectedIconPath": "images/home-selected.png"
},
{
"pagePath": "pages/interview/interview",
"text": "面试题",
"iconPath": "images/interview.png",
"selectedIconPath": "images/interview-selected.png"
},
{
"pagePath": "pages/lesson/lesson",
"text": "课程中心",
"iconPath": "images/lesson.png",
"selectedIconPath": "images/lesson-selected.png"
},
{
"pagePath": "pages/profile/profile",
"text": "我",
"iconPath": "images/profile.png",
"selectedIconPath": "images/profile-selected.png"
}
]
},
"usingComponents": {
"van-button": "@vant/weapp/button/index"
},
+ "window": {
+ "navigationBarBackgroundColor": "#000000",
+ "navigationBarTextStyle":"white",
+ "navigationBarTitleText": "前端面试",
+ "backgroundColor": "#EEEEEE",
+ "backgroundTextStyle":"dark",
+ "enablePullDownRefresh": false
+ }
}
"window"
:这是一个对象,用于定义小程序的窗口属性。
"navigationBarBackgroundColor"
:指定导航栏的背景颜色,这里设置为黑色 (#000000
)。"navigationBarTextStyle"
:指定导航栏的文本样式,这里设置为白色 (white
),表示导航栏上的文字颜色为白色。"navigationBarTitleText"
:指定导航栏的标题文字内容,这里设置为 "前端面试",表示小程序页面打开时导航栏的标题为 "前端面试"。"backgroundColor"
:指定小程序的背景颜色,这里设置为淡灰色 (#EEEEEE
)。"backgroundTextStyle"
:指定下拉刷新时页面的背景样式,这里设置为 "dark",表示背景色为深色,通常用于在下拉刷新时遮罩整个页面以显示加载状态。"enablePullDownRefresh"
:布尔值,用于控制页面是否支持下拉刷新,这里设置为 true
,表示该小程序页面支持下拉刷新操作。
pages\index\index.json
{
"usingComponents": {},
+ "navigationBarTitleText": "首页",
+ "enablePullDownRefresh": true
}
pages\interview\interview.json
{
"usingComponents": {},
+ "navigationBarTitleText": "面试题"
}
pages\lesson\lesson.json
{
"usingComponents": {},
+ "navigationBarTitleText": "课程中心"
}
pages\profile\profile.json
{
"usingComponents": {},
+ "navigationBarTitleText": "个人中心"
}
pages\index\index.js
+import { get } from "../../utils/request";
Page({
data: {
+ bannerList: [],
},
+ async getBannerList() {
+ const { bannerList } = await get("/bannerList");
+ this.setData({
+ bannerList,
+ });
+ },
+ async onLoad() {
+ this.getBannerList();
+ },
});
pages\index\index.wxml
<swiper indicator-dots="{{true}}" autoplay circular interval="3000">
<swiper-item
wx:for="{{bannerList}}"
wx:key="index"
wx:for-item="item"
wx:for-index="index"
>
<image src="{{item.url}}" mode="aspectFill" data-href="{{item.href}}" />
</swiper-item>
</swiper>
pages\index\index.wxss
swiper{
width:100%;
height:350rpx;
}
swiper image{
width:100%;
height:100%;
}
app.wxss
.container{
width:95%;
margin:0 auto;
}
pages\index\index.js
import { get } from "../../utils/request";
Page({
data: {
bannerList: [],
+ articles: [],
+ total: 0,
+ page: 1,
+ limit: 5,
},
async getBannerList() {
const { bannerList } = await get("/bannerList");
this.setData({
bannerList,
});
},
+ async getArticleList() {
+ const { articles, total } = await get("/articleList", {
+ data: {
+ page: this.data.page,
+ limit: this.data.limit,
+ },
+ });
+ this.setData({
+ articles,
+ total,
+ });
+ },
async onLoad() {
this.getBannerList();
+ this.getArticleList();
},
});
pages\index\index.json
{
+ "usingComponents": {
+ "article": "/components/article/article"
+ },
"navigationBarTitleText": "首页"
}
pages\index\index.wxml
<swiper indicator-dots="{{true}}" autoplay circular interval="3000">
<swiper-item wx:for="{{bannerList}}" wx:key="index" wx:for-item="item" wx:for-index="index">
<image src="{{item.url}}" mode="aspectFill" data-href="{{item.href}}" />
</swiper-item>
</swiper>
+<view class="container">
+ <view class="title">经典文章</view>
+ <article space="space" wx:for="{{articles}}" wx:key="index" wx:for-item="article" article="{{article}}"></article>
+</view>
pages\index\index.wxss
swiper{
width:100%;
height:350rpx;
}
swiper image{
width:100%;
height:100%;
}
+.title{
+ width:100%;
+ height:60rpx;
+ line-height: 60rpx;
+ text-align: center;
+}
+.space{
+ margin-bottom: 15rpx;
+}
components\article\article.wxml
<view class="article space">
<text class="title">{{article.title}}</text>
<view class="author">
<text>{{article.author}} | {{article.createTime}}</text>
</view>
<image class="poster" src="{{article.poster}}" mode="aspectFill" />
<text class="content">{{article.content}}</text>
<view class="views">
<text>点赞:{{article.support}} | 观看:{{article.look}}</text>
</view>
</view>
components\article\article.json
{
"component": true,
"usingComponents": {}
}
components\article\article.js
Component({
externalClasses: ["space"],
properties: {
article: {
type: Object,
value: {},
},
},
data: {},
methods: {},
});
components\article\article.wxss
.article {
border: 1px solid #ccc;
border-radius: 15rpx;
padding: 25rpx;
}
.title {
padding-top: 10px;
font-size: 35rpx;
font-weight: bold;
line-height: 50rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
display: inline-block;
}
.author {
font-size: 25rpx;
line-height: 45rpx;
}
.content {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
margin: 15rpx 0;
font-size: 30rpx;
}
.poster {
width: 100%;
height: 300rpx;
border-radius: 20rpx;
}
.views {
color: #777;
font-size: 25rpx;
}
pages\index\index.js
import { get } from "../../utils/request";
Page({
data: {
bannerList: [],
articles: [],
total: 0,
page: 1,
limit: 5,
},
async getBannerList() {
const { bannerList } = await get("/bannerList");
this.setData({
bannerList,
});
},
async getArticleList() {
const { articles, total } = await get("/articleList", {
data: {
page: this.data.page,
limit: this.data.limit,
},
});
this.setData({
+ articles: [...this.data.articles, ...articles],
total,
+ page: this.data.page + 1,
});
},
async onLoad() {
this.getBannerList();
this.getArticleList();
},
+ async onReachBottom() {
+ if (this.data.total === this.data.articles.length) return;
+ wx.showNavigationBarLoading();
+ await this.getArticleList();
+ wx.hideNavigationBarLoading();
+ },
+ async onPullDownRefresh() {
+ this.data.articles = [];
+ this.data.page = 1;
+ await this.getArticleList();
+ wx.stopPullDownRefresh();
+ },
});
components\article\article.wxml
+<view class="article space" bindtap="toDetail">
<text class="title">{{article.title}}</text>
<view class="author">
<text>{{article.author}} | {{article.createTime}}</text>
</view>
<image class="poster" src="{{article.poster}}" mode="aspectFill" />
<text class="content">{{article.content}}</text>
<view class="views">
<text>点赞:{{article.support}} | 观看:{{article.look}}</text>
</view>
</view>
components\article\article.js
Component({
externalClasses: ["space"],
properties: {
article: {
type: Object,
value: {},
},
},
data: {},
methods: {
+ toDetail() {
+ this.triggerEvent("todetail", this.data.article);
+ },
},
});
pages\index\index.wxml
<swiper indicator-dots="{{true}}" autoplay circular interval="3000">
<swiper-item wx:for="{{bannerList}}" wx:key="index" wx:for-item="item" wx:for-index="index">
<image src="{{item.url}}" mode="aspectFill" data-href="{{item.href}}" />
</swiper-item>
</swiper>
<view class="container">
<view class="title">经典文章</view>
+ <article space="space" wx:for="{{articles}}" wx:key="index" wx:for-item="article" article="{{article}}" bind:todetail="toArticleDetail"></article>
</view>
pages\index\index.js
import { get } from "../../utils/request";
Page({
data: {
bannerList: [],
articles: [],
total: 0,
page: 1,
limit: 5,
},
async getBannerList() {
const { bannerList } = await get("/bannerList");
this.setData({
bannerList,
});
},
async getArticleList() {
const { articles, total } = await get("/articleList", {
data: {
page: this.data.page,
limit: this.data.limit,
},
});
this.setData({
articles: [...this.data.articles, ...articles],
total,
page: this.data.page + 1,
});
},
async onLoad() {
this.getBannerList();
this.getArticleList();
},
async onReachBottom() {
if (this.data.total === this.data.articles.length) return;
wx.showNavigationBarLoading();
await this.getArticleList();
wx.hideNavigationBarLoading();
},
async onPullDownRefresh() {
this.data.articles = [];
this.data.page = 1;
await this.getArticleList();
wx.stopPullDownRefresh();
},
+ toArticleDetail(event) {
+ wx.navigateTo({
+ url: "/pages/article-detail/article-detail?id=" + event.detail._id,
+ });
+ }
});
pages\article-detail\article-detail.wxml
<view class="container">
<text class="title">{{article.title}}</text>
<view>
<text>{{article.author}}</text>
|
<text>{{article.createTime}}</text>
</view>
<image class="poster" src="{{article.poster}}" mode="aspectFill" bind:tap="preview" />
<text class="detail-content" user-select>{{article.detail}}</text>
</view>
pages\article-detail\article-detail.wxss
.title {
font-size: 45rpx;
padding: 20rpx 0;
}
.poster {
width: 100%;
height: 350rpx;
margin: 20rpx 0;
}
.detail-content {
font-size: 25rpx;
}
pages\article-detail\article-detail.json
{
"usingComponents": {},
"navigationBarTitleText": "文章详情"
}
pages\article-detail\article-detail.js
import { get } from "../../utils/request";
Page({
data: {
article: {},
},
async onLoad(options) {
let id = options.id;
let { article } = await get("/article", {
data: {
id,
},
});
this.setData({
article,
});
},
preview() {
wx.previewImage({
urls: [this.data.article.poster],
});
},
});
pages\interview\interview.wxml
<scroll-view scroll-x style="white-space: nowrap;">
<view
wx:for="{{tabs}}"
wx:for-index="index"
wx:key="index"
data-index="{{index}}"
bind:tap="tabChange"
class="tab-item {{currentIndex === index ? 'active':''}}"
>
{{ item }}
</view>
</scroll-view>
pages\interview\interview.wxss
.tab-item {
display: inline-block;
padding: 30rpx;
border: 1px solid #ccc;
}
.active {
background: #0099ff;
color: #fff;
}
pages\interview\interview.js
Page({
data: {
tabs: ["css", "html", "js", "react", "vue", "typescript", "node"],
currentIndex: 0,
},
changeCurrentIndex(currentIndex) {
this.setData({
currentIndex,
});
},
tabChange(event) {
this.changeCurrentIndex(event.currentTarget.dataset["index"]);
},
});
pages\interview\interview.wxml
<scroll-view scroll-x style="white-space: nowrap;">
<view
wx:for="{{tabs}}"
wx:for-index="index"
wx:key="index"
data-index="{{index}}"
bind:tap="tabChange"
class="tab-item {{currentIndex === index ? 'active':''}}"
>
{{item}}
</view>
</scroll-view>
+<swiper current="{{currentIndex}}" bind:change="swiperChange">
+ <swiper-item wx:for="{{tabs}}" wx:key="i" >
+ <view>{{item}}</view>
+ </swiper-item>
+</swiper>
pages\interview\interview.js
Page({
data: {
tabs: ["vue", "react", "typescript", "html", "css", "node"],
currentIndex: 0,
},
changeCurrentIndex(currentIndex) {
this.setData({
currentIndex,
});
},
tabChange(event) {
this.changeCurrentIndex(event.currentTarget.dataset["index"]);
},
+ swiperChange(event) {
+ this.changeCurrentIndex(event.detail.current);
+ },
});
pages\interview\interview.wxml
<scroll-view scroll-x style="white-space: nowrap;">
<view wx:for="{{tabs}}" wx:for-index="index" wx:key="index" data-index="{{index}}" bind:tap="tabChange" class="tab-item {{currentIndex === index ? 'active':''}}">
{{item}}
</view>
</scroll-view>
<swiper current="{{currentIndex}}" bind:change="swiperChange">
<swiper-item wx:for="{{tabs}}" wx:key="i">
+ <view wx:for="{{interviews}}" wx:key="i">
+ {{item.title}}
+ </view>
</swiper-item>
</swiper>
pages\interview\interview.js
import { get } from "../../utils/request";
Page({
data: {
tabs: ["vue", "react", "typescript", "html", "css", "node"],
currentIndex: 0,
+ interviews: [],
},
changeCurrentIndex(currentIndex) {
+ this.setData({ currentIndex }, this.getInterviews);
},
tabChange(event) {
this.changeCurrentIndex(event.currentTarget.dataset["index"]);
},
swiperChange(event) {
this.changeCurrentIndex(event.detail.current);
},
+ async getInterviews() {
+ let type = this.data.tabs[this.data.currentIndex];
+ const { interview: interviews } = await get("/interview", {
+ data: { type },
+ });
+ this.setData({
+ interviews,
+ });
+ },
+ async onLoad() {
+ await this.getInterviews();
+ },
});
pages\interview\interview.wxml
<scroll-view scroll-x style="white-space: nowrap;">
<view wx:for="{{tabs}}" wx:for-index="index" wx:key="index" data-index="{{index}}" bind:tap="tabChange" class="tab-item {{currentIndex === index ? 'active':''}}">
{{item}}
</view>
</scroll-view>
+<swiper current="{{currentIndex}}" bind:change="swiperChange" style="height:{{swiperHeight}}px">
<swiper-item wx:for="{{tabs}}" wx:key="i">
+ <view wx:for-index="index" class="swiper-item-{{index}}">
+ <view wx:for="{{interviews}}" wx:key="i" class="interview">{{item.title}}</view>
+ </view>
</swiper-item>
</swiper>
pages\interview\interview.wxss
.tab-item {
display: inline-block;
padding: 30rpx;
border: 1px solid #ccc;
}
.active {
background: #0099ff;
color: #fff;
}
+.interview {
+ height: 100rpx;
+}
pages\interview\interview.js
import { get } from "../../utils/request";
Page({
data: {
tabs: ["vue", "react", "typescript", "html", "css", "node"],
currentIndex: 0,
interviews: [],
+ swiperHeight: 150,
},
changeCurrentIndex(currentIndex) {
this.setData({ currentIndex }, this.getInterviews);
},
tabChange(event) {
this.changeCurrentIndex(event.currentTarget.dataset["index"]);
},
swiperChange(event) {
this.changeCurrentIndex(event.detail.current);
},
async getInterviews() {
let type = this.data.tabs[this.data.currentIndex];
const { interview: interviews } = await get("/interview", {
data: { type },
});
+ this.setData(
+ {
+ interviews,
+ },
+ () => {
+ const query = wx.createSelectorQuery();
+ query
+ .select(`.swiper-item-${this.data.currentIndex}`)
+ .boundingClientRect();
+ query.exec((result) => {
+ const { height } = result[0];
+ this.setData({
+ swiperHeight: height,
+ });
+ });
+ }
+ );
+ },
async onLoad() {
await this.getInterviews();
},
});
app.json
{
"pages": [
"pages/index/index",
"pages/interview/interview",
"pages/lesson/lesson",
"pages/profile/profile",
"pages/improve/improve",
"pages/article-detail/article-detail"
],
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "images/home.png",
"selectedIconPath": "images/home-selected.png"
},
{
"pagePath": "pages/interview/interview",
"text": "面试题",
"iconPath": "images/interview.png",
"selectedIconPath": "images/interview-selected.png"
},
{
"pagePath": "pages/lesson/lesson",
"text": "课程中心",
"iconPath": "images/lesson.png",
"selectedIconPath": "images/lesson-selected.png"
},
{
"pagePath": "pages/profile/profile",
"text": "我",
"iconPath": "images/profile.png",
"selectedIconPath": "images/profile-selected.png"
}
]
},
"usingComponents": {
"van-button": "@vant/weapp/button/index"
},
"window": {
"navigationBarBackgroundColor": "#000000",
"navigationBarTextStyle": "white",
"navigationBarTitleText": "前端面试",
"backgroundColor": "#EEEEEE",
"backgroundTextStyle": "dark",
"enablePullDownRefresh": false
},
+ "requiredBackgroundModes": ["audio"]
}
pages\interview\interview.wxml
<scroll-view scroll-x style="white-space: nowrap;">
<view wx:for="{{tabs}}" wx:for-index="index" wx:key="index" data-index="{{index}}" bind:tap="tabChange" class="tab-item {{currentIndex === index ? 'active':''}}">
{{item}}
</view>
</scroll-view>
<swiper current="{{currentIndex}}" bind:change="swiperChange" style="height:{{swiperHeight}}px">
<swiper-item wx:for="{{tabs}}" wx:key="i">
<view wx:for-index="index" class="swiper-item-{{index}}">
+ <view wx:for="{{interviews}}" wx:key="i" class="interview">
+ <text>{{item.title}}</text>
+ <text>{{item.desc}}</text>
+ <view class="interview-operator">
+ <van-rate custom-class="rate" readonly value="{{item.hard}}" color="#ffd21e" void-icon="star" void-color="#eee" />
+ <image class="music" data-interview="{{item}}" src="{{playingId == item._id ? '/images/pause.png' : '/images/play.png'}}" bind:tap="togglePlay" />
+ </view>
+ </view>
</view>
</swiper-item>
</swiper>
pages\interview\interview.json
{
"usingComponents": {
+ "van-rate": "@vant/weapp/rate/index"
},
"navigationBarTitleText": "面试题"
}
pages\interview\interview.wxss
.tab-item {
display: inline-block;
padding: 30rpx;
border: 1px solid #ccc;
}
.active {
background: #0099ff;
color: #fff;
}
+.interview {
+ padding: 10rpx;
+}
+.interview-operator {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ height: 80rpx;
+ align-items: center;
+ border-bottom: 1rpx solid #ccc;
+ margin-bottom: 5rpx;
+}
+.rate {
+ display: flex;
+}
+.music {
+ width: 60rpx;
+ height: 60rpx;
+}
pages\interview\interview.js
import { get } from "../../utils/request";
Page({
data: {
tabs: ["vue", "react", "typescript", "html", "css", "node"],
currentIndex: 0,
interviews: [],
swiperHeight: 150,
+ playingId: '',
+ audioManager: null,
},
changeCurrentIndex(currentIndex) {
this.setData({ currentIndex }, this.getInterviews);
},
tabChange(event) {
this.changeCurrentIndex(event.currentTarget.dataset["index"]);
},
swiperChange(event) {
this.changeCurrentIndex(event.detail.current);
},
async getInterviews() {
let type = this.data.tabs[this.data.currentIndex];
const { interview: interviews } = await get("/interview", {
data: { type },
});
this.setData(
{
interviews,
},
() => {
const query = wx.createSelectorQuery();
query
.select(`.swiper-item-${this.data.currentIndex}`)
.boundingClientRect();
query.exec((result) => {
const { height } = result[0];
this.setData({
swiperHeight: height,
});
});
}
);
},
async onLoad() {
+ this.getInterviews();
+ this.initAudioManager();
},
+ initAudioManager() {
+ const audioManager = wx.getBackgroundAudioManager();
+ this.setData({ audioManager });
+ audioManager.onPause(() => {
+ this.setData({ playingId: -1 });
+ });
+ },
+ togglePlay(event) {
+ const { url, title, _id } = event.currentTarget.dataset.interview;
+ if(!url){
+ return wx.showToast({
+ title: '音频文件不存在',
+ })
+ }
+ const { audioManager, playingId } = this.data;
+ if (playingId === _id) {
+ audioManager.pause();
+ this.setData({ playingId: -1 });
+ } else {
+ audioManager.title = title;
+ audioManager.src = url;
+ this.setData({ playingId: _id });
+ }
+ },
+ stopAudio() {
+ this.data.audioManager.stop();
+ },
+ onHide() {
+ this.stopAudio();
+ },
+ onUnload() {
+ this.stopAudio();
+ },
});
pages\lesson\lesson.wxml
<van-card
wx:for="{{lessons}}"
wx:key="i"
desc="{{item.desc}}"
title="{{item.title}}"
thumb="{{ item.poster }}"
thumb-mode="aspectFill"
>
<view slot="footer">
<van-button size="small" data-url="{{item.url}}">
观看
</van-button>
<van-button size="small">收藏</van-button>
</view>
</van-card>
pages\lesson\lesson.json
{
"usingComponents": {
"van-card": "@vant/weapp/card/index",
"van-button": "@vant/weapp/button/index"
},
"navigationBarTitleText": "课程中心"
}
pages\lesson\lesson.js
import { get } from "../../utils/request";
Page({
data: {
lessons: [],
},
async onLoad() {
let { lesson: lessons } = await get("/lesson");
this.setData({
lessons,
});
},
});
pages\lesson\lesson.wxml
+<video class="lessonVideo" src="{{url}}" autoplay></video>
<van-card wx:for="{{lessons}}" wx:key="i" desc="{{item.desc}}" title="{{item.title}}" thumb="{{ item.poster }}" thumb-mode="aspectFill">
<view slot="footer">
+ <van-button size="small" data-url="{{item.url}}" bind:tap="watch">观看</van-button>
<van-button size="small">收藏</van-button>
</view>
</van-card>
pages\lesson\lesson.wxss
+.lessonVideo {
+ width: 100%;
+}
pages\lesson\lesson.js
import { get } from "../../utils/request";
Page({
data: {
lessons: [],
+ url: "",
},
async onLoad() {
let { lesson: lessons } = await get("/lesson");
this.setData({
lessons,
});
},
+ watch(event) {
+ let { url } = event.currentTarget.dataset;
+ this.setData({
+ url,
+ });
+ },
});
pages\lesson\lesson.wxml
+<van-search value="{{ value }}" placeholder="请输入搜索关键词" show-action bind:search="onSearch" />
<video class="lessonVideo" src="{{url}}" autoplay></video>
<van-card wx:for="{{filteredLessons}}" wx:key="i" desc="{{item.desc}}" title="{{item.title}}" thumb="{{ item.poster }}" thumb-mode="aspectFill">
<view slot="footer">
<van-button size="small" data-url="{{item.url}}" bind:tap="watch">观看</van-button>
<van-button size="small">收藏</van-button>
</view>
</van-card>
pages\lesson\lesson.json
{
"usingComponents": {
"van-card": "@vant/weapp/card/index",
"van-button": "@vant/weapp/button/index",
+ "van-search": "@vant/weapp/search/index"
},
"navigationBarTitleText": "课程中心"
}
pages\lesson\lesson.js
import { get } from "../../utils/request";
Page({
data: {
lessons: [],
+ filteredLessons: [],
url: "",
+ value: "",
},
async onLoad() {
let { lesson: lessons } = await get("/lesson");
this.setData({
lessons,
+ filteredLessons: lessons,
});
},
watch(event) {
let { url } = event.currentTarget.dataset;
this.setData({
url,
});
},
+ onSearch(event) {
+ let { lessons } = this.data;
+ if (event.detail == "") return this.setData({ filteredLessons: lessons });
+ this.setData({
+ filteredLessons: lessons.filter((item) =>
+ item.title.includes(event.detail)
+ ),
+ });
+ },
});
pages\lesson\lesson.wxml
<van-search value="{{ value }}" placeholder="请输入搜索关键词" show-action bind:search="onSearch" />
<video class="lessonVideo" src="{{url}}" autoplay></video>
<van-card wx:for="{{filteredLessons}}" wx:key="i" desc="{{item.desc}}" title="{{item.title}}" thumb="{{ item.poster }}" thumb-mode="aspectFill">
+ <view slot="footer" mark:lesson="{{item}}">
<van-button size="small" data-url="{{item.url}}" bind:tap="watch">观看</van-button>
+ <van-button size="small" bind:tap="addFavorite">收藏</van-button>
</view>
</van-card>
pages\lesson\lesson.js
import { get } from "../../utils/request";
+const app = getApp();
Page({
data: {
lessons: [],
filteredLessons: [],
url: "",
value: "",
},
async onLoad() {
let { lesson: lessons } = await get("/lesson");
this.setData(
{
lessons,
filteredLessons: lessons,
},
+ () => this.playLesson()
);
},
+ playLesson() {
+ let { lessonId } = app.globalData;
+ if (lessonId) {
+ const lesson = this.data.lessons.find((item) => item._id === lessonId);
+ if (lesson) {
+ this.setData({ url: lesson.url });
+ }
+ }
+ },
+ onShow() {
+ this.playLesson();
+ },
watch(event) {
let { url } = event.currentTarget.dataset;
this.setData({
url,
});
},
onSearch(event) {
let { lessons } = this.data;
if (event.detail == "") return this.setData({ filteredLessons: lessons });
this.setData({
filteredLessons: lessons.filter((item) =>
item.title.includes(event.detail)
),
});
},
addFavorite(event) {
let { lesson } = event.mark;
const favorites = wx.getStorageSync("favorites") || {};
favorites[lesson._id] = lesson;
wx.setStorageSync("favorites", favorites);
},
});
pages\profile\profile.wxml
<view class="profile-login">
<view class="profile-login-container">
<image class="profile-avatar" src="{{isLogin? avatar: avatarUrl}}"></image>
<view class="profile-info" wx:if="{{isLogin}}">
<text>{{nickname}}</text>
</view>
<view class="profile-info" wx:else>
<text class="login-prompt-text">未登录</text>
<button class="login-status-btn" bind:tap="loginUser">点我快捷登录</button>
</view>
</view>
</view>
<van-cell-group inset wx:if="{{isLogin}}">
<van-cell title="退出" bind:click="logout" is-link />
+ <van-cell title="收藏" is-link url="/pages/favorites/favorites" />
</van-cell-group>
<van-button type="info" block open-type="share">分享前端面试</van-button>
pages\favorites\favorites.wxml
<van-cell
wx:for="{{lessons}}"
wx:key="i"
title="{{item.title}}"
mark:lesson="{{item}}"
bind:click="watchLesson"
is-link
></van-cell>
pages\favorites\favorites.json
{
"usingComponents": {
"van-cell": "@vant/weapp/cell/index",
"van-cell-group": "@vant/weapp/cell-group/index"
}
}
pages\favorites\favorites.js
const app = getApp();
Page({
data: {
lessons: [],
},
onLoad() {
let lessons = wx.getStorageSync("favorites");
if (!lessons) return;
this.setData({
lessons: Object.values(lessons),
});
},
watchLesson(event) {
app.globalData.lessonId = event.mark.lesson._id;
wx.switchTab({
url: "/pages/lesson/lesson",
});
},
});
div
元素。<view class="container">
<text>Hello</text>
</view>
src
(设置图片路径)、mode
(设置图片裁剪、缩放的模式)等。<image src="/path/to/image.jpg" mode="aspectFit"/>
其中,mode
的aspectFit
表示按原图比例显示,图片可能会有留白。
bindtap
事件一起使用,来响应文本的点击事件。<text> This is some text. </text>
在微信小程序中,rpx
(Responsive Pixel)是一个专门为屏幕适配设计的长度单位。由于移动设备有着各种各样的屏幕尺寸和分辨率,使用rpx
单位可以更容易地实现多屏适配。
以下是一些关于rpx
的关键点:
定义:
rpx
意为“响应式像素”。基准:
1rpx
等于1px
(像素)。自适应:
rpx
是响应式的,它会根据实际设备的屏幕宽度进行自动缩放。1rpx
会等于1px
;如果屏幕宽度是 500px,那么1rpx
会等于500/750 px
。使用场景:
rpx
尤其适用于跨多种手机型号、尺寸和分辨率的 UI 布局。px
作为单位。转换:
示例:
.container {
width: 750rpx; /* 宽度填满屏幕 */
height: 300rpx; /* 高度为屏幕宽度的2/5 */
}
总之,使用rpx
单位是微信小程序为了简化移动端屏幕适配问题而引入的一个特色设计。在开发过程中合理使用它,可以有效地保证用户界面在不同设备上的一致性和良好表现。
在微信小程序中,事件处理是核心的交互手段。bind:tap
和catch:tap
都是用于处理“点击”事件的,但它们之间存在一些差异。下面是对这两个事件处理器的详细解释:
bind:tap:
bind:tap
是一个常用的事件处理器,用于监听元素的点击事件。bind:tap
事件处理函数会被调用。bind:tap
,还会触发其父级元素上的bind:tap
,直到它到达页面的根元素或被一个catch:tap
捕获。示例:
<view bind:tap="handleTap">点击我</view>
catch:tap:
catch:tap
也是用于监听元素的点击事件的。bind:tap
的主要差异在于:catch:tap
会“捕获”事件,阻止它进一步冒泡。示例:
<view bind:tap="parentTap">
<view catch:tap="childTap">点击我</view>
</view>
在上述示例中,当你点击内部的view
元素时,childTap
函数会被调用,但由于catch:tap
的存在,parentTap
函数不会被触发。
总结:
bind:tap
时,点击事件会冒泡到父级元素。catch:tap
时,点击事件会被当前元素捕获,并停止冒泡。在开发过程中,应根据具体需求选择使用bind:tap
还是catch:tap
。
wx.login
是微信小程序提供的一个核心 API,它允许开发者发起微信用户登录,获取用户登录态。这个登录态在小程序中是非常关键的,因为它通常是获取用户信息、调用微信支付等高级功能的前提条件。
以下是wx.login
的详细解释:
主要功能:
获取 Code:
wx.login
方法时,微信会返回一个临时的登录凭证 code
。code
可以被传送到开发者的服务器,然后服务器可以与微信服务器交互,进一步获取用户的 openId
、sessionKey
甚至 unionId
(如果微信账户与其他应用已经关联)。替代微信用户信息的显式授权:
wx.login
和后续的服务器交互,开发者可以在用户不进行显式授权的情况下获取到其 openId
。使用方法:
wx.login({
success: (res) => {
if (res.code) {
// 可以将 res.code 发送到后台,通过code获取用户的 sessionKey 等相关信息
} else {
console.log("登录失败!" + res.errMsg);
}
},
fail: (error) => {
// 登录失败的处理
},
});
注意事项:
wx.login
获取的 code
是临时的,只能使用一次,所以每次需要与后台交互获取用户信息时,都要重新调用 wx.login
。安全性:
code
获取 openId
或 sessionKey
,因为这涉及到 AppSecret,会存在泄露的风险。code
发送到开发者自己的后台,然后在后台与微信服务器进行交互。与 wx.getUserInfo 的关系:
wx.login
只能获取到用户的 openId
和 sessionKey
。wx.getUserInfo
。但请注意,wx.getUserInfo
需要用户的明确授权。总的来说,wx.login
是微信小程序中的核心登录功能,与后端的配合使用可以安全高效地获取到用户的登录态和基本信息。
wx.request
是微信小程序中提供的一个网络请求 API,允许开发者向服务器发送请求,获取或提交数据。该 API 是开发微信小程序时经常用到的,因为它是小程序与后台服务器通信的主要手段。
以下是wx.request
的详细解释:
主要功能:
GET
、POST
等常见的 HTTP 请求方法,获取数据或提交数据到服务器。使用方法:
基本用法:
wx.request({
url: "https://example.com/data", // 开发者服务器接口地址
method: "GET", // 请求方法,默认为GET,有效值:OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
data: { key: "value" }, // 请求的参数
header: {
"content-type": "application/json", // 默认值
},
success: (res) => {
console.log(res.data); // 服务器返回的数据
},
fail: (error) => {
// 请求失败的处理
},
complete: (res) => {
// 请求完成后的回调函数,无论成功还是失败都会执行
},
});
注意事项:
域名要求:
数据格式:
header
为 'content-type': 'application/json'
,但根据需要也可以设置为其他值,如 'content-type': 'application/x-www-form-urlencoded'
。并发限制:
请求超时:
wx.request
提供了 timeout
参数来设置请求的超时时间。错误处理:
fail
回调,例如 404、500 等。跨域问题:
示例:
获取服务器数据示例:
wx.request({
url: "https://example.com/data",
success: function (res) {
console.log(res.data);
},
});
提交表单数据示例:
wx.request({
url: "https://example.com/submit",
method: "POST",
data: {
username: "abc",
password: "123",
},
header: {
"content-type": "application/x-www-form-urlencoded",
},
success: function (res) {
console.log(res.data);
},
});
总的来说,wx.request
是微信小程序中非常重要的一个 API,它为小程序与后端服务的数据交互提供了基础能力。在开发过程中,正确和高效地使用它是关键。
wx.showToast
是微信小程序中的一个常用 API,用于显示一个短暂的、不会打断用户操作的消息提示框。这个 API 特别适用于给用户提供一些简单的反馈,比如“保存成功”、“操作失败”之类的提示。
以下是 wx.showToast
的详细讲解:
主要功能:
常用参数:
示例:
wx.showToast({
title: "保存成功",
icon: "success",
duration: 2000,
});
wx.showToast({
title: "警告",
image: "/path/to/your/icon.png", // 提供自定义图标的路径
duration: 2000,
});
wx.showToast({
title: "网络错误",
icon: "none",
duration: 2000,
});
注意事项:
wx.showToast
与 wx.showModal
、wx.showLoading
之间存在互斥关系。调用 wx.showToast
时,会自动隐藏 wx.showModal
、wx.showLoading
。wx.showToast
。如果在一个 wx.showToast
显示期间调用另一个 wx.showToast
,那么新的将替换旧的。duration
。总的来说,wx.showToast
是一个轻量级的、用于向用户提供反馈的提示框。在小程序开发中,它是一个非常实用和频繁使用的工具。
wx.showModal
是微信小程序中的一个 API,用于显示模态对话框。这个模态对话框通常用于向用户提供信息、警告或询问用户意见。它包含一个标题、内容区域,以及一个或两个按钮(通常为“取消”和“确定”)。
以下是关于 wx.showModal
的详细解释:
主要功能:
使用方法:
基本用法:
wx.showModal({
title: "提示", // 模态对话框的标题
content: "这是一个模态弹窗", // 模态对话框的内容
showCancel: true, // 是否显示取消按钮,默认为true
cancelText: "取消", // 取消按钮的文字,默认为"取消"
cancelColor: "#000000", // 取消按钮的文字颜色
confirmText: "确定", // 确定按钮的文字,默认为"确定"
confirmColor: "#3CC51F", // 确定按钮的文字颜色
success: (result) => {
if (result.confirm) {
console.log("用户点击确定");
} else if (result.cancel) {
console.log("用户点击取消");
}
},
fail: () => {
console.log("模态对话框显示失败");
},
});
注意事项:
wx.showModal
会返回用户的操作:confirm
和 cancel
。通过检查 result.confirm
的值,你可以知道用户是点击了“确定”按钮,还是“取消”按钮。颜色规范:
#FFFFFF
、red
等。异步操作:
wx.showModal
是一个异步操作,意味着它不会阻塞代码的执行。当用户做出选择后(点击“确定”或“取消”),success
回调函数会被触发。wx.showModal
不返回任何值,也就是说,你不能使用变量去接收它的返回结果。要处理用户的选择,必须使用 success
回调。总结:wx.showModal
是微信小程序中的一个非常实用的 API,它提供了一种简单且直观的方式向用户显示信息或获取用户的确认。正确使用此 API 可以提高用户体验并使小程序交互更为流畅。
getApp
是微信小程序的一个核心 API,它允许你获取全局的小程序实例。当你在微信小程序中调用 App
函数定义小程序行为时,你实际上是在创建一个小程序实例。而 getApp
则允许你在小程序的任何地方访问这个实例。
以下是关于 getApp
的详细解释:
主要功能:
App
对象中定义的全局数据和函数。使用方法:
基本用法:
const appInstance = getApp();
console.log(appInstance.globalData); // 输出在App对象中定义的globalData
注意事项:
生命周期:
getApp
获取的小程序实例与 App
对象的生命周期相同。也就是说,它会在小程序启动时创建,并在小程序关闭时销毁。全局数据共享:
getApp
是访问全局数据和函数的主要方式。在 App
对象中定义的任何数据和函数都可以通过 getApp
在任何页面或组件中访问。避免过度依赖:
getApp
提供了方便的全局数据访问方式,但应避免将大量数据存储在 App
对象中,因为这可能会导致数据管理变得复杂。适当地使用页面和组件的数据和状态更有利于维护和代码的可读性。确保小程序实例存在:
getApp
可能会返回 undefined
。在这种情况下,你应确保在使用 getApp
返回的数据或函数之前,小程序实例已经被创建。总结:getApp
是微信小程序中一个非常有用的 API,允许你轻松访问全局的小程序实例及其数据和函数。然而,正确地使用它并避免过度依赖全局数据是实现高效、可维护和易于理解的小程序的关键。
微信小程序的页面栈是一个关键概念,它涉及到页面的导航、加载、返回和卸载。页面栈基于“栈”这一数据结构,用于管理小程序中的页面导航历史。
以下是关于微信小程序的页面栈的详细解释:
主要功能:
基本概念
页面入栈:
wx.navigateTo
方法),该页面会被压入页面栈的顶部。页面出栈:
wx.navigateBack
方法或用户点击左上角的返回按钮),当前页面会从页面栈的顶部弹出,并被销毁。页面重定向:
wx.redirectTo
方法会关闭当前页面并跳转到目标页面,这意味着当前页面会从栈中移除,而目标页面会压入栈顶。页面替换:
wx.reLaunch
方法可以关闭所有页面并打开目标页面,这会清空整个页面栈并只留下目标页面。Tab 切换:
wx.switchTab
方法切换到一个 tabBar 页面时,这会清空页面栈并将目标 tabBar 页面设为栈底。注意事项:
栈的大小限制:
wx.redirectTo
或 wx.reLaunch
。获取当前页面栈:
getCurrentPages()
函数来获取当前的页面栈。这个函数会返回一个数组,其中第一个元素是栈底页面,最后一个元素是栈顶页面。栈顶页面:
生命周期和页面栈:
onLoad
和 onShow
生命周期方法。onUnload
生命周期方法。onHide
生命周期方法。总结:微信小程序的页面栈是管理页面导航历史的核心机制。通过理解和合理利用页面栈,开发者可以实现复杂的页面导航逻辑并优化用户体验。
wx.navigateTo
是微信小程序中用于页面导航的核心 API 之一。它允许开发者从当前页面打开一个新页面。在小程序的页面栈中,这将会把新页面压入栈顶。
以下是关于 wx.navigateTo
的详细解释:
主要功能:
使用方法:
基本用法:
wx.navigateTo({
url: "/pages/example/example", // 目标页面的路径。前面可以有'/'也可以没有
success: (res) => {
// 页面跳转成功后的回调
},
fail: (error) => {
// 页面跳转失败的回调
console.log(error);
},
complete: () => {
// 页面跳转完成后的回调,无论成功还是失败都会执行
},
});
注意事项:
wx.navigateTo
将不会跳转,需要使用其它方式,如 wx.redirectTo
或 wx.reLaunch
。页面路径:
url
参数中提供的路径,可以是相对于当前页面的路径,也可以是相对于项目根目录的路径。但建议始终使用从项目根目录开始的绝对路径,以避免潜在的路径解析错误。传递参数:
url
中传递参数,例如:/pages/example/example?id=1&name=test
。在被打开的页面中,你可以通过 onLoad
函数的参数来接收这些传递过来的参数。与 wx.redirectTo
的区别:
wx.navigateTo
打开新页面时,当前页面会被保存,用户可以通过点击返回按钮或执行 wx.navigateBack
返回。wx.redirectTo
则是关闭当前页面并跳转到新页面,使当前页面被卸载。关闭页面:
wx.navigateTo
打开的新页面可以通过 wx.navigateBack
或用户点击返回按钮来关闭并返回上一个页面。总结:wx.navigateTo
是微信小程序中进行页面间跳转的基本方法。正确使用它可以确保良好的用户体验和页面间的顺畅导航。
wx.switchTab
是微信小程序中的一个 API,它专为切换 tab 页面而设计。在微信小程序中,tab 页面通常位于小程序的底部导航栏,并提供了快速切换到主要功能或页面的方式。
以下是关于 wx.switchTab
的详细解释:
主要功能:
app.json
中的 tabBar 页面。使用方法:
基本用法:
wx.switchTab({
url: "/pages/example/example", // 目标tabBar页面的路径
success: () => {
// 切换成功后的回调
},
fail: (error) => {
// 切换失败的回调
console.log(error);
},
complete: () => {
// 切换完成后的回调,无论成功还是失败都会执行
},
});
注意事项:
wx.switchTab
中指定的 url
必须是定义在 app.json
中的 tabBar 页面之一。否则,这个方法调用会失败。页面栈的影响:
wx.switchTab
切换到另一个 tabBar 页面时,当前的页面栈会被清空,并且目标 tabBar 页面会成为新的栈底页面。不支持 URL 中传递参数:
wx.switchTab
是切换到一个 tabBar 页面,它不支持在 url
中传递查询参数。如果需要在 tab 页面之间传递数据,你需要使用其他方法,如全局数据、本地存储等。与其他导航方法的区别:
wx.navigateTo
和 wx.redirectTo
不同,wx.switchTab
专门用于切换 tab 页面,而不是打开新页面或重定向到另一个非 tab 页面。动画效果:
wx.switchTab
切换 tab 页面时,微信小程序会自动提供一个平滑的切换动画。总结:wx.switchTab
是微信小程序中切换 tab 页面的核心 API。通过使用它,开发者可以为用户提供一种快速、流畅的方式在主要功能或页面之间切换。正确理解和使用这个 API 是实现高质量、用户友好的小程序的关键。
wx.reLaunch
是微信小程序中的一个核心 API,用于关闭所有页面,并打开至应用的某个页面。它在某些场景下非常有用,如当用户被登出或应用需要进行完全的重启时。
以下是关于 wx.reLaunch
的详细解释:
主要功能:
使用方法:
基本用法:
wx.reLaunch({
url: "/pages/home/home", // 你想要重启至的页面路径
success: () => {
// 重启并切换成功后的回调
},
fail: (error) => {
// 重启失败的回调
console.log(error);
},
complete: () => {
// 重启完成后的回调,无论成功还是失败都会执行
},
});
注意事项:
wx.reLaunch
中指定的 url
是有效的。无效的路径将导致重启失败。页面栈清空:
wx.reLaunch
后,当前的所有页面都会被关闭,新页面成为栈底页面。这意味着用户不能通过返回按钮回到先前的页面。支持 URL 参数:
wx.navigateTo
和 wx.redirectTo
一样,wx.reLaunch
支持在 url
中传递查询参数。这可以在需要重启应用并传递某些信息到新页面时使用。与其他导航方法的区别:
wx.reLaunch
和其他导航方法(如 wx.navigateTo
、wx.redirectTo
、wx.switchTab
)的主要区别在于它会清空整个页面栈并启动新的页面作为栈底页面。使用场景:
总结:wx.reLaunch
是微信小程序中用于实现完全重启的 API。它提供了一种快速、简洁的方式来关闭所有页面并导航到新的页面,从而实现整个应用的重启。正确理解和使用这个 API 可以帮助开发者在需要的场景下提供更好的用户体验。
在微信小程序中,data
和 setData
是与页面和组件状态管理紧密相关的核心概念。
1. data:
data
是页面或组件的一个对象,用于存储页面或组件的初始状态值。这些状态值与页面或组件的.wxml
模板中的数据绑定相关联,当data
中的数据发生变化时,视图会相应地更新。
例如,在页面或组件的 JS 文件中,你可能有如下定义:
Page({
data: {
message: "Hello World!",
count: 0,
},
// ... 其他函数和生命周期方法
});
在上面的例子中,data
对象定义了两个属性:message
和 count
。
2. setData:
setData
是页面或组件的一个核心方法,用于更改 data
中的数据,并告知框架需要更新视图。当你需要改变页面或组件的状态时,直接修改 data
对象是不够的,因为这样不会触发视图更新。你必须使用 setData
方法。
使用 setData
的例子:
Page({
data: {
message: "Hello World!",
count: 0,
},
changeMessage: function () {
this.setData({
message: "New Message!",
});
},
incrementCount: function () {
this.setData({
count: this.data.count + 1,
});
},
// ... 其他函数和生命周期方法
});
在上述代码中,changeMessage
函数使用 setData
更改了 message
的值,而 incrementCount
函数使 count
值增加了 1。每次调用 setData
,页面的视图都会相应地更新。
注意事项:
性能考虑:
setData
是一个相对昂贵的操作,因为它可能会触发视图的重新渲染。因此,建议合并多个数据更改为单个 setData
调用,而不是连续使用多个 setData
。异步操作:
setData
是异步的。这意味着在调用 setData
之后,数据不会立即更新。如果你需要在数据更新后执行某些操作,可以使用 setData
的回调。深度数据路径:
setData
时,可以使用深度数据路径来更新嵌套对象中的属性。例如,this.setData({'obj.key': value})
。总结:在微信小程序中,data
和 setData
是状态管理的基石。通过理解它们的工作原理和正确使用它们,开发者可以轻松管理页面和组件的状态,并确保视图与数据保持同步。
wx:elif
是“else if”的简写形式,用于在wx:if
的基础上提供一个额外的条件分支。如果wx:if
的条件为假(false),wx:elif
提供了一个额外的条件检查并在满足该条件时渲染内容。
示例代码:
<view wx:if="{{score > 80}}">Excellent</view>
<view wx:elif="{{score > 60}}">Good</view>
<view wx:elif="{{score > 40}}">Pass</view>
<view wx:else>Fail</view>
在这个例子中:
score > 80
时,会渲染 "Excellent"score > 60
时,会渲染 "Good"score > 40
时,会渲染 "Pass"wx:elif
可以有多个,每个 wx:elif
用一个新的条件表达式来决定是否渲染这个分支。
wx:else
用于在前面的 wx:if
和 wx:elif
条件都不满足的情况下渲染内容。它不需要自己的条件表达式,因为它在前面所有的条件都不满足的情况下被渲染。
续上面的例子,如果所有给定的条件都不满足(即 score <= 40
),则会渲染 "Fail"。如果其中一个条件满足了,那么对应的内容块将被渲染,并且跳过剩下的所有wx:elif
和wx:else
块。
注意
wx:if
、wx:elif
和 wx:else
必须正确配对。一个 wx:else
必须和一个 wx:if
或 wx:elif
配对,而且它们必须是紧邻的,不能被其他的元素分隔开。wx:if
是具有“惰性”的,如果初始条件为假,它内部的块级元素和组件不会被触发和渲染,直到条件为真。如果经常需要切换的情况下,建议使用 hidden
属性来控制显示/隐藏,因为使用 hidden
属性会保持组件状态,而非重新触发组件的生命周期。使用 wx:if
/wx:elif
/wx:else
可以帮助你创建动态的、响应不同状态的用户界面,同时也需要确保你的代码保持整洁和可维护。
wx.uploadFile
是微信小程序中一个非常有用的 API,它允许开发者将本地的文件(通常是图片、音频、视频文件等)上传到开发者服务器。这个 API 非常适用于实现类似用户上传头像、分享图片等功能。
基础用法
wx.uploadFile
接收一个对象作为参数,该对象中包含一些选项来控制文件上传的行为。其中,最基础且必须的两个参数是 url
和 filePath
:
url
: 一个用来接收上传文件的服务器 URL。filePath
: 要上传文件的本地文件路径。name
: 文件对应的 key,开发者在服务器端通过这个 key 可以获取到文件二进制内容。示例代码
下面是一个基本的 wx.uploadFile
的示例代码:
wx.uploadFile({
url: "https://example.com/upload", // 开发者服务器 URL
filePath: "/path/to/file.jpg", // 本地文件路径
name: "example", // 文件对应的 key
formData: {
// 额外的表单字段
user: "test",
},
success(res) {
const data = res.data; // 服务器返回的数据
// ...
},
fail(err) {
// 上传失败的处理
},
complete() {
// 上传完成后(无论成功或失败)的回调
},
});
参数详解
除了基础用法外,wx.uploadFile
还有一些可选参数可以进一步控制上传行为:
formData
: 一个包含额外表单字段的对象。这些字段将与文件一起被发送到服务器。header
: 一个包含 HTTP 请求头信息的对象,比如可以通过这个参数设置 'content-type': 'multipart/form-data'
。success
, fail
, complete
: 三个回调函数,分别在上传成功、失败、完成(无论成功或失败)时被调用。返回值及其方法
wx.uploadFile
返回一个 UploadTask
对象,这个对象表示一个上传任务,并提供了一些方法用来控制上传流程:
abort()
: 取消上传任务。onProgressUpdate(callback)
: 监听上传进度变化事件,可以用来实现上传进度条等功能。offProgressUpdate(callback)
: 取消监听上传进度变化事件。注意点
wx.uploadFile
进行文件上传时,要注意网络状况和文件大小,尽可能在 Wi-Fi 网络下上传较大的文件,提升用户体验。在微信小程序中,open-type
是 <button>
组件的一个属性,用于指定按钮的点击行为。open-type
提供了一系列的值,用于触发不同的微信功能。以下是一些常见的 open-type
取值及其描述:
常见的 open-type
取值
contact:打开客服会话。如果希望用户在点击按钮后能够与客服进行交流,可以使用此值。
share:触发用户转发。在按钮点击事件中可以获取到一个用于自定义转发内容的对象。
getUserInfo:获取用户信息。点击按钮后,用户会收到一个获取头像昵称等信息的请求,同意后,开发者可以获得这些信息。
getPhoneNumber:获取用户手机号。点击按钮后,用户会收到一个获取手机号的请求,同意后,开发者可以获得这些信息。
launchApp:打开另一个小程序。需要在 app.json
的 navigateToMiniProgramAppIdList
字段内声明需要跳转的小程序列表。
openSetting:打开小程序设置页面。用户可以在此页面中开启或关闭某些权限。
feedback:打开“意见反馈”页面。
navigate:进行页面的跳转。
使用示例
下面是一些使用 open-type
的基本示例:
使用 open-type
实现客服消息功能:
<button open-type="contact">联系客服</button>
使用 open-type
实现用户转发功能:
<button open-type="share">分享给朋友</button>
在 Page 对象的 onShareAppMessage
函数中你可以自定义转发内容。
使用 open-type
获取用户信息:
<button open-type="getUserInfo" bindgetuserinfo="handleGetUserInfo">获取用户信息</button>
在处理函数 handleGetUserInfo
中你可以获取到用户的信息。
Page({
// ...
handleGetUserInfo(e) {
console.log(e.detail.errMsg);
console.log(e.detail.userInfo);
console.log(e.detail.rawData);
},
});
注意事项
open-type
值有不同的使用条件和效果,具体可以参考微信小程序官方文档。getUserInfo
和 getPhoneNumber
等能够获取用户数据的 open-type
时,要确保符合微信的政策和相关法规要求。在微信小程序中,form
组件是用于提交一些用户的输入信息至服务器的一个非常有用的组件。关于你提到的 bindsubmit="submitUserInfo"
,这里涉及到两个部分:form
组件的基本使用以及 bindsubmit
的具体用法。
1. form 组件
form
组件常常用来搭配各种输入组件如 input
, checkbox
, slider
等,用以提交表单数据。下面是一个基本的例子:
<form bindsubmit="submitUserInfo">
<input name="username" type="text" placeholder="请输入用户名"/>
<button type="submit">提交</button>
</form>
2. bindsubmit="submitUserInfo"
这里的 bindsubmit="submitUserInfo"
表示当用户触发表单提交事件(例如点击了类型为 submit
的按钮)的时候,会调用页面实例下名为 submitUserInfo
的方法。
在页面的 JS 代码中,你可以如下实现 submitUserInfo
方法:
Page({
submitUserInfo: function (e) {
console.log(e.detail.value); // 输出表单所有name值为key的对象
var username = e.detail.value.username; // 获取输入框内容
// 你可以在这里进行进一步的处理,例如验证输入内容的有效性,或者将数据提交到服务器等。
},
});
e.detail.value
是一个包含表单中所有 input
的对象,对象的 key 是 input
的 name
属性值,对象的 value 是用户输入的内容。注意事项
form
组件内的 input
组件有 name
属性,否则用户的输入将不会被包含在 submit
事件的 event.detail.value
中。button
组件,并设置 open-type
为 getUserInfo
。wx.showShareMenu
是微信小程序中用于触发分享功能的 API。微信小程序是微信提供的一种轻应用形式,它允许开发者创建一些在微信内运行的小型应用。wx.showShareMenu
主要用于显示微信原生的分享按钮,并允许用户将小程序的内容分享给微信好友或者分享到朋友圈。
在微信小程序的开发中,调用分享功能并自定义分享内容通常是一个常见的需求。wx.showShareMenu
使得小程序能够轻松地集成分享功能。
以下是一个基本的 wx.showShareMenu
使用方法:
wx.showShareMenu({
withShareTicket: true,
menus: ["shareAppMessage", "shareTimeline"],
});
让我们深入了解这个方法的参数:
withShareTicket
: 类型为 Boolean
,默认值为 false
。当设置为 true
时,会返回分享结果的一个加密数据(shareTicket),通常用于获取更多关于分享的信息,比如群分享的标识信息等。menus
: 类型为 Array
,默认值为 ['shareAppMessage', 'shareTimeline']
。它用于指定分享类型。shareAppMessage
代表分享给微信好友,shareTimeline
代表分享到微信朋友圈。如果你希望自定义分享内容,可以在页面的脚本部分定义 onShareAppMessage
和/或 onShareTimeline
函数:
Page({
onShareAppMessage: function (res) {
return {
title: "自定义分享标题",
path: "/page/user?id=123",
};
},
onShareTimeline: function () {
return {
title: "自定义分享朋友圈的标题",
query: "foo=bar",
};
},
});
onShareAppMessage
: 用于自定义通过“发送给朋友”方式分享出去的内容。
title
: 分享标题path
: 分享的页面路径(带参数)onShareTimeline
: 用于自定义通过“分享到朋友圈”方式分享出去的内容。
title
: 分享标题query
: 分享的页面路径上携带的查询参数在微信小程序中,onShareAppMessage
是一个用来自定义用户点击分享按钮或使用右上角菜单“转发”时所展示的分享内容的函数。这个函数允许你自定义分享标题、分享图像、分享路径等内容。此方法需要返回一个对象,用于配置分享内容。
基础用法
以下是 onShareAppMessage
的一个基础使用实例:
Page({
onShareAppMessage: function (res) {
return {
title: "自定义转发标题",
path: "/page/user?id=123",
imageUrl: "/path/to/image.jpg", // 图片路径
};
},
});
在这个实例中,当用户点击分享按钮时,他们会看到一个分享卡片,该卡片具有自定义的标题、路径和图像。
参数说明
title
: String 类型,转发标题。不填则默认使用当前小程序名称。path
: String 类型,转发的路径。需要是一个相对路径。imageUrl
: String 类型,自定义图片路径。可以是本地文件路径、代码包文件路径或者网络图片路径。不填则使用截图。在 onShareAppMessage
函数的参数 res
中,也包含了一些有用的信息,例如:
res.from
: String 类型,表示转发事件来源。button
: 页面内转发按钮;menu
: 右上角转发菜单;touchmenu
: 底部触摸菜单。res.target
: 当 from
值为 button
时,返回触发这次转发事件的 button 组件实例;否则返回 undefined。例子
下面的例子展示了一个更加具体的用法,当用户点击不同的按钮进行分享时,可以展示不同的分享内容:
Page({
onShareAppMessage: function (res) {
if (res.from === "button") {
// 来自页面内转发按钮
console.log(res.target);
}
return {
title: "自定义转发标题",
path: "/page/user?id=123",
};
},
});
通过检查 res.from
和 res.target
的值,你可以确定分享的来源,并做出相应的逻辑处理。希望这些信息能够帮助你更好地使用 onShareAppMessage
方法来自定义微信小程序的分享功能!
onShareTimeline
是微信小程序的一个生命周期函数,用于处理用户通过“分享到朋友圈”分享内容时的事件。在微信小程序中,如果你希望自定义用户分享到朋友圈的内容(比如自定义标题、分享的页面路径或者自定义图片),你可以在页面脚本中使用 onShareTimeline
函数来返回一个自定义的对象。
基础用法
下面的代码展示了 onShareTimeline
的一个基础用法:
Page({
onShareTimeline: function () {
return {
title: "自定义朋友圈分享标题",
query: "key=value",
imageUrl: "/path/to/image.jpg",
};
},
});
参数说明
在 onShareTimeline
中你可以返回一个对象,该对象可以包括以下字段:
title
: String 类型,分享到朋友圈的标题。如果不填则默认使用当前小程序名称。
query
: String 类型,分享路径中的查询字符串,必须是 key1=val1&key2=val2 的格式。从这个转发入口进入后,可通过 wx.onLaunch()
或 wx.onShow()
获取启动参数中的 query
。
imageUrl
: String 类型,自定义图片路径。可以是本地文件路径、代码包文件路径或者网络图片路径。不填则使用截图。
示例
考虑以下使用示例,当用户选择在朋友圈分享内容时,它将展示自定义的标题、图片,并在用户点击分享内容进入小程序时携带自定义的参数:
Page({
onShareTimeline: function () {
return {
title: "探索美食世界",
query: "from=shareTimeline",
imageUrl: "/images/share.jpg",
};
},
});
在这个例子中:
wx.onLaunch()
或 wx.onShow()
的回调函数中获取到 query
参数,其 from
的值将是 shareTimeline
。share.jpg
,你可以根据实际情况设置路径。通过利用 onShareTimeline
函数,你可以在用户分享你的小程序内容到朋友圈时提供更加丰富和个性化的内容。希望这些信息能够帮助你更有效地使用这个功能!
onLaunch(options)
是微信小程序的全局生命周期钩子,它不是页面级别的生命周期,而是小程序整体的生命周期。这个生命周期钩子会在小程序启动时触发,通常是在用户点击小程序图标启动小程序时执行。下面是关于 onLaunch
的详细解释:
onLaunch(options)
:options
参数包含了小程序启动时的参数信息,通常包括场景值、启动路径、分享信息等。onLaunch
是小程序全局的,只会在小程序启动时触发一次,不会随着页面切换而触发。在 onLaunch
中,你可以执行一些全局设置和初始化工作,例如初始化全局数据、登录验证、获取用户信息等操作。这个生命周期钩子通常用于确保小程序在启动时的准备工作,以便后续页面可以顺利运行。例如:
App({
onLaunch(options) {
// 在小程序启动时执行的初始化操作
console.log("小程序启动了");
// 获取用户信息
wx.getUserInfo({
success: function (res) {
console.log(res.userInfo);
},
});
},
});
微信小程序的页面生命周期钩子是一组函数,用于在不同阶段执行特定的操作。这些生命周期钩子提供了对小程序页面生命周期的控制,允许开发者在不同的阶段执行初始化、数据加载、页面展示等操作。下面是这些生命周期钩子的解释:
onLoad(options)
:
options
参数包含了页面跳转时的参数。onReady()
:
onShow()
:
onHide()
:
onUnload()
:
onPullDownRefresh()
:
wx.stopPullDownRefresh()
来停止下拉刷新动画。onReachBottom()
:
onShareAppMessage(options)
:
这些生命周期钩子允许你在不同的时机执行特定的代码,以掌握小程序页面的生命周期,实现更好的用户体验和功能交互。根据不同的需求,你可以在这些生命周期钩子中添加相应的代码来完成页面的初始化、数据加载、事件监听等操作。
wx:for
是微信小程序中的一个重要的指令,用于在 WXML 模板中进行列表渲染。它允许你遍历一个数组或对象,并将其中的每个元素渲染为对应的组件或内容。这个指令使得在小程序页面中动态展示数据变得非常方便。以下是关于 wx:for
的详细解释:
使用语法:
<view wx:for="{{array}}" wx:key="uniqueKey">
<!-- 每次迭代的内容 -->
</view>
wx:for
:这是用于指定要遍历的数组或对象的属性,可以是数组、对象等。wx:key
:指定每个迭代项的唯一标识符,通常是一个元素的唯一字段或索引。这是为了提高列表性能和避免出现渲染问题,确保每个元素都有唯一的标识。例如,假设你有一个包含学生姓名的数组 students
,你可以使用 wx:for
来将每个学生的姓名渲染到页面上:
<view wx:for="{{students}}" wx:key="id">
{{item.name}}
</view>
其中,students
是你的数据源,wx:key
指定了一个唯一标识符,这里使用了 id
字段。在每次迭代中,item
代表当前元素,你可以访问其属性,例如 item.name
来渲染学生的姓名。
需要注意的是,wx:for
是一种在小程序模板中进行循环渲染的强大工具,但要小心不要在大型列表中滥用,以免影响性能。此外,确保指定的 wx:key
是唯一的且稳定的,以避免渲染问题。
如果你需要在 wx:for
循环中执行更复杂的操作,你可以使用 wx:for-item
和 wx:for-index
来指定迭代项的别名和索引,以方便操作。例如:
<view wx:for="{{students}}" wx:key="id">
<text>索引:{{index}}</text>
<text>姓名:{{item.name}}</text>
</view>
在这个例子中,index
表示当前迭代的索引,item
表示当前迭代的元素,这样你可以更方便地访问和显示数据。
swiper
是微信小程序中的一个视图容器组件,用于实现轮播图效果,允许用户在多个图片或内容之间进行滑动切换。它非常适合用于展示广告轮播、图片列表、产品展示等需要切换多个内容的场景。下面让我来详细讲解微信小程序中的 swiper
组件以及其相关属性和用法:
基本用法:
在小程序的 WXML 文件中,你可以使用以下方式来创建一个基本的 swiper
:
<swiper indicator-dots="{{true}}" autoplay="{{true}}" interval="{{3000}}">
<swiper-item>
<image src="image1.jpg" mode="aspectFill"></image>
</swiper-item>
<swiper-item>
<image src="image2.jpg" mode="aspectFill"></image>
</swiper-item>
<!-- 可以添加更多的 swiper-item -->
</swiper>
上述代码创建了一个带有两个轮播项的 swiper
,它会自动播放,并在每个轮播项之间切换,每次切换间隔 3 秒,并显示页码指示点。
常用属性:
以下是一些常用的 swiper
组件属性,用于配置和控制轮播效果:
indicator-dots
:布尔值,是否显示轮播指示点,默认为 false
,设置为 true
则显示指示点。
autoplay
:布尔值,是否自动播放,默认为 false
,设置为 true
则自动播放。
interval
:轮播间隔时间,单位为毫秒,默认为 5000 毫秒(5 秒)。
duration
:切换动画时长,单位为毫秒,默认为 500 毫秒。
circular
:布尔值,是否开启无限循环轮播,默认为 false
,设置为 true
则开启。
current
:设置当前所在的轮播项的索引,从 0 开始计数,可以用于指定初始展示的轮播项。
swiper-item:
swiper-item
是 swiper
的子组件,用于包裹每个轮播项的内容。可以在其中放置图片、文本、按钮等内容。每个 swiper-item
对应一个轮播项。
事件:
swiper
组件支持 bindchange
事件,用于监听轮播项切换事件。可以在事件处理函数中获取到当前轮播项的索引。
<swiper
indicator-dots="{{true}}"
autoplay="{{true}}"
interval="{{3000}}"
bindchange="swiperChange"
>
<swiper-item>
<image src="image1.jpg" mode="aspectFill"></image>
</swiper-item>
<swiper-item>
<image src="image2.jpg" mode="aspectFill"></image>
</swiper-item>
</swiper>
Page({
swiperChange(event) {
// 获取当前轮播项的索引
console.log("当前轮播项索引:", event.detail.current);
},
});
注意事项:
swiper
需要包含至少 2 个 swiper-item
,否则轮播效果将无法正常工作。
图片的 src
属性可以是远程图片链接,也可以是本地图片路径。
在小程序的 WXSS 中可以自定义样式来调整轮播图的外观,包括指示点的样式、轮播项的样式等。
使用 wx:for
指令可以方便地实现动态轮播项的生成。
要确保 swiper
组件所在的页面的布局允许滑动,通常需要设置页面的高度或容器的高度,以便用户可以滑动查看不同的轮播项。
总之,swiper
组件是在微信小程序中实现轮播图效果的强大工具,你可以根据自己的需求和设计来配置和使用它,以提供更好的用户体验。
<image>
组件是微信小程序中用于显示图片的组件,它提供了不同的 mode
属性,用于控制图片的显示模式。不同的 mode
属性会影响图片在组件内部的布局和展示效果。以下是常见的 mode
属性及其作用的解释:
scaleToFill
(默认值):
<image>
组件,不保持原始图片的宽高比例,可能导致图片变形。aspectFit
:
<image>
组件内部,不会变形。<image>
组件的边界。aspectFill
:
<image>
组件,可能会裁剪图片的某一部分。<image>
组件,不会露出空白。widthFix
:
<image>
组件的宽度等比例缩放,保持原始图片的宽高比例。<image>
组件的高度,可能会导致图片顶部和底部有空白。top
:
<image>
组件的顶部居中显示,不会裁剪图片。<image>
组件不一致,可能会导致左右有空白。bottom
:
<image>
组件的底部居中显示,不会裁剪图片。<image>
组件不一致,可能会导致左右有空白。center
:
<image>
组件的中间居中显示,不会裁剪图片。<image>
组件不一致,可能会导致上下或左右有空白。left
:
<image>
组件的左侧居中显示,不会裁剪图片。<image>
组件不一致,可能会导致上下有空白。right
:
<image>
组件的右侧居中显示,不会裁剪图片。<image>
组件不一致,可能会导致上下有空白。这些不同的 mode
属性允许你根据实际需求控制图片在 <image>
组件内的展示效果,以获得最佳的用户体验。根据图片的尺寸和 <image>
组件的大小,选择适当的 mode
属性,以使图片能够在页面中得到正确的布局和展示效果。
在微信小程序中,可以使用 Component
函数来定义自定义组件,该函数接受一个配置对象作为参数,其中包含了自定义组件的属性、数据、方法等信息。
让我们逐个解释这个配置对象中的属性和选项:
externalClasses: ["space"]
:
externalClasses
是一个配置项,它用于指定可以在组件外部样式中使用的 CSS 类名。在这个例子中,指定了一个外部样式类名 "space"。properties
:
properties
是一个配置项,用于定义组件的属性(也称为组件的属性字段)。{}
。data
:
data
是一个配置项,用于定义组件内部的数据。data
为空对象 {}
。methods
:
methods
是一个配置项,用于定义组件内部的方法。methods
为空对象 {}
。showNavigationBarLoading
和 hideNavigationBarLoading
是微信小程序提供的用于显示和隐藏导航栏加载动画的方法,它们通常用于指示页面正在进行一些耗时的操作,以提醒用户等待。
showNavigationBarLoading
方法:
showNavigationBarLoading
是一个微信小程序的全局方法,用于在导航栏右侧显示加载动画。使用方式如下:
wx.showNavigationBarLoading();
hideNavigationBarLoading
方法:
hideNavigationBarLoading
也是一个微信小程序的全局方法,用于隐藏导航栏的加载动画。使用方式如下:
wx.hideNavigationBarLoading();
这两个方法通常成对使用,showNavigationBarLoading
用于开始加载数据或执行耗时操作时显示加载动画,然后在数据加载完成或操作执行完毕后使用 hideNavigationBarLoading
来隐藏加载动画。
示例:
Page({
onLoad() {
// 在页面加载时显示导航栏加载动画
wx.showNavigationBarLoading();
// 模拟一个耗时操作,比如发送网络请求
setTimeout(() => {
// 数据加载完成后隐藏导航栏加载动画
wx.hideNavigationBarLoading();
}, 2000); // 假设加载数据需要2秒
},
});
这样,在页面加载时,用户会看到导航栏右侧的加载动画,以提示页面正在加载中,当数据加载完成后,加载动画将被隐藏。这有助于提高用户体验,让用户清楚地知道页面的状态。
wx.stopPullDownRefresh()
是微信小程序中的一个方法,用于停止页面下拉刷新的动画效果。当用户在页面顶部下拉时,如果你的页面支持下拉刷新(通过设置 enablePullDownRefresh
为 true
),小程序会显示一个下拉刷新的动画。一旦你的页面完成了数据的刷新操作,你可以调用 wx.stopPullDownRefresh()
来停止这个下拉刷新的动画。
以下是 wx.stopPullDownRefresh()
方法的一些关键点:
当你的页面支持下拉刷新(在页面的配置中设置 enablePullDownRefresh: true
)时,用户可以在页面顶部下拉以触发刷新操作。
一旦你的页面完成了数据的刷新,通常在数据请求成功后,你应该调用 wx.stopPullDownRefresh()
来停止下拉刷新的动画。
如果在下拉刷新时用户松手之前执行了 wx.stopPullDownRefresh()
,动画效果会立即停止。
通常,你应该在下拉刷新的回调函数中(例如 onPullDownRefresh
生命周期函数)执行数据刷新操作,并在数据刷新完成后调用 wx.stopPullDownRefresh()
来告诉小程序停止刷新动画。
示例代码:
Page({
onPullDownRefresh() {
// 下拉刷新回调函数,通常用于重新加载数据
// 在数据加载完成后调用 wx.stopPullDownRefresh() 停止刷新动画
fetchData()
.then(() => {
// 数据加载成功后停止刷新动画
wx.stopPullDownRefresh();
})
.catch(() => {
// 数据加载失败也需要停止刷新动画
wx.stopPullDownRefresh();
});
},
});
在上述示例中,onPullDownRefresh
是下拉刷新的回调函数,当用户下拉页面时触发。在数据加载完成后,无论成功或失败,都要调用 wx.stopPullDownRefresh()
来停止刷新动画,以告诉用户刷新操作已经完成。这有助于提供更好的用户体验,让用户知道何时可以继续浏览页面。
triggerEvent
是微信小程序中的一个方法,用于触发自定义组件上的事件。它允许在自定义组件内部的某个方法中触发一个自定义事件,然后可以在页面中监听并响应该事件。
以下是 triggerEvent
方法的基本用法和一些重要概念:
基本用法:
// 在自定义组件内部的某个方法中触发一个自定义事件
this.triggerEvent("myevent", { data: "event data" });
上述代码中,this
表示自定义组件实例,triggerEvent
方法用于触发一个名为 "myevent" 的自定义事件,并传递一个包含数据的对象 { data: 'event data' }
给事件处理函数。
自定义组件内监听事件:
在自定义组件的 WXML 中,可以通过 bind:myevent
来监听 "myevent" 事件,并指定事件处理函数:
<custom-component bind:myevent="onMyEvent"></custom-component>
在上述示例中,当自定义组件触发 "myevent" 事件时,会调用名为 "onMyEvent" 的事件处理函数。
页面中监听事件:
在页面的 WXML 中,可以通过 bind:myevent
来监听自定义组件触发的事件,并指定事件处理函数:
<custom-component bind:myevent="onMyEvent"></custom-component>
在上述示例中,当自定义组件触发 "myevent" 事件时,会调用名为 "onMyEvent" 的事件处理函数,该函数需要在页面的 JavaScript 中定义。
传递数据:
通过 triggerEvent
可以传递数据给事件处理函数。在触发事件时,可以在第二个参数中传递一个包含数据的对象。例如:
this.triggerEvent("myevent", { message: "Hello, world!" });
在事件处理函数中可以通过 event.detail
来访问传递的数据:
onMyEvent(event) {
console.log(event.detail.message); // 输出: "Hello, world!"
}
通过以上方式,你可以在自定义组件内部的某个方法中触发自定义事件,并将数据传递给事件处理函数。这样可以实现自定义组件与页面之间的通信,让组件能够在特定的时机触发事件,页面可以监听并响应这些事件,从而实现更丰富的交互和功能。
wx.previewImage
是微信小程序中的一个 API 方法,用于预览图片,支持在当前页面或新页面中打开图片预览界面,允许用户在预览界面中滑动浏览图片、缩放图片、保存图片等操作。
以下是 wx.previewImage
方法的详细讲解:
基本用法:
wx.previewImage({
current: "", // 当前显示图片的链接,可选
urls: [], // 需要预览的图片链接列表,必填
});
current
(可选):表示当前显示图片的链接,用于指定预览时从哪一张图片开始显示。如果不提供此参数,则默认从第一张图片开始预览。
urls
(必填):需要预览的图片链接列表,可以是一个包含多个图片链接的数组。预览的图片将按照数组的顺序依次展示。
注意事项:
urls
参数必须为一个包含至少一张图片链接的数组,否则 previewImage
方法会报错。
在预览界面中,用户可以通过滑动图片来切换图片,也可以通过手势缩放图片大小。
用户可以在预览界面中点击右上角的保存按钮,将图片保存到手机相册。
wx.previewImage
方法可以在当前页面或新页面中打开预览界面,具体取决于当前页面的配置。如果在当前页面预览,用户可以通过手势返回上一页面;如果在新页面中预览,用户可以通过左上角的返回按钮返回上一页面。
示例:
// 在当前页面预览图片
wx.previewImage({
current: "https://example.com/image1.jpg", // 当前显示图片的链接
urls: [
"https://example.com/image1.jpg",
"https://example.com/image2.jpg",
"https://example.com/image3.jpg",
],
});
// 在新页面预览图片
wx.navigateTo({
url: "/pages/imagePreview/imagePreview?url=https://example.com/image1.jpg",
});
上述示例中,第一个调用 wx.previewImage
方法在当前页面预览图片,第二个通过 wx.navigateTo
在新页面中预览图片。在新页面预览时,需要在新页面中获取传递的图片链接参数,并在页面中调用 wx.previewImage
方法来触发预览操作。
wx.previewImage
方法通常用于实现图片点击预览功能,以提供更好的用户体验。用户可以在预览界面中自由浏览和操作图片,同时也可以保存图片到手机相册。
scroll-view
是微信小程序中的一个可滚动的视图容器组件,它允许在一个固定区域内滚动显示内容。scroll-view
通常用于实现可滚动的长列表、聊天记录、详情页等场景,以便在有限的显示区域内显示大量内容。
以下是 scroll-view
组件的主要属性和用法:
基本用法:
<scroll-view scroll-x="{{true}}" <!-- 是否允许横向滚动 -->
scroll-y="{{true}}"
<!-- 是否允许纵向滚动 -->
style="height: 300px;">
<!-- scroll-view 的高度 -->
<!-- 内容区域 -->
</scroll-view>
scroll-x
和 scroll-y
属性:用于控制是否允许横向和纵向滚动。将它们设置为 true
表示允许对应方向的滚动。
style
属性:用于设置 scroll-view
的样式,包括高度、宽度、背景颜色等。通常需要设置一个固定的高度,以确定可滚动区域的高度。
内容区域:
在 scroll-view
组件内部可以放置任何内容,例如文本、图片、列表等。当内容超过 scroll-view
的可视区域时,用户就可以通过滚动来查看内容。
<scroll-view style="height: 300px;">
<text>这是一段文本内容</text>
<image src="image.jpg"></image>
<!-- 更多内容 -->
</scroll-view>
scroll-view 的滚动事件:
scroll-view
支持一些事件,用于监听滚动事件。例如,你可以使用 bindscroll
事件来监听滚动时触发的事件,获取滚动的位置信息等。
<scroll-view style="height: 300px;" bindscroll="onScrollViewScroll">
<!-- 内容区域 -->
</scroll-view>
Page({
onScrollViewScroll(event) {
// 获取滚动的位置信息
const { scrollTop, scrollLeft } = event.detail;
console.log("scrollTop:", scrollTop);
console.log("scrollLeft:", scrollLeft);
},
});
scroll-view 的其他属性和方法:
scroll-top
和 scroll-left
属性:用于控制 scroll-view
滚动到指定的位置。
scroll-into-view
属性:指定要滚动到的某个子元素的 id,使其滚动到可视区域内。
scroll-with-animation
属性:是否使用动画滚动。
scrolltolower
和 scrolltoupper
事件:当滚动到底部或顶部时触发的事件。
scroll-view
还支持一些其他属性和方法,用于控制滚动,如 scroll-into-view
, scrollWithAnimation
, scrollTo
等。
总之,scroll-view
是微信小程序中用于实现可滚动视图的重要组件,它提供了丰富的配置选项和事件,可以用于实现各种滚动需求的页面。在开发小程序时,根据具体的需求和设计,可以使用 scroll-view
来展示滚动内容,提高用户体验。
wx.createSelectorQuery
是微信小程序中的一个用于查询 DOM 节点信息的 API。它允许你通过选择器选择页面中的 DOM 元素,并获取这些元素的位置、大小等信息,以便进行后续的操作,例如动态布局、动画效果等。
以下是 wx.createSelectorQuery
的基本用法和常见操作:
创建选择器查询实例:
要开始使用 wx.createSelectorQuery
,首先需要创建一个查询实例。通常,你可以在页面的 onLoad
生命周期中创建它:
// 在页面 onLoad 中创建选择器查询实例
Page({
onLoad() {
const query = wx.createSelectorQuery();
// 继续后续操作...
},
});
选择 DOM 元素:
使用 query.select
方法可以选择页面中的单个 DOM 元素,或者使用 query.selectAll
方法选择多个 DOM 元素。你需要传递一个选择器作为参数,以指定要选择的元素。
// 选择单个元素
query.select("#myElement").boundingClientRect();
// 选择多个元素
query.selectAll(".myElements").boundingClientRect();
查询 DOM 元素信息:
在选择了要查询的 DOM 元素后,你可以使用一系列方法来获取这些元素的信息,比如位置、大小、滚动位置等。常见的方法包括 boundingClientRect
、scrollOffset
、fields
等。
// 获取元素的位置和大小信息
query
.select("#myElement")
.boundingClientRect((rect) => {
console.log("Element Info:", rect);
})
.exec();
执行查询操作:
一旦设置好查询操作,你需要调用 exec
方法来执行查询。注意,exec
是一个异步操作,因此需要传递一个回调函数来处理查询结果。
// 执行查询操作并处理结果
query.exec((res) => {
console.log("Query Result:", res);
});
示例:
以下是一个示例,演示如何使用 wx.createSelectorQuery
获取一个元素的位置和大小信息:
Page({
onLoad() {
const query = wx.createSelectorQuery();
// 选择要查询的元素
query
.select("#myElement")
.boundingClientRect((rect) => {
console.log("Element Info:", rect);
})
.exec();
},
});
在这个示例中,wx.createSelectorQuery
创建了一个选择器查询实例,然后使用 query.select('#myElement')
选择了一个 id 为 "myElement" 的 DOM 元素,并使用 boundingClientRect
方法获取了该元素的位置和大小信息。最后,通过 query.exec
执行查询并在回调函数中处理查询结果。
通过 wx.createSelectorQuery
,你可以在小程序中方便地获取和操作 DOM 元素的信息,以实现各种交互效果和布局调整。
wx.getBackgroundAudioManager
是微信小程序提供的一个用于管理后台音频播放的 API。通过这个 API,你可以控制和管理后台音频的播放、暂停、停止,以及获取音频的状态信息等。
以下是一些常用的 wx.getBackgroundAudioManager
的方法和属性:
创建音频管理实例:
使用 wx.getBackgroundAudioManager
可以获取一个后台音频管理实例,通常需要在页面的 onLoad
生命周期中创建实例。
const audioManager = wx.getBackgroundAudioManager();
设置音频信息:
你可以设置音频的标题、歌手、封面图等信息,这些信息将在音频播放时显示在通知栏。
audioManager.title = "音频标题";
audioManager.singer = "歌手名称";
audioManager.coverImgUrl = "封面图 URL";
控制音频播放:
audioManager.src
:设置音频的播放源。audioManager.play()
:播放音频。audioManager.pause()
:暂停音频播放。audioManager.stop()
:停止音频播放。audioManager.seek(position)
:跳转到指定位置(单位:秒)继续播放。音频状态事件:
audioManager.onPlay(callback)
:监听音频播放事件。audioManager.onPause(callback)
:监听音频暂停事件。audioManager.onStop(callback)
:监听音频停止事件。audioManager.onTimeUpdate(callback)
:监听音频播放进度更新事件。audioManager.onEnded(callback)
:监听音频播放结束事件。audioManager.onError(callback)
:监听音频播放错误事件。获取音频状态信息:
audioManager.currentTime
:获取当前播放时间(单位:秒)。audioManager.duration
:获取音频总时长(单位:秒)。audioManager.paused
:获取音频是否处于暂停状态。audioManager.buffered
:获取音频已缓冲的时间范围。控制音频音量和静音:
audioManager.volume
:设置音频的音量,取值范围为 0 到 1。audioManager.muted
:设置音频是否静音。通过 wx.getBackgroundAudioManager
,你可以在小程序中实现音频播放功能,并对音频的播放状态进行监听和控制。这对于开发音乐播放器、语音导航等应用非常有用。
在微信小程序中,<video>
组件用于嵌入和播放视频内容。它允许你在小程序中集成视频播放功能,可以播放本地视频文件或在线视频流。以下是一些 <video>
组件的常见属性和用法:
<video
src="{{videoSrc}}" <!-- 视频源,可以是本地或网络链接 -->
controls="{{true}}" <!-- 是否显示视频控制条 -->
autoplay="{{false}}" <!-- 是否自动播放视频 -->
poster="{{posterSrc}}" <!-- 视频封面图 -->
initial-time="{{0}}" <!-- 初始播放时间,单位为秒 -->
direction="{{0}}" <!-- 视频方向,0:正常,90:逆时针旋转90度,180:旋转180度,270:逆时针旋转270度 -->
danmu-list="{{danmuList}}" <!-- 弹幕列表,可用于显示弹幕 -->
danmu-btn="{{false}}" <!-- 是否显示弹幕开关按钮 -->
enable-danmu="{{false}}" <!-- 是否允许发送弹幕 -->
show-center-play-btn="{{true}}" <!-- 是否显示中间的播放按钮 -->
auto-pause-if-navigate="{{true}}" <!-- 是否在页面切换时自动暂停视频 -->
auto-pause-if-open-native="{{true}}" <!-- 是否在跳转到原生播放器时自动暂停视频 -->
vslide-gesture="{{false}}" <!-- 是否启用纵向滑动手势 -->
hslide-gesture="{{false}}" <!-- 是否启用横向滑动手势 -->
show-play-btn="{{true}}" <!-- 是否显示播放按钮 -->
show-center-play-btn="{{true}}" <!-- 是否显示中间的播放按钮 -->
show-mute-btn="{{true}}" <!-- 是否显示静音按钮 -->
show-captions-btn="{{true}}" <!-- 是否显示字幕按钮 -->
show-play-progress="{{true}}" <!-- 是否显示播放进度 -->
object-fit="{{contain}}" <!-- 视频的缩放模式,可选值:fill, contain, cover -->
bindplay="handleVideoPlay" <!-- 绑定播放事件处理函数 -->
bindpause="handleVideoPause" <!-- 绑定暂停事件处理函数 -->
bindended="handleVideoEnded" <!-- 绑定视频播放结束事件处理函数 -->
bindtimeupdate="handleVideoTimeUpdate" <!-- 绑定播放时间更新事件处理函数 -->
/>
一些常见的用法和注意事项:
src
属性用于指定视频源,可以是本地视频文件路径或网络视频链接。controls
属性决定是否显示视频控制条,允许用户控制播放、暂停、音量等。autoplay
属性可以设置视频是否自动播放。poster
属性用于设置视频封面图,当视频未播放时显示。danmu-list
属性可以用于显示弹幕,提供弹幕列表。以下是一个简单的示例,展示了一个基本的 <video>
组件的使用:
<video src="{{videoSrc}}" controls autoplay poster="{{posterSrc}}" bindplay="handleVideoPlay" bindpause="handleVideoPause" bindended="handleVideoEnded"></video>
Page({
data: {
videoSrc: "https://example.com/sample.mp4",
posterSrc: "https://example.com/poster.jpg",
},
handleVideoPlay() {
console.log("Video started playing");
},
handleVideoPause() {
console.log("Video paused");
},
handleVideoEnded() {
console.log("Video ended");
},
});
这个示例中,<video>
组件会自动播放,用户可以控制播放和暂停,并且在视频播放结束时触发相应的事件处理函数。
请注意,视频播放功能还涉及到网络请求和资源加载,因此在实际使用中需要考虑网络状态和性能优化,以提供良好的用户体验。
在微信小程序中,mark
是一个用于识别触发事件的目标节点以及承载自定义数据的属性。这个属性的引入版本是基础库 2.7.1 以上,它可以用于标记具体触发事件的节点,并且可以在事件处理函数中获取这些信息。
下面是关于 mark
的一些主要信息和用法:
标记触发事件的目标节点:
mark
来识别事件的确切触发节点。这对于需要区分触发节点的情况非常有用。自定义数据承载:
mark
还可以用于携带一些自定义数据,类似于 dataset
,这些数据可以在事件处理函数中访问。事件回调函数:
mark
会被合并,并返回给事件回调函数。这意味着你可以在事件处理函数中获取触发节点的信息和自定义数据。下面是一个示例,展示了如何使用 mark
标记触发事件的节点并获取自定义数据:
<view>
<button mark="button1" data-name="Button 1" bindtap="handleTap">Button 1</button>
<button mark="button2" data-name="Button 2" bindtap="handleTap">Button 2</button>
</view>
Page({
handleTap(event) {
const mark = event.currentTarget.dataset.mark;
const dataName = event.currentTarget.dataset.name;
console.log(`点击了标记为 ${mark} 的按钮,按钮名称是:${dataName}`);
},
});
在这个示例中,两个按钮都设置了 mark
属性,并附带了 data-name
自定义数据。当任何一个按钮被点击时,handleTap
事件处理函数会获取触发按钮的 mark
属性和自定义数据,从而区分触发的是哪个按钮,并获取按钮的名称。
通过 mark
属性,你可以更容易地区分事件触发源并携带自定义数据,以实现更精确和灵活的事件处理。
wx.reLaunch
、wx.navigateTo
、wx.redirectTo
和 wx.switchTab
是微信小程序中用于页面跳转的不同方法,它们各自具有不同的特点和使用场景。下面我将解释它们的区别和适用场景:
wx.reLaunch:
wx.reLaunch
用于关闭所有页面,然后打开新页面。它会将当前页面栈清空,不保留任何页面历史记录,然后打开指定页面。示例:
wx.reLaunch({
url: "/pages/home/home",
});
wx.navigateTo:
wx.navigateTo
用于打开新页面,并保留当前页面在页面栈中,用户可以通过左上角返回按钮返回前一个页面。示例:
wx.navigateTo({
url: "/pages/detail/detail?id=123",
});
wx.redirectTo:
wx.redirectTo
用于关闭当前页面,然后打开新页面。它不保留当前页面在页面栈中,用户无法返回到前一个页面。示例:
wx.redirectTo({
url: "/pages/profile/profile",
});
wx.switchTab:
wx.switchTab
用于跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。示例:
wx.switchTab({
url: "/pages/home/home",
});
总结:
wx.reLaunch
时,页面栈会被清空,适用于跳转到小程序的首页或需要关闭所有页面的情况。wx.navigateTo
时,可以保留页面栈,适用于多层级页面之间的跳转。wx.redirectTo
时,会关闭当前页面,适用于需要替换当前页面内容的情况。wx.switchTab
时,通常用于底部 tabBar 导航切换,关闭其他非 tabBar 页面。根据你的具体需求和页面导航结构,选择适合的跳转方法来实现你的功能。