总结:USONB(简单记忆:You are so NB)
U:undefined
S:string、symbol
O:object
N:null、number
B:boolean
JS函数分为三类:命名函数、匿名函数、自执行函数。
function f1 () { ...... } // 命名函数
const f2 = function () { ...... } // 匿名函数
(function (n1, n2) { ...... })(10, 20) // 自执行函数(只执行一次)
const school = { name: 'new East' };
const cities = { xiaoqu: ['北京', '上海', '深圳'] };
Object.setPrototypeOf(school, cities);
Object.getPrototypeOf(school); // 此方法用于获取原型对象
// Object.is方法判断两个值是否完全相等
Object.is(120, 120); // true
Object.is(NaN, NaN); // true
注意:NaN === NaN // false
// 开方
Math.sqrt(x * x + y * y);
// 反正弦(效果图如下)
Math.asin(y / z) / Math.PI * 180;
// 幂(注意:**为ES7的写法)
Math.pow(10, 3) == 10 * 10 * 10 == 10 ** 3;
// 去掉一个数的小数部分
Math.trunc(3.5); // 3
// 判断一个数是否为正数、零或负数
Math.sign(100); // 1
Math.sign(0); // 0
Math.sign(-200); // -1
数组去重:
const rest = new Set([1, 2, 3, 4, 4]);
[...rest]; // [1, 2, 3, 4]
rest.size; // 4
rest.add(5); // 往集合中添加一项
rest.delete(3); // 删除集合中指定某一项
rest.has(2); // 判断集合中是否存在某一项
rest.clear(); // 清空集合
并集:
const a = new Set([1, 2, 3]);
const b = new Set([4, 2, 3]);
const union = [...new Set([...a, ...b])]; // [1, 2, 3, 4]
交集:
let interesct = new Set([...a].filter(item => b.has(item)));
interesct = [...interesct]; // [2, 3]
const obj = {
[Symbol('name')]: '一斤代码',
age: 18,
title: 'engineer'
};
Object.keys(obj); // ['age', 'title']
Object.getOwnPropertySymbols(obj); // [Symbol('name')]
Reflect.ownKeys(obj); // ['age', 'title', Symbol('name')]
对象添加Symbol类型的属性:
// 方法一:
const game = {
name: "狼人杀",
[Symbol('say')]: function () { console.log('开始游戏吧'); },
[Symbol('zibao')]: function () { console.log('准备自爆啦'); }
}
// 方法二:
const obj = { ... } // 此处代码不可见
const methods = {
up: Symbol(),
down: Symbol()
}
obj[methods.up] = function () { ... }
obj[methods.down] = function () { ... }
function fn (a, b, ...args) { // ...args参数一般放在最后
console.log(a, b, args);
}
fn (1, 2, 3, 4, 5); // 1, 2, [3, 4, 5]
需求:采用面向对象的思想遍历对象中的数组的每一项值
const banji = {
name: '高三一班',
stus: ['小明', '小赵', '小李', '小钱'],
[Symbol.iterator]: function () {
let index = 0;
return {
next: () => {
if (index < this.stus.length) {
const result = { value: this.stus[index], done: false };
index++; // 下标自增
return result;
} else return { value: undefined, done: true };
}
}
}
};
for (let v of banji) {
console.log(v); // 小明小赵小李小钱
}
function *gen () {
console.log('111');
yield '字符串1';
console.log('222');
yield '字符串2';
console.log('333');
yield '字符串3';
console.log('444');
}
for (const v of gen()) {
console.log(v);
}
const iterator = gen();
console.log(iterator.next()); // 111(换行){ value: "字符串1", done: false }
// next方法可以传入实参
function *gen (arg) {
console.log(arg);
const one = yield 111;
console.log(one);
const two = yield 222;
console.log(two);
const three = yield 333;
console.log(three);
}
// 参数将作为上一个yield语句的整体返回结果
const iterator = gen('AAA');
console.log(iterator.next());
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));
// 打印结果:
// AAA
// { value: 111, done: false }
// BBB
// { value: 222, done: false }
// CCC
// { value: 333, done: false }
// DDD
// { value: undefined, done: true }
// 生成器函数实例
function one () {
setTimeout(() => {
console.log('111');
iterator.next();
}, 1000);
}
function two () {
setTimeout(() => {
console.log('222');
iterator.next();
}, 1000);
}
function three () {
setTimeout(() => {
console.log('333');
iterator.next();
}, 1000);
}
function *gen () {
yield one();
yield two();
yield three();
}
const iterator = gen();
iterator.next(); // 每隔一秒打印一个函数的值
function getUsers () {
setTimeout(() => {
iterator.next('用户数据');
}, 1000);
}
function getOrders () {
setTimeout(() => {
iterator.next('订单数据');
}, 1000);
}
function getGoods () {
setTimeout(() => {
iterator.next('商品数据');
}, 1000);
}
function *gen () {
const users = yield getUsers();
const orders = yield getOrders();
const goods = yield getGoods();
}
// 调用生成器函数
const iterator = gen();
iterator.next(); // { value: undefined, done: false }
class Phone {
// 构造方法
constructor (brand, price) {
this.brand = brand;
this.price = price;
}
// 方法
call () { console.log('手机型号是', this.brand); }
}
const onePlus = new Phone('1+', 1999);
console.log(onePlus); // Phone { brand: "1+", price: 1999 }
onePlus.call(); // 手机型号是1+
class Phone {
get price () {
console.log('手机的价格是xxx');
return 'metoo';
}
set price (newVal) {
console.log('手机的价格修改了');
}
}
const s = new Phone();
console.log(s.price); // get函数的返回值是这个属性的值
s.price = 'free';
// 打印结果:手机的价格是xxx(换行)metoo(换行)手机的价格修改了(换行)"free"
class Phone {
// 构造方法
constructor (brand, price) {
this.brand = brand;
this.price = price;
}
// 父类成员属性
call () {
console.log('手机可以打电话');
}
}
class SmartPhone extends Phone {
// 构造方法
constructor (brand, price, color, size) {
super(brand, price);
this.color = color;
this.size = size;
}
photo () {
console.log('手机可以拍照');
}
}
const xiaomi = new SmartPhone('小米', 799, '黑色', '4.7inch');
xiaomi.call(); // 手机可以打电话
xiaomi.photo(); // 手机可以拍照
// 手机
function Phone (brand, price) {
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function () {
console.log('这是一个方法');
}
// 智能手机
function SmartPhone (brand, price, color, size) {
Phone.call(this, brand, price);
this.color = color;
this.size = size;
}
// 设置子级构造函数的原型
SmartPhone.prototype = new Phone;
SmartPhone.prototype.constructor = SmartPhone; // 此行代码可省略
// 声明子类的方法
SmartPhone.prototype.photo = function () {
console.log('这是另外一个方法');
}
const chuizi = new SmartPhone('锤子', '2499', '黑色', '5.5inch');
console.log(chuizi); // { brand: "锤子", price: "2499", color: "黑色", size: "5.5inch" }
// 引入fs模块
const fs = require('fs');
// 使用promise实现
const p = new Promise((resolve, reject) => {
fs.readFile('文件1地址', (err, data) => {
resolve(data);
});
});
p.then(value => {
return new Promise((resolve, reject) => {
fs.readFile('文件2地址', (err, data) => {
resolve([value, data]);
});
});
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile('文件3地址', (err, data) => {
value.push(data);
resolve(value);
});
});
}).then(value => {
console.log(value);
});
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', '请求地址');
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) resolve(xhr.response);
else reject(xhr.status);
}
}
});
p.then(function (value) {
console.log(value);
}, function (reason) {
console.log(reason);
});
<div><slot>后备内容slot>div>
<child1>这是一个匿名插槽child1>
<div>
<slot name="title">这里填写标题slot>
<slot name="subtitle">这里填写小标题slot>
div>
<child2>
<div slot="title">这是一个页面大标题div>
<div slot="subtitle">这是一个页面小标题div>
child2>
<div>
<slot name="title">这里填写标题slot>
<slot name="subtitle">这里填写小标题slot>
div>
<child3>
<template v-slot:title>这是一个页面大标题template>
<template v-slot:subtitle>这是一个页面小标题template>
child3>
<div>
<slot :foo="foo">slot>
div>
<child4>
<template v-slot:default="scope">来自子组件数据:{{scope.foo}}template>
child4>
获取State中的数据(两种方法):
// 方法一
this.$store.state.params; // 注:params表示变量名
// 方法二
import { mapState } from 'vuex';
computed: {
...mapState(['params1', 'params2']) // 注:params1和params2均表示变量名
}
this.params1 // 使用时这样写
// 先定义
setStr (state) {
return state.params.slice(0, 2); // params表示在State中定义的变量
}
// 后使用(HTML代码和JS代码)
<div>{{setStr}}</div>
import { mapGetters } from 'vuex';
computed: {
...mapGetters(['setStr'])
}
// HTML代码(此处省略v-for遍历代码)
<button @click="btn(item.name)"></button>
// JS代码(VueX代码)
state: { // 在State中定义变量
arr: [{ id: 1, name: '张三' }, { id: 2, name: '李四' }, { id: 3, name: '王五' }],
username: ''
},
mutations: { // 在Mutations中定义方法
setName (state, name) {
state.username = name;
}
}
// JS代码(使用VueX)
import { mapState, mapMutations } from 'vuex';
computed: {
...mapState(['arr', 'username'])
},
methods: {
...mapMutations(['setName'])
btn (name) {
this.setName(name); // 注意:传递多个值时,需要转化为object对象格式
}
}
注意:若需要进入某个页面就执行mutations中的方法,可在main.js中执行以下代码:
import store from './store';
store.commit('setName');
// JS代码(VueX代码)
state: { // 在State中定义变量
count: 0, // 购买数量
totalPrice: 0 // 总价
},
mutations: { // 在Mutations中定义方法
add (state) {
state.count++;
this.commit('total');
},
total (state) {
state.totalPrice = state.count * 10;
}
},
actions: { // 在Actions中提交mutation
addFn ({commit}) {
commit('add'); // 注意:传递多个值时,需要转化为object对象格式
}
}
注意:
1、action提交的是mutation,而不是直接变更状态
2、action可以包含任意异步操作
// VueX代码:假设category.js、shoppingCart.js和my.js均包含以下代码:
export default {
state: { ... },
getters: { ... },
mutations: { ... },
actions: { ... }
}
// VueX代码:将上述几个文件引入:
import category from './modules/category.js';
import shoppingCart from './modules/shoppingCart.js';
import my from './modules/my.js';
export default {
modules: {
category, shoppingCart, my
}
}
// HTML代码:
<div>{{count}}</div>
// JS代码:
import { mapState } from 'vuex';
export default {
computed: {
...mapState({ count: state => state.shoppingCart.count }) // 假设count变量在shoppingCart.js中已定义
}
}
wx.showLoading({ title: '加载中...' });
wx.hideLoading();
<view wx:for="{{arrList}}" wx:for-item="ite" wx:for-index="count"></view>
注意:在数据循环时,小程序内部已经封装好了item和index,可以直接使用。若需要更换名称,则需要使用wx:for-item="新变量"和wx:for-index=“新变量”。
wx.setNavigationBarTitle({ title: "标题名称" });
// 首先需要配置json文件
"enablePullDownRefresh": true
"backgroundTextStyle": "dark" // 可选项,用于设置刷新时三个点的颜色
// 其次需要在js中编写如下代码
onPullDownRefresh () { // 下拉刷新
wx.showNavigationBarLoading(); // 可选项,开启头部刷新状态
wx.stopPullDownRefresh(); // 数据加载完毕,隐藏下拉刷新状态
wx.hideNavigationBarLoading(); // 可选项,隐藏头部刷新状态
}
onReachBottom () { ... } // 上滑刷新
// 子组件child
this.triggerEvent('updateData', { data: 10 });
// 父组件
<child bind:updteData="update"></child>
// 设置角标
wx.setTabBarBadge({
index: 2, // 第几个tab
text: String(shoppingCartArr.length)
});
// 移除角标
wx.removeTabBarBadge({
index: 2
});
// 定义变量
data: {
startX: 0,
startY: 0
},
// 定义方法
touchstart (e) { // 开始触摸时
this.data.shoppingCartArr.forEach(item => {
if (item.isTouchMove) item.isTouchMove = false;
// 开始触摸时将所有商品的删除按钮重置
this.setData({
startX: e.changedTouches[0].clientX,
startY: e.changedTouches[0].clientY
});
});
},
touchmove (e) { // 手指滑动时
const index = e.currentTarget.dataset.index;
// 开始的x和y坐标
const startX = this.data.startX;
const startY = this.data.startY;
// 移动的x和y坐标
const touchMoveX = e.changedTouches[0].clientX;
const touchMoveY = e.changedTouches[0].clientY;
// 调用计算角度方法
const angel = this.angel({ x: startX, y: startY }, { x: touchMoveX, y: touchMoveY });
// 遍历数组中的所有对象
this.data.shoppingCartArr.forEach((item, i) => {
item.isTouchMove = false;
// 滑动角度>30°则直接return
if (Math.abs(angel) > 30) return;
// 匹配
if (i == index) {
if (touchMoveX > startX) item.isTouchMove = false; // 右滑
else item.isTouchMove = true; // 左滑
}
});
},
angel (start, end) {
const _x = end.x - start.x;
const _y = end.y - start.y;
// 返回角度Math.atan()返回数字的反正切值
return 360 * (Math.atan(_y / _x) / (2 * Math.PI));
}
// 步骤一:获取openid
wx.login({
success: (res) => {
const appid = '这是你的appid';
const secret = '这是你的secret';
wx.request({
url: '这里是你的请求地址',
success (res) {
const openid = res.data.openid;
this.wechatPay(openid);
}
});
}
});
// 步骤二:调用支付接口
wechatPay (openid) {
wx.request({ // 发起后端接口请求
url: '这里是你的请求地址',
methods: 'POST',
data: {
openid: openid // 这里填写后端需要的参数
},
success (res) {
wx.requestPayment({
appId: res.data.appId,
timeStamp: res.data.timeStamp,
nonceStr: res.data.nonceStr,
package: res.data.package,
signType: res.data.signType,
paySign: res.data.paySign,
success (res) {
wx.showToast({ title: '支付成功' });
},
fail () {
wx.showToast({ title: '支付失败' });
}
});
}
});
}
View(页面HTML)
ViewModel(核心调度协调器)用于数据双向绑定
Model(单页面静态数据)
注意:三者之间是双向箭头
应用生命周期:
onLaunch —— 初始化完成时触发(全局只触发一次)
onShow —— uni-app启动触发,或从后台进入前台(会多次触发)
onHide —— uni-app从前台进入后台(会多次触发)
onError —— uni-app报错时触发
页面生命周期:
onLoad —— 不会多次触发
onShow —— 多次触发
onReady —— 页面初次渲染完成时触发,不会多次触发
onHide —— 多次触发
onUnload —— 监听页面卸载
注意: tabBar页面展现过一次就保留在内存中,再次切换tabbar页面,只会触发每一个页面的onShow方法,不会再触发onLoad方法。
tabBar至多展示5个,至少展示2个。
"tabBar": {
"color": "文字默认颜色",
"selectedColor": "文字选中颜色",
"list": [{ "text": "标题", "pagePath": "页面路径" }, { ... }]
}
公用样式在globalStyle中配置。
"globalStyle": {
"navigationBarTextStyle": "导航栏标题颜色及状态栏前景颜色,仅支持black/white",
"navigationBarTitleText": "导航栏标题文字内容",
"navigationBarBackgroundColor": "导航栏背景颜色(同状态栏背景色)",
"backgroundColor": "下拉显示出来的窗口的背景色"
}
所有页面需要在pages中配置。
"pages": [
{ "path": "页面路径", "style": { "enablePullDownRefresh": true },
{ ... }
]
<view></view>
// hover-class表示点击后加上指定的类
// hover-stop-propagation表示禁止事件冒泡
<button></button>
// size表示按钮大小
// plain表示按钮镂空(无背景颜色,只有描边)
// disabled表示禁用按钮
<image></image>
// mode="aspectFit"
// mode="aspectFill"
注意:无论XXX是否大小写,在js获取时均为小写。
// html代码
<view :data-userId="数值"></view>
// js代码
e.currentTarget.dataset.userid // 这里的userid每个字母均为小写
@import url("css文件相对路径");
注意: 不能使用*选择器;字体引用推荐使用以~@开头的绝对路径
// pages.json部分配置项
"path": "...",
"style": {
"app-plus": {
"titleNView": {
"type": "transparent",
"buttons": [{ "type": "share" }]
}
}
}
// js部分代码
uni.setNavigationBarColor({ // 通过代码设置导航栏
frontColor: '#fff',
backgroundColor: '#000'
});
onPullDownRefresh () { ... }
// 该方法与data(){}等方法同级
// 当数据更新完成后,使用uni-stopPullDownRefresh()方法结束刷新
// 也可以使用uni-startPullDownRefresh()方法手动下拉刷新
onReachBottom () { ... }
// 该方法与data(){}等方法同级
// 可以使用onReachBottomDistance来设置距离页面底部还剩多少间距时触发该方法
uni.setStorage
uni.getStorage
uni.removeStorage
uni.setStorageSync
uni.getStorageSync
uni.removeStorageSync
uni.chooseImage
uni.previewImage
// 1、HTML在标签上新增longpress事件
// 2、JS主要代码
uni.showActionSheet({
itemList: ['保存图片', '分享到微信'],
success: (res) => {
if (res.tapIndex == 0) {
uni.downLoadFile({
url: '图片地址',
success: (result) => {
const tempFilePath = result.tempFilePath; // 图片临时路径
uni.saveImageToPhotosAlbum({ // 保存图片至本地相册
filePath: tempFilePath,
success: () => {
uni.showToast({ title: '保存成功' });
}
});
}
});
}
}
});
小程序中用户点击分享后,在JS中定义onShareAppMessage处理函数,设置该页面的分享信息。
注意:此函数在微信小程序、百度小程序、字节跳动小程序和QQ小程序中生效。
onShareAppMessage (res) { // 此函数与onLoad()函数同级
return {
title: '标题',
path: '/pages/xxx/xxx?id=' + id //这里的参数根据需要添加即可
};
}
// 首先需要设置appid和appsecret
mainfest.json -> App SDK配置 -> 分享微信消息及朋友圈 -> 填写appid和appsecret
// 监听导航栏的按钮
onNavigationBarButtonTap (e) { // 与onLoad()同级
const index = e.index;
if (index == 0) { // index为0则分享
uni.share({
provider: 'weixin',
scene: 'WXSenceTimeline',
type: 0,
href: '完整的url',
title: '这里填写标题',
summary: '简介',
imageUrl: '封面/图片url',
success: (res) => {}
});
}
}
// #ifdef MP
console.log('这里的JS代码只在小程序中生效');
// #endif
/* #ifdef H5 */
.content { 这里的CSS代码只在H5中生效 }
/* #endif */
<!-- #ifdef MP -->
这里的HTML代码只在小程序中生效
<!-- #endif -->
<!-- #ifndef H5 -->
这里的HTML代码不在H5中生效
<!-- #endif -->
// html代码
<video id="mymovie"></video>
// js代码
onReady () {
this.videoContext = uni.createVideoContext('mymovie');
}
onShow () {
if (this.videoContext) this.videoContext.play(); // 当页面展示时,播放视频(也可手动控制视频播放,就无需此行代码)
}
onHide () {
this.videoContext.pause();
}
// html代码
<video
@playing="meIsPlaying"
v-for="item in hotTrailerArr"
:key="item.id"
:id="item.id"
:data-playingindex="item.id"
:src="item.src"
:poster="item.poster"></video>
// js代码(播放一个视频,需暂停其他视频)
meIsPlaying (e) {
let trailerId = '';
if (e) {
trailerId = e.currentTarget.dataset.playingindex;
this.videoContext = uni.createVideoContext(trailerId);
}
for (let i = 0; i < this.hotTrailerArr.length; i++) {
const temp = this.hotTrailerArr[i].id;
if (temp != trailerId) uni.createVideoContext(temp).pause();
}
}
// html代码
<view :animation="animationData" style="opacity: 0;"></view>
// js代码
data () {
animationData: {}
},
onLoad () {
this.animation = uni.createAnimation();
},
onUnload () {
this.animationData = {};
},
methods: {
// 创建点赞动画
praiseMe () {
// 构建动画数据,并通过step表示这组动画的完成
this.animation.translateY(-60).opacity(1).step({ duration: 400 });
// 导出动画数据到view数据,实现组件动画效果
this.animationData = this.animation.export();
// 还原动画
setTimeout(() => {
this.animation.translateY(0).opacity(0).step({ duration: 0 });
this.animationData = this.animation.export();
}, 500);
}
}
order: 0;
flex-shrink: 0;
align-self: center;
<NavLink to="/home" />
<NavLink to="/about" />
<Switch>
<Route exact path="/home" component={Home} />
<Route exact path="/about" component={About} />
<Redirect to="/home" />
Switch>
<Link to={`/home/${item.id}/${item.name}`}>一个路由链接Link>
<Route path="/home/:id/:name" component={Home} />
const { id, name } = this.props.match.params
一个路由链接Link>
<Route path="/home" component={Home} />
import qs from 'querystring'
const { search } = this.props.location
const { id, name } = qs.parse(search.slice(1))
一个路由链接Link>
<Route path="/home" component={Home} />
const { id, name } = this.props.location.state
// html代码
<button onClick={() => this.goPage(item.id, item.name)}>
// js代码
goPage = (id, name) => {
this.props.history.replace(`/home/${id}/${name}`) // params传参,这里的replace也可换成push方法
// this.props.history.replace(`/home?id=${id}&name=${name}`) // search传参
// this.props.history.replace(`/home`, { id, name }) // state传参
}
/*
提示:
1、后退一页this.props.history.goBack()
2、前进一页this.props.history.goForward()
3、指定跳转几页this.props.history.go(),小括号内填写正数表示前进几页,填写负数表示后退一页
*/
import { withRouter } from 'react-router-dom'
class Header extends React.Component {
render () {} // 此处省略该组件里的代码
}
export default withRouter(Header)
// withRouter可以加工一般组件,使一般组件具备路由组件所特有的API。简言之,可以在该组件中使用this.props.history.xxx等一些方法
// withRouter的返回值是一个新组件