使用uview框架及其微信小程序云开发 仅供学习和交流,

首先讲一下原理 具体看下边
https://www.cnblogs.com/raicho/p/16025522.html
这个还是比较简单的,如果自己会一点后端,根据上面的步骤慢慢来,我这里为了省事,使用了云函数基于nodejs作为后端 并且调用了第三方api。
为什么要使用微信云开发 性能非常慢,加上时间原因就没自己写后端, 而且用到了微信云存储,为什么?如果你为了图方便你可以在微信小程序的后台管理 页面把所有的视频去水印白名单给写上 目前我所知道的有将近两百个,如果你单纯是纯粹去水印的话 ,不需要云存储云开发也是可以的,直接添加将近两百个域名白名单,这样极大节省流量及其费用,因为前端返回去水印链接需要添加上域名白名单这样用户才可以自主下载,否则因为跨域限制无法下载,那么接下来就需要用到自己的微信云函数了。在后台将这些链接处理好 并上传到云存储 再将云存储的每个id传递给用户 让用户下载 这样就不涉及跨域了,
为什么我写到后台就是因为域名白名单限制并且不仅仅做的这一个功能。虽然只是随手写写的,下个月就到期了。。。。。。
下面是前端代码 样式及其页面
<view class="container">
<view style="background-color: #66CC99; height:260rpx; border-bottom-left-radius: 30rpx; border-bottom-right-radius: 30rpx;"></view>
<view style="padding: 30rpx;margin-top:-100rpx; ">
<view style="background-color: #F8F8F8;border-radius: 20rpx;">
<view style="padding: 60rpx 30rpx;">
<u-row>
<u-col span="8">
<view class="" style="padding:10rpx 20rpx">
<u--input placeholder="请粘贴视频/文字/图片链接" border="none" clearable v-model="inputRadioUrl"></u--input>
</view>
</u-col>
<u-col span="4">
<view
style="background-color:#87BF90;border-radius: 40rpx;"
:title="item.title"
v-for="(item, index) in jiazai"
:key="index"
@click="showToast(item)"
>
<view style="font-size: 32rpx;text-align: center;padding: 16rpx 0rpx;color: white;">获取</view>
</view>
</u-col>
</u-row>
</view>
</view>
<view>
<!-- //正在加载通知 -->
<u-toast ref="uToast"></u-toast>
</view>
</view>
export default {
data() {
return {
//加载框
jiazai: [
{
type: 'loading',
message: '正在解析',
duration: '6000'
}
],
inputRadioUrl: '',
radioUrl: '',
//文案内容
textContent: '',
imgUrl: '',
links: '',
srcs: ''
};
},
methods: {
//加载框
showToast(params) {
let that = this;
this.$refs.uToast.show({
...params
});
that.getRadio(); //获取后端的数据 去水印的连接
},
这里的原理是这样的,先从后端获取到去水印的链接及其文案内容, 跳转页面链接后顺便将链接将传递到后台,为什么要这么做,一方面是为了便于当前页面可以添加广告 另外一方面也是为了节省服务器流量,后面请听我说
getRadio() {
let that = this;
const regex = /https?:\/\/v\.douyin\.com\/\w+\//; // 匹配链接
this.links = this.inputRadioUrl.match(regex) || [];
// console.log(this.links)
if (this.inputRadioUrl.length === 0 && !this.inputRadioUrl.includes('http://') && !this.inputRadioUrl.includes('https://')) {
uni.showToast({
title: '去除失败,请稍后重试',
icon: 'none'
});
console.log(this.inputRadioUrl);
} else {
wx.cloud.callFunction({
name: 'dy',
data: {
functionName: 'dyUrl',
url: that.links[0]
},
success: function(res) {
if (res.result.code == 200) {
if (res.result.data.type == 1) {
that.textContent = res.result.data.title;
that.radioUrl = res.result.data.video_url;
that.$refs.uToast.hide();
uni.navigateTo({
url: '/pages/tool/dy/dyhandle?textContent=' + that.textContent + '&radioUrl=' + that.radioUrl
});
} else if (res.result.data.type == 2) {
that.imgUrl = res.result.data.imgs;
that.textContent = res.result.data.title;
let imgs = JSON.stringify(that.imgUrl);
that.$refs.uToast.hide();
uni.navigateTo({
url: '/pages/tool/dy/dyhandle?imgUrl=' + imgs + '&textContent=' + that.textContent
});
}else{
uni.showToast({
title: '解析失败,稍后重试',
icon: 'none'
});
}
}else{
uni.showToast({
title: '后台解析失败,稍后重试',
icon: 'none'
});
}
},
fail: function(err) {
uni.showToast({
title: '解析失败,稍后重试',
icon: 'none'
});
that.$refs.uToast.hide();
}
});
}
}
}
};
云函数代码
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 使用当前云环境
const axios = require('axios')
//解析链接 返回给前端
async function dyUrl(url) {
const token = '点兵点将'
const apiUrl = '直接找个第三方api吧'
const params = { token, url };
try {
const response = await axios.get(apiUrl, { params }); // 发送 HTTP 请求
const data = response.data;
if (data.code === 200) {
return data;
} else {
return data.msg;
}
} catch (err) {
console.error(err);
return err;
}
};
//当用户点击保存视频时 前端获取到上一个方法返回的连接,上传到本地云存储返回云存储连接后给用户下载
async function uploadDy(Video_url) {
try {
const { data: videoData } = await axios.get(Video_url, { responseType: 'arraybuffer' })
const fileSize = videoData.byteLength/1024/1024 // 计算视频大小
if (fileSize > 100) { // 判断是否超过100M
return { type: 'error', msg: '上传的视频超过100M' }
}
const { fileID } = await cloud.uploadFile({
cloudPath: `videos/${Date.now()}.mp4`,
fileContent: videoData,
})
return { type: 'video', Video_urls: fileID}
} catch (error) {
console.error(error)
return error
}
}
//当用户点击保存图片时 前端获取到上一个方法返回的连接,上传到本地云存储返回云存储连接后给用户下载
async function uploadDyTupian(tupian_url) {
try {
const pictureIds = []
const tasks = []
let pictureSize = 0 // 总图片大小
for (let i = 0; i < tupian_url.length; i++) {
tasks.push(
(async () => {
try {
const { data: imageData } = await axios.get(tupian_url[i], { responseType: 'arraybuffer' })
const fileSize = imageData.byteLength/1024/1024 // 计算单张图片大小
pictureSize += fileSize
if (pictureSize > 20) { // 判断是否超过20M
return { type: 'error', msg: '上传的图片总大小超过20M' }
}
const { fileID } = await cloud.uploadFile({
cloudPath: `dyPicture/${Date.now()}/${i + 1}.jpg`,
fileContent: imageData,
})
pictureIds.push(fileID)
console.log('上传成功', fileID)
// return pictureIds // 返回数组
} catch (error) {
console.error('上传失败', error)
}
})()
)
}
await Promise.all(tasks)
return { type: 'picture', imgs_url: pictureIds} // 将返回值放在异步任务的外部
} catch (error) {
console.error(error)
return error
}
}
// 云函数入口函数
exports.main = async (event, context) => {
const { functionName, url} = event
try {
if (functionName === 'dyUrl') {
return await dyUrl(url)
} else if (functionName === 'uploadDy') {
return await uploadDy(url)
} else if(functionName==='uploadDyTupian'){
return await uploadDyTupian(url)
}
else {
return { type: 'error', msg: '无效的函数名' }
}
} catch (error) {
console.error(error)
return { type: 'error', msg: error.message }
}
}

