css动画
动画原理
/* 同时设置多个变换属性,用空格隔开 */
transform: rotate(180deg) translateX(100px) scale(0.5);
/* transform 的实现原理类似于矩阵,先旋转后平移和先平移后旋转结果是不同的 */
transform: translateX(100px) rotate(180deg) scale(0.5);
rotate(180deg)旋转角度
translateX(100px)沿着X轴平移100像素
scale(0.5)等比例缩放
skew(30deg)倾斜角度
transform-origin: 50px 100px;
/* 设置transform的原点 */
/* 原点的位置会影响旋转的圆心,缩放的位置 */
/* 值的带选项:center, top, bottom, left, right, 还可以写具体的长度值 */
/* transform-origin: center;
/ / 原点若x值和y值都为0,代表的是元素左上角的位置 */
/* 第一参数值代表横向移动的距离,正数代表向右移动,负数代表向左移动 */
/* 第二参数值代表纵向移动的距离,正数代表向下移动,负数代表向上移动 */
过渡动画
transition: all 2s linear;
/* transition复合属性可以拆解成以下属性 */
/* 过渡属性:声明一个需要产生过渡动画的属性 */
/* 可以同时声明多个属性,属性之间用逗号隔开 */
/* 待选项:
all: 代表所有属性
none: 没有任何属性
*/
transition-property: opacity, transform;
transition-property: all;
/* 补间动画的时长 */
transition-duration: 1s;
transition-duration: 1000ms;
/* 补间动画的速度曲线 */
/* 带选项:
linear: 匀速播放动画
ease-in: 慢进匀速出
ease-out: 匀速进慢出
ease-in-out: 慢进慢出
steps(n): 声明有n个过渡阶段
*/
transition-timing-function: linear;
/* 除了使用预制带选项,也可以手动赋值如下: */
transition-timing-function: cubic-bezier(0.76, 0.19, 0.19, 0.8);
/* steps 函数 */
transition-timing-function: steps(5);
/* 延迟播放动画的时间 */
transition-delay: 1s;
/* 使用transition属性设置所有的过渡动画属性 */
/* 属性顺序如下:过渡属性名 过渡时长 速度曲线 延迟时间 */
transition: all 3s ease-in-out 2s;
transition -property:过度属性
transition -duration:过度动画时长
transition-timeing-function:过度动画的运动曲线
transition-delay:过度动画的延迟时间
过渡动画事件
// 过渡动画事件
// 过渡动画播放完成事件
box.addEventListener('transitionend', ev => {
console.log(ev);
console.log('播放结束');
})
box.addEventListener('transitionstart', ev => {
console.log(ev);
console.log('开始播放');
})
box.addEventListener('transitionrun', ev => {
console.log('run');
})
transitionend:过度动画播完触发
transitionstart:过度动画开始播完触发
transitionrun:过度动画运行时播完触发
animation动画
/* 动画名称 */
/* 作用:用于告诉浏览器,该动画应用哪一个动画关键帧序列 */
animation-name: move;
/* 动画播放时长 */
animation-duration: 2s;
/* 动画播放的速度曲线 */
animation-timing-function: linear;
/* 延迟播放的时间 */
/* animation-delay: 1s; */
/* 动画播放次数 */
/* 带选项:
infinite: 无限循环播放
*/
/* animation-iteration-count: infinite; */
/* animation-iteration-count: 2; */
/* 动画播放方向 */
/* 带选项:
normal:正向播放
reverse: 反向播放
alternate: 正向播放一次然后反向再播放一次
alternate-reverse: 反向播放一次然后正向再播放一次
*/
/* animation-direction: alternate-reverse; */
/* 播放结束后,元素的最终状态模式 */
/*
带选项:
forwards:动画播放完后,保留最后一帧的状态
backwards:动画播放完后,保留第一帧的状态
both:动画播放完后,保留第一帧和最后一帧的状态和
*/
animation-fill-mode: forwards;
/* 可以定义复合属性,取代上面的所有属性 */
/* 赋值顺序,可以参考如下顺序 */
/* duration | timing-function | delay | iteration-count | direction | fill-mode | play-state | name */
/* duration | timing-function | delay | name */
/* duration | name */
animation: move 2s linear 0s forwards;
}
/* 关键帧:动画播放时的几个关键状态 */
/* 序列:有序的队列 */
/* 定义一个关键帧序列 如下: */
/* 使用@keyframes定义关键帧序列,后面参数为:动画名 */
@keyframes move {
/* 起始状态 */
/* from { */
0% {
transform: translateX(0);
color: #000;
font-size: 16px;
}
/* 用百分比定义中间状态 */
50% {
transform: translateX(1000px);
color: pink;
font-size: 32px;
}
/* 结束状态 */
/* to { */
100% {
transform: translateX(500px);
color: green;
font-size: 64px;
}
}
btn.addEventListener('click', () => {
if (!box.classList.contains('active')) {
box.classList.add('active')
}
})
box.addEventListener('animationend', () => {
console.log('动画播放完成');
})
box.addEventListener('animationstart', () => {
console.log('动画开始播放');
})
box.addEventListener('animationiteration', () => {
console.log('动画重复播放');
})
动画事件一般用的最多的是animationend
渐变色和响应式布局
/* 线性渐变色 */
/* 注意:渐变色的值,适用于 background-image 属性,而不是 background-color */
/* linear-gradient
第一个参数: 渐变的方向,也可以是个角度值
默认方向为: to bottom
后续颜色参数可以追加一个距离值
*/
/* background-image: linear-gradient(to right, red, yellow 100px, green 200px); */
background-image: linear-gradient(30deg, red, red 100px, blue 100px, blue 200px, black 200px);
/* 径向渐变 */
background-image: radial-gradient(red, yellow);
background-image: radial-gradient(red, red 100px, yellow 100px, yellow 200px, black 200px);
/* 重复线性渐变 */
background-image: repeating-linear-gradient(to right, black, black 50px, white 50px, white 100px);
/* 重复径向渐变 */
background-image: repeating-
响应式布局
/* 什么是页面的响应式?
页面的元素样式会根据页面的宽度做出变化
*/
/* 如何实现响应式? */
/* 使用媒体查询,来实现响应式布局 */
/* 媒体查询的作用:当媒体查询条件成立时,将应用花括号中代码块的样式 */
/* 语法:@media media-type and (condition1) and (condition2) */
/* 媒体类型 media-type:
备选项
all: 所有设备
print:打印机的预览模式
screen:显示屏
speech:语音合成器
*/
/* min-width: 屏幕最小宽度 */
@media screen and (min-width: 700px) {
.box {
background-color: #f00 !important;
}
}
/* max-width: 屏幕最大宽度 */
@media screen and (max-width: 1000px) {
.box {
background-color: #00f !important;
}
}
jquery
jquery是jquery是一个js的工具库
针对页面元素,jquery提供了很多操纵页面元素的函数
还有一些工具函数,方便一些运算
jquery可以充当发起网络请求的客户端工具
// jquery 使用的方法:
// 1. 查询并存储元素
// 2. 操作元素,包括修改元素样式,绑定事件等
let box = document.querySelector('.box')
// 查询并构造一个jquery对象
let $box = $('.box')
console.log($box);
// 修改样式
$box.css('background-color', '#f00')
jquery绑定事件
// 给jquery对象绑定事件时,直接调用该事件名称对应的函数
// $box.click(function (ev) {
// console.log(ev);
// console.log('click');
// })
// $box.mousemove(function (ev) {
// console.log(ev);
// console.log('move');
// })
// $box.mouseenter(function (ev) {
// console.log('enter');
// })
// 手动触发事件
// $box.click()
// $box.mouseenter()
// 使用 on 函数绑定事件
const click1 = function (ev) {
console.log('click1');
console.log(ev);
}
$box.on('click', click1)
$box.on('click', function (ev) {
console.log('click2');
console.log(ev);
})
// 使用 off 解绑事件
// 如果只写一个参数,会解绑所有的对应事件
// $box.off('click')
$box.off('click', click1)
// 使用 one 函数,可以让绑定的事件只触发一次
// $box.one('click', (ev) => {
// console.log('one click');
// console.log(ev);
// })
$box[0].addEventListener('click', function () {
console.log('one click');
$box[0].removeEventListener('click', arguments.callee)
})
// 页面加载完成事件
$(function () {
console.log('load');
})
canvas画布
canvas 绘制几何图形原理是,先获取绘画的点,这个点在canvas中称为路径(path),会根据用户使用的工具不同(工具要么是笔刷要么是油漆桶),进行镂空绘制或者填充绘制
canvas最重要的是
// 获取画布
let c = document.querySelector('canvas')
let ctx = c.getContext('2d')
画线
// 获取画布
let c = document.querySelector('canvas')
let ctx = c.getContext('2d')
// 修改笔头宽度
ctx.lineWidth = 20
// 画线之前要开启路径
ctx.beginPath()
// 移动笔头
ctx.moveTo(100, 50)
// 绘制直线路径
ctx.lineTo(200, 50)
ctx.lineTo(200, 300)
// ctx.lineTo(100, 50)
// 闭合路径
ctx.closePath()
// 根据路径绘图
// 绘制镂空线
ctx.stroke()
// 绘制填充图形
// ctx.fill()
ctx.beginPath()
ctx.moveTo(250, 250)
// 绘制弧形
// 第一个和第二个参数: 圆心坐标
// 第三个参数: 圆半径
// 第四个和第五个参数: 起始弧度和结束弧度
// 0 度代表水平向右
// 正方向为顺时针
ctx.arc(250, 250, 250, Math.PI / 180 * 30, Math.PI)
ctx.closePath()
ctx.stroke()
// ctx.fill()
画图片
// 获取画布
let c = document.querySelector('canvas')
let ctx = c.getContext('2d')
// 绘制图片,只能绘制html页面中的图片<img>标签,且必须是加载完成的图片
// 获取图片源
const img = document.querySelector('img')
img.addEventListener('load', () => {
// 图片加载完成后才能绘制图片
// 语法:
// void ctx.drawImage(image, dx, dy);
// void ctx.drawImage(image, dx, dy, dWidth, dHeight);
// void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
// 解释:
// image:img标签
// dx,dy: 绘制图片的坐标位置
// dWidth, dHeight: 绘制图片的宽度和高度
// sx, sy: 图片内部的坐标,用于截取图片
// sWidth, sHeight: 截取图片的宽高
// 绘制完整图片
// ctx.drawImage(img, 100, 50)
// ctx.drawImage(img, 100, 50, 200, 100)
// 绘制部分图片
ctx.drawImage(img, 70, 130, 250, 100, 100, 50, 250, 100)
})
函数
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
// 动画目标: 将一个 50 x 50 的方块,以每秒 100px 的速度 向右移动
// requestAnimationFrame 请求动画的下一帧
// 参数是一帧之后的回调函数
requestAnimationFrame(render)
// 上一次动画时长
let lastTime = 0
// 上一帧到下一帧的间隔时间
let deltaTime = 0
let box = {
position: { x: 0, y: 0 },
width: 50,
height: 50,
// 速度: 每秒移动 100px
v: 100
}
// time 动画的播放总时长
function render(time) {
// 执行每一帧的逻辑
// 计算上一帧到这一帧的时间间隔
deltaTime = time - lastTime
lastTime = time
console.log(deltaTime);
// 速度 * deltaTime = 每帧的速度
box.position.x += deltaTime * 0.001 * box.v
// 画图
// 清空画布
ctx.clearRect(0, 0, 500, 500)
ctx.fillRect(box.position.x, box.position.y, box.width, box.height)
// 循环递归请求下一帧
requestAnimationFrame(render)
}
多媒体标签
视频
<!-- 属性
width 标签宽度
height 标签高度
controls 控制面板
muted 静音
autoplay 自动播放
src 媒体源
preload 预载模式
loop 循环
poster 海报
-->
<!-- 使用自动播放+静音,能实现自动播放的效果 -->
<!-- <video width="200" height="200" src="./video/oceans.mp4" controls autoplay muted></video> -->
<video controls preload="auto" loop poster="./img/1.png">
<!-- source 代表视频源 -->
<source src="./video/oceans.mp4">
</source>
</video>
音频
<!-- 由于audio和video都属于HTMLMediaElement的实例
所以audio的所有使用方法和video一样
可以通过 instanceof 来判断一个对象是否是某个类型的实例
video instanceof HTMLMediaElement
-->
<!-- <audio src="./audio/a4.mp3" controls loop></audio> -->
<!-- source 标签若有多个,那么浏览器会从上至下加载直到某一个被加载成功为止 -->
<audio controls>
<source src="./audio/a4.mp3">
<source src="./audio/b4.mp3">
<source src="./audio/c4.mp3">
</audio>
事件
// 可以通过音频类型 Audio 来播放音效
let aud = new Audio('./audio/a4.mp3')
// 关于自动播放
// 若直接播放媒体资源,将获得一个异常,告诉你浏览器不允许在用户未经允许的请款下自动播放
// video.play()
// setTimeout(() => {
// video.play()
// }, 5000)
// document.addEventListener('click', () => {
// // 由于不能直接自动播放,所以需要一个事件触发播放
// video.play()
// })
playBtn.addEventListener('click', () => {
// 播放
video.play()
// 获取媒体的总时间
totalTime.innerHTML = video.duration
})
pauseBtn.addEventListener('click', () => {
// 暂停
video.pause()
})
setInterval(() => {
// video.currentTime 当前媒体播放的进度时间
currentTime.innerHTML = video.currentTime
}, 1000)
goTo.addEventListener('click', () => {
// 跳转播放时间
video.currentTime = Number(inp.value)
})
// 音量加减
// 取值范围是0~1
vUp.addEventListener('click', () => {
video.volume = Math.min(1, video.volume + 0.1)
})
vDown.addEventListener('click', () => {
video.volume = Math.max(0, video.volume - 0.1)
})
// 静音与恢复
muted.addEventListener('click', () => {
video.muted = !video.muted
})
微信小程序
小程序项目结构
项目下的文件和文件夹的作用如下:
components: 小程序的自定义组件
images: 图片文件夹
pages: 存放页面文件的文件夹
index: 页面文件夹
index.js: 页面的js代码
index.json: 页面的配置
index.wxml: html模板文件
index.wxss: 页面的样式文件
utiles: 辅助用的js代码放的文件夹
app.js: 微信小程序的程序入口(程序入口:开始执行代码的地方)
app.json: 小程序应用程序的全局配置文件
app.wxss: 小程序的全局样式(.wxss文件是小程序的样式文件)
project.config.json: 小程序项目的配置
sitemap.json: 用于微信搜索小程序的配置文件
常用标签
<!-- page 标签相当于 html 中的 body -->
<page></page>
<!-- view 标签相当于 html 中的 div -->
<view></view>
<!-- text 相当于 html 中的 span -->
<text></text>
<!-- image 相当于 html 中的 img -->
<image></image>
<!-- block 是一个自身不会显示的标签 -->
<block></block>
认识页面对象模型page
使用Page函数包裹的整个对象是一个 page 对应的对象模型,例如:
Page({
data: {
// 数据
},
onLoad: {
// 加载完成事件
}
})
模板语法
模板语法是微信规定的一套书写wxml的语法
插值
作用:用于将变量值插入页面
语法:
<!-- name 变量,定义在 js 文件的 data 中 -->
{{name}}
注意:插值运算的花括号中{{}},填写的内容其实是js表达式
循环渲染
作用:可以将数组数据循环显示到页面中
语法:
<!-- wx: 开头的写在标签头部的东西 称为指令 -->
<!-- array: 来自js data中的数组 -->
<!-- 使用 wx:for 一定要加上 wx:key,wx:key的值是array对象中的不可重复的属性 -->
<view wx:for="{{array}}" wx:key="id">
<!-- index: 是 wx:for 中隐式声明的变量,代表循环遍历array时的当前索引 -->
<!-- item: 是 wx:for 中隐式声明的变量,代表循环遍历array时的当前数组成员 -->
{{index}}: {{item}}
</view>
条件渲染
可以根据条件判断,选择性的渲染页面
语法:
<view wx:for="{{table}}" wx:key="name">
<text>{{index}}: 姓名 = {{item.name}}; 年龄 = {{item.age}}; 性别 = </text>
<!-- wx:if 指令的值为布尔表达式,为true是渲染该节点,否则不渲染 -->
<text wx:if="{{item.sex==='male'}}">男</text>
<!-- wx:if 可以和 wx:elif、wx:else 连用 -->
<text wx:elif="{{item.sex==='female'}}">女</text>
<text wx:else>其他</text>
</view>
全局配置
app.json 文件中的配置是全局配置 影响所有页面
entryPagePath 小程序启动页的路径
pages 页面的路径列表
window 全局窗口的配置
tabBar 底部选项卡
debug 开启调试模式
页面配置
全局配置下,window中的所有内容,每个页面自身也可以配置
disableScroll 禁止用户上下滚动页面
usingComponents 使用组件
授权
用户需要使用本地设备上的一些设备功能时,需要向系统获取设备权限,例如:摄像头,定位信息,联系人,陀螺仪等
此时就需要进行授权操作
什么时候使用授权
在用户即将使用一些需要授权才能使用的本地设备功能时(微信小程序已经把这些功能制作成了接口,当需要调用这些接口的时候就可以进行授权)
流程
读取当前权限
判断是否存在权限
不存在权限就进行授权
// 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.record" 这个 scope
wx.getSetting({
success(res) {
if (!res.authSetting['scope.record']) {
// 调用 wx.authorize 进行授权
wx.authorize({
scope: 'scope.record',
success() {
// 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问
wx.startRecord();
},
});
}
},
});
权限列表
文档: 授权 | 微信开放文档
授权期限
授权后,权限将一直存在,直到小程序被删除为止
关于二次授权
用户在进行授权时是可以拒绝的,若拒绝授权,我们可以使用 wx.openSetting 打开设置引导用户开启权限
例如以下代码
wx.getSetting({
success: (res) => {
console.log(res);
if (!res.authSetting['scope.camera']) {
if (typeof res.authSetting['scope.camera'] === 'undefined') {
// 用户没有进行过授权
wx.authorize({
scope: 'scope.camera',
success: () => {
console.log('开启摄像头');
},
});
} else {
// 用户拒绝过授权
// openSetting 打开权限设置
// 设置中包含的是已经授权或被拒绝过的权限
wx.openSetting({
success(res) {
console.log(res);
},
});
}
} else {
console.log('开启摄像头');
}
},
});
什么是组件
具备独立的 js,json,wxml,wxss的一段代码是一个组件
组件主要的作用是复用页面代码
创建组件
注册组件
组件结构
组件生命周期
组件属性
// 在组件的配置中添加 properties 配置
Component({
/**
* 组件的属性列表
*/
properties: {
// 声明属性 value
// 具体声明方式可参考 https://developers.weixin.qq.com/miniprogram/dev/reference/api/Component.html#properties-%E5%AE%9A%E4%B9%89
value: {
type: String, // 属性类型 可以通过设置 optionalTypes 来接收多种类型的数据
value: 'o,k', // 属性默认值
// 属性变化监听器
observer: function (newVal, oldVal) {
console.log(newVal);
console.log(oldVal);
console.log(this)
}
}
},
})
组件内设置属性的方法和 Page 设置 data 是一样的
// 使用 setData 设置属性
this.setData({value: 'hello'})
在 Page 中注册组件后就可以将组件作为标签使用了
// 注册组件
{
"useingComponent": {
"my-component": "path/to/component"
}
}
<!-- 使用组件 -->
<!-- _value 是当前页面 data 中的值 -->
<my-component value="{{_value}}"></my-component>
注意: 除了在组件内修改 value 值以外,还可以通过修改 Page 的 _value 来修改组件的 value 值
组件方法
获取组件并调用组件方法
Page({
getComponent() {
// 给组件添加 class="my-component"
// 通过 selectComponent 获取组件
let com = this.selectComponent('.my-component')
// 假设组件 methods 中有个方法叫 myFn
// 调用组件方法
com.myFn()
}
})
组件事件
<!-- 假设组件的模板如下 -->
<button bindtap="onClick">发送点击事件</button>
// 组件声明如下
Component({
methods: {
onClick() {
// triggerEvent 可以发出事件
// 文档: https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html#%E7%9B%91%E5%90%AC%E4%BA%8B%E4%BB%B6
// 第一个参数: 发出的事件名称
// 第二个参数: 事件传递出去的参数
// 第三个参数: 事件选项
this.triggerEvent('my-click', 'my detail')
}
}
})
<!-- Page 的 wxml 如下 -->
<!-- 通过 bind:<event-name> 的方式绑定事件 -->
<my-component bind:my-click="myClickHandler"></my-component>
Page({
// myClickHandler 将接收组件的 my-click 事件
myClickHandler(event) {
// event.detail 的值就是 triggerEvent 的第二个参数值
console.log(event.detail)
}
})
将数据保存到小程序的全局对象中
// 获取小程序实例对象
const app = getApp()
app.globalData.x = 1 // 给小程序的全局对象赋值
// 只要不关闭小程序就能通过小程序全局对象保存参数
为什么要使用全局对象来存储数据
为了让每个页面共享相同的数据
持久化数据
什么叫持久化?持久化就是长期存储数据到磁盘中,关闭应用程序后,存储的数据还在
异步是什么?异步就是程序执行的时候不会等待或卡顿
同步是什么?同步的程序在调用的时候会等待或卡顿
导航与页面间传参
导航:引导页面跳转到指定位置
导航方法有两种:1. 页面标签进行导航,类似 html 中的 a 标签;2. 使用js进行导航,类似于 location.href
使用 navigator 标签
语法:
<!-- url:要跳转到的页面路径 -->
<!-- 若要传递参数,可以在url后面增加 ?key=value 的参数 -->
<navigator url="path"></navigator>
使用 wx.navigateTo
语法:
function(){
wx.navigateTo({
// path: 要跳转的路径
// key=value: 要传递的参数
url: 'path?key=value'
})
}
// wx.navigateTo 跳转到某页 会新增堆栈
// wx.redirectTo 重定向到某页 不会新增堆栈
// wx.navigateBack 返回
参数的获取可以在另一个页面的 onLoad 声明周期函数中 options 变量中存放着参数
js代码中的赋值与读值
在js代码的函数中读取属性的方法:
Page({
read() {
console.log('read')
// 函数中的 this 代表当前页面对象模型
console.log(this)
// 谁用this.data读取页面属性
console.log(this.data.table)
}
})
给页面属性赋值的方法:
Page({
write() {
// 使用this.setData函数进行赋值,参数是个json对象,需要修改哪个属性,就给该对象添加哪个属性
this.setData({title: '天龙八部'})
}
})
页面底部选项卡
在 app.json 中 增加 tabBar 配置就能添加选项卡
{
"tabBar": {
"selectedColor": "#444", // 选中的按钮的文本颜色
"list": [ // 按钮列表
{
"pagePath": "pages/read/read", // 跳转的页面路径
"text": "领读", // 按钮的文字描述
"iconPath": "image/tab_icon1.png", // 未选中时的图标路径
"selectedIconPath": "image/tab_icon1_active.png" // 选中时的图标路径
}
]
},
}
注意:要显示选项卡,按钮列表中,必须要有一个配置的 pagePath 属性值,是小程序的入口页面
注意:底部选项卡指定的页面不能是分包里的页面
自定义底部选项卡图标
可以在阿里适量图库下载需要的图标(一般来说是一个镂空图标和一个填充图标)
将下载后的图片复制到小程序项目目录下,然后再tabBar配置选项中配置即可