vue动态调节背景图片
在一些场景下我们需要使用户可以进行自定义背景图片,包括背景图片和其透明度(当然,还有许多也可以,这里就以这两个为例子,都差不多),这里我就为大家详细介绍如何动态设置背景图片(伪类绑定样式属性值)。
其中声音播放部分详情在 https://blog.csdn.net/qq_45803593/article/details/125653908
先上效果图
1、调节数据
首先我们先设置改变背景图片的组件,其实就是一个计数器和选择器(这里的透明度我们设置步长为 0.1,最小值为 0.5,最大值为1,精确 1 位小数)
<div class="opacityChoice">
<div>
<span>聊天背景透明度</span>
</div>
<div>
<el-input-number size="mini" v-model="theme.opacity" :min="0.5" :max="1" :precision="1" :step="0.1" label="透明度"></el-input-number>
</div>
</div>
<div class="bgImgChoice">
<div>
<span>聊天背景选择</span>
</div>
<div>
<el-select size="mini" v-model="theme.bgImg" placeholder="请选择背景图片" @change="seeBackGround()">
<el-option
v-for="item in bgImgs"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<div>
<el-image style="width: 120px; height: 80px" :src="bgImg"></el-image>
</div>
</div>
<div class="updateThemeBtn">
<el-button type="primary" @click="updateThemeInfo()">确认修改</el-button>
</div>
data 部分
data () {
return {
theme: {},
...
bgImg: '', // 目前选择的图片
...
bgImgs: [
{
value: 'http://localhost:8081/upload/chat/bg/1.jpg',
label: '默认'
},
{
value: 'http://localhost:8081/upload/chat/bg/2.jpg',
label: '宇航员'
},
{
value: 'http://localhost:8081/upload/chat/bg/3.jpg',
label: '星空'
},
{
value: 'http://localhost:8081/upload/chat/bg/4.jpg',
label: '星云'
},
{
value: 'http://localhost:8081/upload/chat/bg/5.jpg',
label: '天空'
},
{
value: 'http://localhost:8081/upload/chat/bg/6.jpg',
label: '云雾'
},
{
value: 'http://localhost:8081/upload/chat/bg/7.jpg',
label: '夕阳'
},
{
value: 'http://localhost:8081/upload/chat/bg/8.jpg',
label: '月狼'
}
]
}
},
在页面创建时,我们将数据进行初始化
created () {
this.hasSound = this.$store.state.user.userInfo.notifySound !== 'none'
this.theme = this.$store.state.user.userInfo
this.bgImg = this.$store.state.user.userInfo.bgImg
},
在选中的背景图片发生变化时,我们替换相应的图片,并在点击提交时向数据库提交数据
methods: {
seeBackGround () {
this.$nextTick(() => {
this.bgImg = this.theme.bgImg
})
},
updateThemeInfo () {
if (!this.hasSound) {
this.theme.notifySound = 'none'
}
userApi.updateThemeInfo(this.theme).then(res => {
this.$message.success('修改主题信息成功n(*≧▽≦*)n')
this.$store.dispatch('user/SET_USERINFO', res.data.userInfo)
})
}
}
2、展示页面
<el-container class="myImg" :style="{'--myImgPath': 'url(' + userInfo.bgImg + ')', '--myOpacity': userInfo.opacity}">
<el-aside width="350px" style="height: inherit;border-right: 1px solid #c8c8c8;">
<router-view></router-view>
</el-aside>
<el-container>
<el-header>
<div class="conversationName">
<span style="font-size:24px">{{ currentConversation.name }}</span>
</div>
</el-header>
<el-main>
<my-main
v-if="currentConversation.id"
:currentConversation="currentConversation" />
<div class="no-conversation hor-ver-center" v-else>
<p class="text">聊天~打开心灵的窗户</p>
<chat-svg width="800" height="648"/>
</div>
</el-main>
</el-container>
</el-container>
我们将其父元素背景设置为透明
.chat {
height: inherit;
background: transparent;
}
然后我们为其插入伪类样式,其中 var(--myImgPath)
和 var(--myOpacity)
是用来动态传值的,在 vue 中我们可以使用 :style="{'--myImgPath': 'url(' + userInfo.bgImg + ')', '--myOpacity': userInfo.opacity}"
的形式来为其进行赋值,从而实现背景图片与背景透明度根据我们的调节来进行动态的显示
.myImg::before {
background-image: var(--myImgPath);
background-repeat:no-repeat;
background-size: cover;
background-attachment: fixed;
content: '';
opacity: var(--myOpacity);
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: -1;
}
3、组件代码
<template>
<div class="theme" style="height:240px;overflow: auto;">
<div class="audioSound">
<div>
<span>新消息通知声音</span>
</div>
<div v-if="hasSound">
<audio :src="notifyAudio" ref="sound" muted></audio>
<el-select size="mini" v-model="theme.notifySound" placeholder="请选择提示音" @change="playSound()">
<el-option
v-for="item in sounds"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<el-switch
v-model="hasSound"
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</div>
<div class="opacityChoice">
<div>
<span>聊天背景透明度</span>
</div>
<div>
<el-input-number size="mini" v-model="theme.opacity" :min="0.5" :max="1" :precision="1" :step="0.1" label="透明度"></el-input-number>
</div>
</div>
<div class="bgImgChoice">
<div>
<span>聊天背景选择</span>
</div>
<div>
<el-select size="mini" v-model="theme.bgImg" placeholder="请选择背景图片" @change="seeBackGround()">
<el-option
v-for="item in bgImgs"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<div>
<el-image style="width: 120px; height: 80px" :src="bgImg"></el-image>
</div>
</div>
<div class="updateThemeBtn">
<el-button type="primary" @click="updateThemeInfo()">确认修改</el-button>
</div>
</div>
</template>
<script>
import userApi from '@/api/modules/user'
const notifySoundMap = {
default: require('../../../static/audio/default.mp3'),
apple: require('../../../static/audio/apple.mp3'),
pcqq: require('../../../static/audio/pcqq.mp3'),
momo: require('../../../static/audio/momo.mp3'),
huaji: require('../../../static/audio/huaji.mp3'),
mobileqq: require('../../../static/audio/mobileqq.mp3'),
none: ''
}
export default {
name: 'MessageNotification',
data () {
return {
theme: {},
hasSound: true,
notifyAudio: '',
BGIMG_URL: 'http://localhost:8081/upload/chat/bg/',
bgImg: '',
sounds: [
{
value: 'default',
label: '默认'
},
{
value: 'apple',
label: '苹果'
},
{
value: 'pcqq',
label: '电脑端qq'
},
{
value: 'momo',
label: '陌陌'
},
{
value: 'huaji',
label: '滑稽'
},
{
value: 'mobileqq',
label: '手机qq'
}
],
bgImgs: [
{
value: 'http://localhost:8081/upload/chat/bg/1.jpg',
label: '默认'
},
{
value: 'http://localhost:8081/upload/chat/bg/2.jpg',
label: '宇航员'
},
{
value: 'http://localhost:8081/upload/chat/bg/3.jpg',
label: '星空'
},
{
value: 'http://localhost:8081/upload/chat/bg/4.jpg',
label: '星云'
},
{
value: 'http://localhost:8081/upload/chat/bg/5.jpg',
label: '天空'
},
{
value: 'http://localhost:8081/upload/chat/bg/6.jpg',
label: '云雾'
},
{
value: 'http://localhost:8081/upload/chat/bg/7.jpg',
label: '夕阳'
},
{
value: 'http://localhost:8081/upload/chat/bg/8.jpg',
label: '月狼'
}
]
}
},
created () {
this.hasSound = this.$store.state.user.userInfo.notifySound !== 'none'
this.theme = this.$store.state.user.userInfo
this.bgImg = this.$store.state.user.userInfo.bgImg
},
methods: {
playSound () {
this.notifyAudio = notifySoundMap[this.theme.notifySound]
this.$nextTick(() => {
this.$refs['sound'].play()
})
},
seeBackGround () {
this.$nextTick(() => {
this.bgImg = this.theme.bgImg
})
},
updateThemeInfo () {
if (!this.hasSound) {
this.theme.notifySound = 'none'
}
userApi.updateThemeInfo(this.theme).then(res => {
this.$message.success('修改主题信息成功n(*≧▽≦*)n')
this.$store.dispatch('user/SET_USERINFO', res.data.userInfo)
})
}
}
}
</script>
<style>
.theme {
display: flex;
flex-direction: column;
justify-content: space-around;
padding: 0 25px;
}
.theme .audioSound {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 60px;
}
.theme .opacityChoice {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 60px;
}
.theme .bgImgChoice {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
</style>
其相关的所有代码
<template>
<div class="theme" style="height:240px;overflow: auto;">
<div class="audioSound">
<div>
<span>新消息通知声音</span>
</div>
<div v-if="hasSound">
<audio :src="notifyAudio" ref="sound" muted></audio>
<el-select size="mini" v-model="theme.notifySound" placeholder="请选择提示音" @change="playSound()">
<el-option
v-for="item in sounds"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<el-switch
v-model="hasSound"
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</div>
<div class="opacityChoice">
<div>
<span>聊天背景透明度</span>
</div>
<div>
<el-input-number size="mini" v-model="theme.opacity" :min="0.5" :max="1" :precision="1" :step="0.1" label="透明度"></el-input-number>
</div>
</div>
<div class="bgImgChoice">
<div>
<span>聊天背景选择</span>
</div>
<div>
<el-select size="mini" v-model="theme.bgImg" placeholder="请选择背景图片" @change="seeBackGround()">
<el-option
v-for="item in bgImgs"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<div>
<el-image style="width: 120px; height: 80px" :src="bgImg"></el-image>
</div>
</div>
<div class="updateThemeBtn">
<el-button type="primary" @click="updateThemeInfo()">确认修改</el-button>
</div>
</div>
</template>
<script>
import userApi from '@/api/modules/user'
const notifySoundMap = {
default: require('../../../static/audio/default.mp3'),
apple: require('../../../static/audio/apple.mp3'),
pcqq: require('../../../static/audio/pcqq.mp3'),
momo: require('../../../static/audio/momo.mp3'),
huaji: require('../../../static/audio/huaji.mp3'),
mobileqq: require('../../../static/audio/mobileqq.mp3'),
none: ''
}
export default {
name: 'MessageNotification',
data () {
return {
theme: {},
hasSound: true,
notifyAudio: '',
BGIMG_URL: 'http://localhost:8081/upload/chat/bg/',
bgImg: '',
sounds: [
{
value: 'default',
label: '默认'
},
{
value: 'apple',
label: '苹果'
},
{
value: 'pcqq',
label: '电脑端qq'
},
{
value: 'momo',
label: '陌陌'
},
{
value: 'huaji',
label: '滑稽'
},
{
value: 'mobileqq',
label: '手机qq'
}
],
bgImgs: [
{
value: 'http://localhost:8081/upload/chat/bg/1.jpg',
label: '默认'
},
{
value: 'http://localhost:8081/upload/chat/bg/2.jpg',
label: '宇航员'
},
{
value: 'http://localhost:8081/upload/chat/bg/3.jpg',
label: '星空'
},
{
value: 'http://localhost:8081/upload/chat/bg/4.jpg',
label: '星云'
},
{
value: 'http://localhost:8081/upload/chat/bg/5.jpg',
label: '天空'
},
{
value: 'http://localhost:8081/upload/chat/bg/6.jpg',
label: '云雾'
},
{
value: 'http://localhost:8081/upload/chat/bg/7.jpg',
label: '夕阳'
},
{
value: 'http://localhost:8081/upload/chat/bg/8.jpg',
label: '月狼'
}
]
}
},
created () {
this.hasSound = this.$store.state.user.userInfo.notifySound !== 'none'
this.theme = this.$store.state.user.userInfo
this.bgImg = this.$store.state.user.userInfo.bgImg
},
methods: {
playSound () {
this.notifyAudio = notifySoundMap[this.theme.notifySound]
this.$nextTick(() => {
this.$refs['sound'].play()
})
},
seeBackGround () {
this.$nextTick(() => {
this.bgImg = this.theme.bgImg
})
},
updateThemeInfo () {
if (!this.hasSound) {
this.theme.notifySound = 'none'
}
userApi.updateThemeInfo(this.theme).then(res => {
this.$message.success('修改主题信息成功n(*≧▽≦*)n')
this.$store.dispatch('user/SET_USERINFO', res.data.userInfo)
})
}
}
}
</script>
<style>
.theme {
display: flex;
flex-direction: column;
justify-content: space-around;
padding: 0 25px;
}
.theme .audioSound {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 60px;
}
.theme .opacityChoice {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 60px;
}
.theme .bgImgChoice {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
</style>
<template>
<div class="chat">
<el-container style="height: inherit;">
<audio :src="NotifyAudio" ref="audio" muted></audio>
<el-aside width="60px" style="height: inherit;background-color:#2f2e2e">
<my-menu />
</el-aside>
<el-container class="myImg" :style="{'--myImgPath': 'url(' + userInfo.bgImg + ')', '--myOpacity': userInfo.opacity}">
<el-aside width="350px" style="height: inherit;border-right: 1px solid #c8c8c8;">
<router-view></router-view>
</el-aside>
<el-container>
<el-header>
<div class="conversationName">
<span style="font-size:24px">{{ currentConversation.name }}</span>
</div>
</el-header>
<el-main>
<my-main
v-if="currentConversation.id"
:currentConversation="currentConversation" />
<div class="no-conversation hor-ver-center" v-else>
<p class="text">聊天~打开心灵的窗户</p>
<chat-svg width="800" height="648"/>
</div>
</el-main>
</el-container>
</el-container>
</el-container>
</div>
</template>
<script>
import myMenu from '@/views/layout/MyMenu'
import myMain from '@/views/layout/myMain'
import chatSvg from '@/SVGComponents/chat'
import conversationApi from '@/api/modules/conversation'
const notifySoundMap = {
default: require('../../static/audio/default.mp3'),
apple: require('../../static/audio/apple.mp3'),
pcqq: require('../../static/audio/pcqq.mp3'),
momo: require('../../static/audio/momo.mp3'),
huaji: require('../../static/audio/huaji.mp3'),
mobileqq: require('../../static/audio/mobileqq.mp3'),
none: ''
}
export default {
name: 'Chat',
components: { myMain, myMenu, chatSvg },
data () {
return {
NotifyAudio: '', // 播放的声音
notifySound: '' // 目前设置的声音
}
},
created () {
this.notifySound = this.userInfo.notifySound
this.getMyConversationsList()
},
sockets: {
// 客户端connect事件,服务端可针对connect进行信息传输
connect: function () {
this.$message.info('连接成功')
console.log('socket connected:', this.$socket.id)
},
onlineUser (data) {
// console.log('当前在线用户列表:', data)
this.$store.dispatch('user/SET_ONLINE_USER', data)
},
receiveMessage (news) {
this.$refs['audio'].play()
// 不是现在所处的房间就新增未读消息
if (news.roomId !== this.$store.state.conversation.currentConversation.roomId || JSON.stringify(this.$store.state.conversation.currentConversation) === '{}') {
this.$store.dispatch('conversation/SET_UNREAD_NUM', {type: 'add', data: news})
}
},
receiveValidateMessage (news) { // 同时向系统消息页面发送未读消息
this.$refs['audio'].play()
},
receiveAgreeFriendValidate (data) {
this.$refs['audio'].play()
}
},
computed: {
currentConversation () {
return this.$store.state.conversation.currentConversation
},
userInfo () {
return this.$store.state.user.userInfo
}
},
watch: {
userInfo: {
handler (newVal, oldVal) {
this.userGoOnline()
},
deep: true,
immediate: true
},
notifySound: {
handler (notifySound) {
this.NotifyAudio = notifySoundMap[notifySound]
},
deep: true,
immediate: true
}
},
methods: {
// 用户上线
userGoOnline () {
if (this.userInfo) { // 有用户信息时才发送给后端进行保存
this.$socket.emit('goOnline', this.userInfo)
}
},
// 将会话信息存入vuex
getMyConversationsList () {
conversationApi.getMyConversationsList(this.$store.state.user.userInfo.id).then(res => {
this.$store.dispatch('conversation/SET_RECENT_CONVERSATION', {type: 'init', data: res.data.myConversationsList})
})
}
}
}
</script>
<style>
.chat {
height: inherit;
background: transparent;
}
.myImg::before {
background-image: var(--myImgPath);
background-repeat:no-repeat;
background-size: cover;
background-attachment: fixed;
content: '';
opacity: var(--myOpacity);
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: -1;
}
.el-footer {
background-color: #f7f7f7;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
color: #333;
text-align: center;
}
.el-main {
color: #333;
}
.conversationName {
display: flex;
height: inherit;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
.no-conversation {
text-align: center;
}
.no-conversation .text {
color: #909399;
font-size: 20px;
}
.hor-ver-center {
position: absolute;
top: 60%;
left: 60%;
transform: translate(-50%, -60%);
}
</style>