处理页面
<template>
<view class="">
<view class="top" style="background-color: #66CC99">
<u-navbar title="获取素材" :autoBack="true" :placeholder="true" :safeAreaInsetTop="true" fixed leftIconSize="50rpx" height="120rpx" bgColor="#66CC99"></u-navbar>
</view>
<view class="container" style="padding: 30rpx;">
<view>
<view class="" style="background-color: white;" v-if="dyShipin">
<u-subsection :list="list1" mode="button" fontSize="32rpx" :current="spcurrent2" @change="dyShipinNav" bgColor="white"></u-subsection>
</view>
<view class="" style="background-color: white;" v-if="dyTupian">
<u-subsection :list="list2" mode="button" fontSize="32rpx" :current="tpcurrent2" @change="dyTupianNav" bgColor="white"></u-subsection>
</view>
<!-- 视频部分 -->
<view style="text-align: center; padding-top:60rpx;" v-if="dyShipin">
<view v-if="spcurrent2 == 0">
<video :src="radioURL" controls></video>
<u-tabbar :placeholder="true" :safeAreaInsetBottom="true" :border="false">
<view
class=""
style="padding: 10rpx;width: 80vw; margin-bottom: 160rpx;"
:title="item.title"
v-for="(item, index) in save"
:key="index"
@click="showToast(item)"
>
<u-row custom-style="justify-content:center">
<u-button type="primary" text="保存视频" size="large" shape="circle" color="#66CC99"></u-button>
</u-row>
</view>
</u-tabbar>
</view>
<view v-if="spcurrent2 == 1">
<view style="background-color: #F8F8F8;border-radius: 20rpx;" @click="textGet">
<view style="padding: 60rpx 30rpx;">
<view style="font-size: 32rpx">{{ textContent }}</view>
</view>
<text style="font-size: 26rpx;color:#747677;font-weight:bold">点击复制</text>
</view>
</view>
</view>
<!-- 图片部分 -->
<view style="text-align: center; padding-top:60rpx;" v-if="dyTupian">
<view v-if="tpcurrent2 == 0">
<u-grid :col="2" :highlight="false">
<u-grid-item v-for="(item, index) in imgsURL" :key="index" :highlight="false" custom-style="opacity:1">
<view class="" style="padding-top:20rpx;">
<u-row><u--image :showLoading="true" :src="item" width="300rpx" height="300rpx"></u--image></u-row>
</view>
<view
style=" border: 2rpx solid #ADB1B2; color:#747677; font-size: 30rpx; border-radius: 6rpx; width:300rpx;margin-top: 10rpx;"
@click="singleTupian(index)"
>
<u-button text="下载图片"></u-button>
</view>
</u-grid-item>
</u-grid>
<u-tabbar :placeholder="true" :safeAreaInsetBottom="true" :border="false">
<view
class=""
style="padding: 10rpx;width: 80vw; margin-bottom: 160rpx;"
:title="item.title"
v-for="(item, index) in save"
:key="index"
@click="showToast1(params)"
>
<u-row custom-style="justify-content:center">
<u-button type="primary" text="保存图片" size="large" shape="circle" color="#66CC99"></u-button>
</u-row>
</view>
</u-tabbar>
</view>
<view v-if="tpcurrent2 == 1">
<view style="background-color: #F8F8F8;border-radius: 20rpx;" @click="textGet">
<view style="padding: 60rpx 30rpx;">
<view style="font-size: 32rpx">{{ textContent }}</view>
</view>
<text style="font-size: 26rpx;color:#747677;font-weight:bold">点击复制</text>
</view>
</view>
</view>
</view>
</view>
<!-- //正在保存 通知提醒 -->
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
export default {
data() {
return {
flag: false,
//音频链接
radioURL: '',
imgsURL: [], //图片链接
singleImgUrl: [], //单个图片链接
textContent: '', //文案内容
//判断是视频还是图片显示页面
dyShipin: false,
dyTupian: false,
//保存视频的消息提醒
save: [
{
type: 'loading',
message: '正在保存',
duration: '20000'
}
],
//点击位置
spcurrent2: 0, //视频
tpcurrent2: 0, //图片
checkedList: [],
//导航名称
list1: [{ name: '视频提取' }, { name: '文字提取' }],
list2: [{ name: '图片提取' }, { name: '文字提取' }]
};
},
onLoad(options) {
console.log(options);
if (options.hasOwnProperty('radioUrl')) {
this.dyShipin = true;
this.radioURL = options.radioUrl;
this.textContent = options.textContent;
} else if (options.hasOwnProperty('imgUrl')) {
this.dyTupian = true;
this.imgsURL = JSON.parse(options.imgUrl);
this.textContent = options.textContent;
} else {
wx.showToast({
title: '传递错误!'
});
}
},
methods: {
// 文字提取
textGet() {
let that = this;
wx.setClipboardData({
data: that.textContent,
success: function(res) {
wx.showToast({
title: '复制成功'
});
}
});
},
//视频下载方法
downLoad() {
let that = this;
//先上传后下载
wx.cloud.callFunction({
name: 'dy',
data: {
functionName: 'uploadDy',
url: that.radioURL
},
success: res => {
let fileId = res.result.Video_urls;
wx.cloud.downloadFile({
fileID: fileId,
success: res => {
// 下载成功后,将视频保存到相册中
wx.saveVideoToPhotosAlbum({
filePath: res.tempFilePath,
success: res => {
wx.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
});
that.$refs.uToast.hide();
},
fail: res => {
wx.showToast({
title: '保存失败',
icon: 'none',
duration: 2000
});
that.$refs.uToast.hide();
}
});
},
fail: res => {
wx.showToast({
title: '下载失败',
icon: 'none',
duration: 2000
});
that.$refs.uToast.hide();
}
});
}
});
},
//视频处理方法
showToast(params) {
let that = this;
this.$refs.uToast.show({
...params
});
if (that.radioURL == '') {
that.$refs.uToast.hide();
uni.showToast({
title: '下载失败,稍后重试',
icon: 'none'
});
} else {
//获取用户授权信息
wx.getSetting({
success(res) {
if (res.authSetting['scope.writePhotosAlbum']) {
// 已经获得授权,直接存储
that.downLoad();
} else if (res.authSetting['scope.writePhotosAlbum'] === undefined) {
// 第一次运行,授权未定义,可以直接保存,系统会一次性询问用户权限
that.downLoad();
} else {
//用户拒绝授权后 打开设置页开启
wx.openSetting({
success(res) {
if (res.authSetting['scope.writePhotosAlbum']) {
that.downLoad();
} else {
// 用户拒绝授权
wx.showToast({
title: '拒绝授权!'
});
that.$refs.uToast.hide();
}
},
fail(res) {
wx.showToast({
title: '设置失败'
});
}
});
}
},
fail(res) {
wx.showToast({
title: '设置失败'
});
}
});
}
},
//所有图片处理方法
showToast1(params) {
let that = this;
this.$refs.uToast.show({
message: '正在保存',
duration: 10000,
type: 'loading'
});
//上一级页面没有传递页面
if (that.imgsURL == '') {
that.$refs.uToast.hide();
uni.showToast({
title: '下载失败,稍后重试',
icon: 'none'
});
} else {
//获取用户授权信息
wx.getSetting({
success(res) {
if (res.authSetting['scope.writePhotosAlbum']) {
// 已经获得授权,直接存储
that.tupianDownLoad();
} else if (res.authSetting['scope.writePhotosAlbum'] === undefined) {
// 第一次运行,授权未定义,可以直接保存,系统会一次性询问用户权限
that.tupianDownLoad();
} else {
//用户拒绝授权后 打开设置页开启
wx.openSetting({
success(res) {
if (res.authSetting['scope.writePhotosAlbum']) {
that.tupianDownLoad();
} else {
// 用户拒绝授权
wx.showToast({
title: '拒绝授权!'
});
that.$refs.uToast.hide();
}
},
fail(res) {
wx.showToast({
title: '设置失败'
});
}
});
}
},
fail(res) {
wx.showToast({
title: '设置失败'
});
}
});
}
},
//保存所有图片的方法
tupianDownLoad() {
var that = this;
//先上传后下载
wx.cloud.callFunction({
name: 'dy',
data: {
functionName: 'uploadDyTupian',
url: that.imgsURL
},
success: res => {
// console.log(res);
let fileIds=res.result.imgs_url;
for (let i = 0; i < fileIds.length; i++) {
const fileId = fileIds[i];
wx.cloud.downloadFile({
fileID: fileId,
success: res => {
// 下载成功后,将视频保存到相册中
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: res => {
wx.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
});
that.$refs.uToast.hide();
},
fail: res => {
console.log(res);
wx.showToast({
title: '保存失败',
icon: 'none',
duration: 2000
});
that.$refs.uToast.hide();
}
});
},
fail: res => {
console.log(res);
that.$refs.uToast.hide();
}
});
}
}
});
},
//单个图片方法
singleTupianDownLoad() {
let that = this;
// console.log(res);
wx.cloud.callFunction({
name: 'dy',
data: {
functionName: 'uploadDyTupian',
url: that.singleImgUrl
},
success: res => {
console.log(res);
let fileId = res.result.imgs_url;
console.log(fileId);
wx.cloud.downloadFile({
fileID: fileId,
success: res => {
console.log(res);
// 下载成功后,将视频保存到相册中
wx.saveVideoToPhotosAlbum({
filePath: res.tempFilePath,
success: res => {
wx.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
});
that.$refs.uToast.hide();
},
fail: res => {
wx.showToast({
title: '保存失败',
icon: 'none',
duration: 2000
});
that.$refs.uToast.hide();
}
});
},
fail: res => {
console.log(res);
wx.showToast({
title: '下载失败',
icon: 'none',
duration: 2000
});
that.$refs.uToast.hide();
}
});
}
});
},
//单个图片下载
singleTupian(item) {
this.singleImgUrl=[],//重置数组
this.singleImgUrl.push(this.imgsURL[item]);
let that = this;
// console.log(this.singleImgUrl);
this.$refs.uToast.show({
message: '正在保存',
duration: 1000,
type: 'loading'
});
if (that.imgsURL == '') {
that.$refs.uToast.hide();
uni.showToast({
title: '下载失败,稍后重试',
icon: 'none'
});
} else {
//获取用户授权信息
wx.getSetting({
success(res) {
if (res.authSetting['scope.writePhotosAlbum']) {
// 已经获得授权,直接存储
// that.singleTupianDownLoad();
} else if (res.authSetting['scope.writePhotosAlbum'] === undefined) {
// 第一次运行,授权未定义,可以直接保存,系统会一次性询问用户权限
that.singleTupianDownLoad();
} else {
//用户拒绝授权后 打开设置页开启
wx.openSetting({
success(res) {
if (res.authSetting['scope.writePhotosAlbum']) {
that.singleTupianDownLoad();
} else {
// 用户拒绝授权
wx.showToast({
title: '拒绝授权!'
});
that.$refs.uToast.hide();
}
},
fail(res) {
that.$refs.uToast.hide();
wx.showToast({
title: '设置失败'
});
}
});
}
},
fail(res) {
that.$refs.uToast.hide();
wx.showToast({
title: '设置失败'
});
}
});
}
},
//视频导航
dyShipinNav(index) {
this.spcurrent2 = index;
},
//图片导航
dyTupianNav(index) {
this.tpcurrent2 = index;
}
}
};
</script>
<style scoped lang="scss">
/* 取消 u-grid-item 的点击遮罩 */
::v-deep .u-grid-item--hover--class {
opacity: 1;
}
::v-deep .u-tabbar__content__item-wrapper {
margin-bottom: 60rpx;
justify-content: center;
}
</style>
只是讲一下大概原理。有些地方写的还不是特别好,多多交流
小程序demo效果,可以试一试
