先贴个效果图:
这里弹框我单独封装成了组件,哪里用哪里拿就行
(需要从向父组件一个参数visible,这个参数是用于当用户点击同意/不同意 都需要关闭弹窗)
<template>
<view class="comp-container">
<view class="dialog">
<view class="title">用户隐私保护提示</view>
<view class="desc">
感谢您使用本小程序,在使用前您应当阅读并同意<text class="privacy" @click="handleOpenPrivacyContract">《用户隐私保护指引》</text>,当点击同意,即表示您已理解并同意该条款内容,该条款将对您产生法律约束力;如您不同意,将无法继续使用小程序相关功能。
</view>
<view class="footer">
<button type="default" class="btn disagree" @click="handleDisagree">不同意</button>
<button type="default" open-type="agreePrivacyAuthorization" class="btn agree" @agreeprivacyauthorization="handleAgree">同意</button>
</view>
</view>
</view>
</template>
<script setup>
import { defineEmits } from 'vue'
const emit = defineEmits(['getVisible'])
const visible = null;
function handleDisagree() {
// 处理用户不同意隐私协议的逻辑
emit('getVisible',false);
uni.exitMiniProgram()
}
function handleAgree() {
// 处理用户同意隐私协议的逻辑
emit('getVisible',false);
}
function handleOpenPrivacyContract(){
uni.openPrivacyContract()
}
</script>
<style lang="scss" scoped>
.comp-container {
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
z-index: 999;
}
.dialog {
color: #333;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border-radius: 20rpx;
padding: 50rpx 40rpx;
width: 560rpx;
box-sizing: border-box;
.title {
width: 100%;
color: #000;
text-align: center;
font-size: 32rpx;
font-weight: 650;
box-sizing: border-box;
}
.desc {
line-height: 40rpx;
box-sizing: border-box;
margin-top: 50rpx;
font-size: 26rpx;
.privacy {
color: #2f80ed;
}
}
.footer {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 30rpx;
.btn {
display: flex;
align-items: center;
color: #FFF;
font-size: 28rpx;
font-weight: 500;
line-height: 80rpx;
text-align: center;
height: 80rpx;
border-radius: 10rpx;
border: none;
background: #07c160;
flex: 1;
justify-content: center;
&:nth-last-child(1) {
margin-left: 30rpx;
}
&.disagree {
color: #333;
background: #f2f2f2;
}
}
}
}
</style>
为了方便小白食用,附上组件使用的页面,需要的自取(一般都在登录页用)
<template>
<view class="content">
<!-- <img src="../../static/image/logo.png" alt="" class="logo"/> -->
<view class='form'>
<text class="login-title">账号登录</text>
<uni-forms ref="formRef" :modelValue="formData" :rules="formRules" validate-trigger="submit">
<uni-forms-item class="input-item" name="UserName">
<view class="iconfont icon-yonghuming"></view>
<input type="text" v-model="formData.UserName" placeholder="请输入用户名" />
</uni-forms-item>
<uni-forms-item class="input-item" name="PassWord">
<view class="iconfont icon-mima"></view>
<input type="text" v-model="formData.PassWord" placeholder="请输入密码" :password="showPassword"/>
<text class="iconfont" :class="[!showPassword ? 'icon-yanjing_xianshi' : 'icon-yanjing_yincang']"
@click="changePassword"></text>
</uni-forms-item>
<uni-forms-item class="input-item" name="isChecked">
<view class="checkbox">
<uni-data-checkbox multiple v-model="formData.isChecked" :localdata="hobby" class="checkbox-box"></uni-data-checkbox>
<text class="agreement-title" @click='openAgreement'>《用户服务协议》</text>
<text>和</text>
<text class="agreement-title" @click='openAgreement'>《用户隐私协议》</text>
<PrivacyDialog v-if='visible' @getVisible='getVisible'/>
</view>
</uni-forms-item>
</uni-forms>
<button @click="submit" class="button">登录</button>
</view>
</view>
</template>
<script setup>
import {login} from '../../request/api.js'
import {alert} from '../../components/msg/msgPrompt.js'
import PrivacyDialog from '../../components/privacyDialog/index.vue'
import {ref, reactive, nextTick } from "vue"
import {onLoad,onReady} from "@dcloudio/uni-app"
const visible = ref(false);
const formData=reactive({
UserName:'123456',
PassWord:'123456',
isChecked:[],
})
const hobby=reactive([{text: '',value: 0}])
const checkbox1=reactive( [0])
const showPassword=ref(true)
const formRef = ref(null)
// 校验规则
function setFormRules(){
return {
UserName: {
rules: [{
required: true,
errorMessage: '用户名不能为空'
}]
},
PassWord: {
rules: [{
required: true,
errorMessage: '密码不能为空'
}]
},
isChecked: {
rules: [{
required: true,
errorMessage: '请先勾选用户协议'
},{
validateFunction:function(rule,value,data,callback){
if (value.length !==1) {
callback('请先勾选用户协议')
}
return true
}
}]
}
}
}
const formRules = setFormRules();
// 设置校验规则
onReady(() => {
formRef.value.setRules(formRules);
})
// 密码显示与隐藏
function changePassword() {
showPassword.value = !showPassword.value;
}
onLoad(()=>{
uni.getPrivacySetting({
success: res => {
//用户之前同意过隐私协议则会返回false;如果开发者声明了隐私收集,且用户还没同意过则返回true
if (res.needAuthorization) {
//需要显示隐私协议弹框
visible.value = true;
} else {
//不需要显示隐私协议弹框
visible.value = false;
}
},
fail: () => {
}
})
})
function getVisible(visib){
visible.value = visib;
}
function openAgreement(){
uni.openPrivacyContract()
}
function submit(ref) {
formRef.value.validate().then(result => {
const params={
"password": result.PassWord,
"userName": result.UserName
}
login(params).then( res => {
if(res.code === 200){
uni.navigateTo({
url:'/pages/index/index'
});
const id = {
"id":res.data.id
}
uni.setStorageSync('userInfo', {...params,...id});
uni.setStorageSync('token',res.data.token);
}else if(res.code === 201){
alert(res.message);
}
}).catch(err => {
console.log(err);
});
}).catch(err => {
console.log('表单校验失败', err);
})
}
</script>
<style lang="scss">
.content{
background:linear-gradient(180deg, #F1FAEE 0%, #1b9fff 80%);
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.logo{
width: 150rpx;
height: 150rpx;
margin-bottom: 100rpx;
margin-top: 20rpx;
}
.form{
width: 70%;
background-color: #fff;
padding: 40rpx 20rpx 40rpx;
display: flex;
flex-direction: column;
align-items: center;
border-radius: 80rpx;
box-shadow: 10px 10px 10px 3px rgba(100,100,100, 0.75);
.uni-data-checklist{
width: 10rpx;
padding-right: 15rpx;
}
}
.agreement-title{
color: #1b9fff;
cursor: pointer;
}
.checkbox{
display: flex;
align-items: center;
font-size: 24rpx;
.checkbox-box{
margin-right: 10rpx;
}
}
.login-title{
font-size: 44rpx;
margin-bottom: 60rpx;
margin-top: 0;
}
.uni-forms{
width: 100%;
.uni-forms-item__content{
display: flex;
align-items: center;
gap: 16rpx;
padding: 0 20rpx;
border-bottom: #fff solid 1px;
height: 80rpx;
input{
flex: 1;
}
.iconfont{
font-size: 36rpx;
}
}
/* #ifdef H5 */
::v-deep .uni-forms-item__content{
display: flex;
align-items: center;
gap: 8px;
padding: 0 10px;
border-bottom: #fff solid 1px;
height: 60px;
input{
flex: 1;
}
.iconfont{
font-size: 18px;
}
}
/* #endif */
}
.button{
color: #fff;
height: 30;
width: 80%;
border-radius: 40rpx;
background-color: #1b9fff;
}
}
</style>