在微信小程序如何在快速的创建一个可拖拽的按钮,我们就需要使用微信的skyline渲染模式,
app-bar 默认是全局显示在页面的最上层,所有我们利用这个特效。
首先在miniprogram文件内创建app-bar文件夹【app-bar名字只能这么写】,然后再app-bar中创建名为index的组件
而且需要再app.json 配置 “appBar”: {}
{
...
"appBar": {}
}
在app-bar组件中的wxml文件中
index.wxml
<pan-gesture-handler worklet:ongesture="onGesture">
<view id="consult" class="consult" bind:tap="onConsult" hidden="{{!visible}}">
<view class="consult-box">
<image src="{{icon}}" mode="" />
</view>
</view>
</pan-gesture-handler>
index.ts
import { openServer } from "../utils/config";
const GestureState = {
POSSIBLE: 0,
BEGIN: 1,
ACTIVE: 2,
END: 3,
CANCELLED: 4,
};
const { shared, spring } = wx.worklet;
const defaultX = 160;
//x,y起始位置
const x = shared(defaultX);
const y = shared(0);
const scale = shared(1);
//用于记录在打开底部弹出时,y的开始位置
const dy = shared(0);
//边距
const margin = 10;
//是否是首次打开
let first = false;
//记录按钮当前位置
let iconX = shared(0);
//客服icon的尺寸
let iconWidth = shared(0);
let iconHeight = shared(0);
// 获取系统信息
const systemInfo = wx.getSystemInfoSync();
const { windowWidth, windowHeight } = systemInfo;
var app = getApp();
//需要显示的页面
const visibleRoutes: string[] = [
"pages/index/index",
"pages/xxx/xxx",
];
let timer = 0;
Component({
properties: {
visible: {
type: Boolean,
value: false,
observer: function (a, b) {
if (a && this.data.currentPathVisible) {
first = true;
//获取 icon 按钮的尺寸
this.createSelectorQuery()
.select(".consult-box")
.boundingClientRect((res) => {
this.setData({
iconSize: { w: res.width, h: res.height },
});
iconWidth.value = res.width;
iconHeight.value = res.height;
console.log("iconSize", res);
})
.exec();
timer = setTimeout(() => {
x.value = spring(-margin, {}, () => {});
clearTimeout(timer);
}, 1000);
}
},
},
themeCode: {
value: "",
type: String,
observer: function (a: string, b) {
console.log(a);
this.setData({
icon: app.globalData.dictMap.get("customerServiceIcon"),
});
},
},
//监听页面是否在滚动
scrolling: {
type: Boolean,
value: false,
observer: function (a, b) {
if (!a) {
this.setData({
currentPathVisible: true,
});
//当前路由显示,判断icon 从左边出现 还是右边出现
console.log("显示", x.value, iconX.value, iconWidth.value);
if (x.value >= -windowWidth / 2 + iconWidth.value) {
//从右
x.value = spring(-margin, {}, () => {});
} else if (x.value <= -windowWidth / 2 + iconWidth.value) {
//从左
x.value = spring(
-windowWidth + iconWidth.value + margin,
{},
() => {}
);
}
} else {
this.setData({
currentPathVisible: false,
});
clearTimeout(timer);
//当前路由隐藏,判断icon 从左边隐藏 还是右边隐藏
if (x.value >= -windowWidth / 2 + iconWidth.value) {
//向右
x.value = spring(defaultX, {}, () => {});
} else if (x.value <= -windowWidth / 2 + iconWidth.value) {
//向左
x.value = spring(-windowWidth - defaultX, {}, () => {});
}
}
},
}
},
data: {
icon: "",
//客服icon的尺寸
iconSize: {
w: 72,
h: 82,
},
currentPathVisible: true, // 用于判断,用户进入首页,刚加载完成班别数据,此时跳转到个人主页,会触发出现悬浮客服按钮
},
lifetimes: {
ready() {
wx.onAppRoute((route: any) => {
console.log("onAppRoute", route.path);
if (visibleRoutes.includes(route.path)) {
this.setData({
currentPathVisible: true,
});
//当前路由显示,判断icon 从左边出现 还是右边出现
console.log("显示", x.value, iconX.value, iconWidth.value);
if (x.value >= -windowWidth / 2 + iconWidth.value) {
//从右
x.value = spring(-margin, {}, () => {});
} else if (x.value <= -windowWidth / 2 + iconWidth.value) {
//从左
x.value = spring(
-windowWidth + iconWidth.value + margin,
{},
() => {}
);
}
} else {
this.setData({
currentPathVisible: false,
});
clearTimeout(timer);
//当前路由隐藏,判断icon 从左边隐藏 还是右边隐藏
if (x.value >= -windowWidth / 2 + iconWidth.value) {
//向右
x.value = spring(defaultX, {}, () => {});
} else if (x.value <= -windowWidth / 2 + iconWidth.value) {
//向左
x.value = spring(-windowWidth - defaultX, {}, () => {});
}
}
});
},
attached() {
this.applyAnimatedStyle(".consult-box", () => {
"worklet";
return {
transform: `translate(${x.value}px, ${y.value}px) scale(${scale.value})`,
};
});
},
},
methods: {
//监听打开客服
onConsult() {
openServer();
},
onGesture(evt: any) {
"worklet";
console.log("onGesture", evt);
if (evt.state === GestureState.BEGIN) {
scale.value = 1.1;
} else if (evt.state === GestureState.ACTIVE) {
x.value += evt.deltaX;
y.value += evt.deltaY;
} else if (
evt.state === GestureState.END ||
evt.state === GestureState.CANCELLED
) {
scale.value = 1;
//x
if (x.value > -windowWidth / 2) {
x.value = spring(-margin, {}, () => {});
iconX.value = -margin;
} else if (x.value <= -windowWidth / 2) {
x.value = spring(
-windowWidth + iconWidth.value + margin,
{},
() => {}
);
// iconX.value = -windowWidth + iconWidth.value + margin
console.log(iconWidth.value, margin);
}
if (y.value < -windowHeight / 2 + iconHeight.value) {
y.value = spring(-windowHeight / 2 + iconHeight.value, {}, () => {});
} else if (y.value >= windowHeight / 2 - iconHeight.value * 2) {
y.value = spring(
windowHeight / 2 - iconHeight.value * 2,
{},
() => {}
);
}
}
},
},
});
如何控制app-bar
首先我们在app.ts中 globalData对象中新增 appBarComp:null;
在index首页onload的时候获取app-bar实例
onLoad: function (options: any) {
//获取appbar实例
if (typeof this.getAppBar === "function") {
app.globalData.appBarComp = this.getAppBar();
}
}
然后在别的地方控制传递的参数来控制app-bar,通过setData控制
//设置客服icon显示
app.globalData.appBarComp &&
app.globalData.appBarComp.setData({
visible: true,
});
到处结束,相当的简单。