全局scss封装引入背景图片路径报错

本文介绍在使用SCSS进行全局mixin封装时遇到的背景图路径错误问题及解决方案。通过将图片路径前缀从'@'更改为'~@',解决了相对路径引用图片的错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近使用scss做了全局的mixin封装,用到背景图,意外发现通过相对路径引入图片后报错,大致意思为图片路径不对,改为了使用@代替src路径引入图片依然报错,一番百度后带出解决方案通过 ~@ 代替src路径进行图片引入

如下所示

.box{
    // background: url('@/assets/img/bg.png')   
    // 改为
    background: url('~@/assets/img/bg.png') 
}

 

<think>我们正在将Vue3 + Element Plus项目迁移到Vue3 + UniApp + uView Plus项目。用户遇到了一个模块引入错误:`模块找不到 D:/民意测评/vue3-uni-mycp/utils/request`。这个错误表明在迁移过程中,请求模块的路径可能不正确或者文件不存在。 根据引用[1]和[2]的内容,迁移过程中可能会因为配置问题导致白屏或者模块找不到的错误。同时,引用[3]提到图标组件的引入方式,引用[4]提到图片上传组件,引用[5]提到Element Plus分页组件的国际化问题,但这些都不是当前问题的直接原因。不过,我们可以借鉴这些引用中解决问题的思路。 当前问题分析: 1. 错误信息:`模块找不到 D:/民意测评/vue3-uni-mycp/utils/request`,说明在代码中尝试引入`@/utils/request`(或者类似路径)时,找不到该文件。 2. 可能的原因: - 文件路径错误:原项目中的utils/request.js文件没有被正确复制到新项目的对应位置。 - 路径别名配置问题:在新项目中,路径别名`@`可能没有配置,或者配置不正确。 - 文件扩展名问题:在引入时没有写文件扩展名,而新环境默认的解析扩展名可能不包括.js。 解决方案: 步骤1:检查文件是否存在 - 确认原项目中的`utils/request.js`文件是否已经复制到新项目的相同目录下(即`D:/民意测评/vue3-uni-mycp/utils/request.js`是否存在)。 步骤2:检查路径别名配置 - 在Vue3项目中,通常使用`@`代表`src`目录。在UniApp中,默认也是支持的。但为了确保,我们可以检查项目根目录下的`vite.config.js`(如果使用Vite)或`vue.config.js`(如果使用Vue CLI)中的别名配置。 例如,在vite.config.js中: ```js import { defineConfig } from 'vite' import path from 'path' export default defineConfig({ resolve: { alias: { '@': path.resolve(__dirname, './src') } } }) ``` 如果没有使用Vite,而是使用UniApp自带的构建工具,那么默认已经配置了`@`为项目根目录。如果项目结构特殊,可能需要手动配置。 步骤3:检查引入语句 - 确保在代码中引入request模块的语句正确。通常应该是: ```js import request from '@/utils/request' ``` 步骤4:如果文件确实存在且路径正确,但依然报错,可能是文件扩展名解析问题。可以尝试在引入时加上扩展名: ```js import request from '@/utils/request.js' ``` 步骤5:如果使用的是TypeScript,还需要确认`tsconfig.json`中是否配置了路径别名: ```json { "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"] } } } ``` 步骤6:如果以上步骤都确认无误,可能是缓存问题。尝试删除node_modules和dist(或unpackage)目录,重新安装依赖(npm install 或 yarn),然后重新运行项目。 另外,根据引用[2]中提到的错误导入Vue3组件的问题,我们也需要检查在request模块中是否有错误的导入语句。 在迁移过程中,还应该注意: - UniApp和普通Vue3项目在API使用上存在差异(比如网络请求,UniApp推荐使用`uni.request`,而不是`axios`)。 - 因此,原项目中的`request.js`可能是基于`axios`封装的,而UniApp中不能直接使用`axios`(因为UniApp运行在小程序环境,而小程序不支持`axios`使用的XMLHttpRequest)。 所以,我们可能需要重写`request.js`,使用`uni.request`来封装请求。 例如,一个简单的基于`uni.request`的封装: ```js // utils/request.js const baseURL = 'http://your-api-base-url' export const request = (options) => { return new Promise((resolve, reject) => { uni.request({ url: baseURL + options.url, method: options.method || 'GET', data: options.data || {}, header: { 'Content-Type': 'application/json', ...options.header }, success: (res) => { if (res.statusCode >= 200 && res.statusCode < 300) { resolve(res.data) } else { reject(res) } }, fail: (err) => { reject(err) } }) }) } ``` 然后在代码中使用: ```js import { request } from '@/utils/request' request({ url: '/api/survey', method: 'GET' }).then(data => { console.log(data) }) ``` 总结: 1. 确认文件存在且路径正确。 2. 检查路径别名配置。 3. 修改request模块,使用uni.request代替axios(因为UniApp环境不支持axios)。 如果按照以上步骤操作,应该可以解决模块找不到的问题,并且网络请求也能正常运行。 注意:在迁移过程中,类似的问题可能出现在其他模块上,都需要逐一检查和处理。 相关问题: 1. 在UniApp中如何配置路径别名? 2. UniApp中如何封装网络请求? 3. 为什么UniApp中不能使用axios? 4. 如何解决迁移过程中出现的模块找不到错误?</think># Vue3 + UniApp + uView Plus 迁移指南 ## 模块未找到错误分析 根据错误信息 `模块找不到 D:/民意测评/vue3-uni-mycp/utils/request`,这通常是由以下原因导致的: 1. **路径配置问题**:新项目中路径别名配置不正确 2. **文件缺失**:request.js 文件未正确迁移到新项目 3. **构建工具差异**:UniApp 使用自己的构建系统,与 Vite 不同 ## 完整迁移方案 ### 1. 迁移 request.js 文件 首先将原项目的 `utils/request.js` 文件复制到新项目的对应位置: ```javascript // utils/request.js const baseURL = import.meta.env.VITE_API_BASE || 'http://172.26.26.43/dev-api' export const request = (config) => { return new Promise((resolve, reject) => { uni.request({ url: baseURL + config.url, method: config.method || 'GET', data: config.data || {}, header: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${getAuthToken()}`, ...config.headers }, success: (res) => { if (res.statusCode >= 200 && res.statusCode < 300) { resolve(res.data) } else { reject(res) } }, fail: (err) => reject(err) }) }) } function getAuthToken() { const token = uni.getStorageSync('token') if (!token) { uni.showToast({ title: '请先登录', icon: 'none' }) uni.navigateTo({ url: '/pages/login/login' }) return null } return token } ``` ### 2. 配置路径别名 在 UniApp 项目中配置路径别名: ```javascript // vue.config.js const path = require('path') module.exports = { configureWebpack: { resolve: { alias: { '@': path.resolve(__dirname, './src'), 'utils': path.resolve(__dirname, './utils') } } } } ``` ### 3. 修改组件代码 将原代码迁移到 UniApp + uView Plus 框架: ```html <template> <view class="detail-container"> <!-- 索引板块卡片 --> <u-card class="index-card"> <u-form :model="formData" ref="indexForm" class="mobile-form" > <!-- 问卷标题 --> <u-form-item label="问卷标题:" prop="dcWjTitle" label-position="top"> <u-input v-model="formData.dcWjTitle" placeholder="请输入问卷标题" clearable /> </u-form-item> <view class="form-row"> <!-- 被测评人 --> <u-form-item label="被测评人:" prop="dcId" class="inline-form-item"> <u-select v-model="formData.dcId" multiple :remote="true" clearable placeholder="请选择被测评人" @search="searchBdr" :loading="bdrLoading" @focus="handleBdrFocus" > <u-option v-for="item in bdrOptions" :key="item.dcId" :label="item.dcName" :value="item.dcId" /> </u-select> </u-form-item> <!-- 人员部门 --> <u-form-item label="人员部门:" prop="dcDept" class="inline-form-item"> <u-input v-model="formData.dcDept" placeholder="请输入人员部门" clearable /> </u-form-item> </view> <!-- 提交状态 --> <u-form-item label="提交状态:" prop="state"> <u-select v-model="formData.state" placeholder="请选择提交状态" clearable class="mobile-select" > <u-option label="已提交" :value="1" /> <u-option label="未提交" :value="0" /> </u-select> </u-form-item> <!-- 按钮区域 --> <u-form-item class="button-group"> <u-button type="primary" @click="handleSearch" class="action-button" icon="search" > 搜索 </u-button> <u-button @click="handleReset" class="action-button" icon="reload" > 重置 </u-button> </u-form-item> </u-form> </u-card> <!-- 数据显示板块 --> <u-card class="data-card"> <template #header> <view class="card-header"> <u-button type="primary" size="small" icon="reload" @click="fetchData" > 刷新数据 </u-button> </view> </template> <!-- 数据加载 --> <view v-if="loading" class="loading-container"> <u-loading mode="circle" size="40"></u-loading> </view> <view v-else class="card-container"> <view v-for="(item, index) in tableData" :key="item.dcWjId" class="data-card-item" > <!-- 顶部:问卷标题 --> <view class="card-header-section"> <view class="card-title">{{ item.dcWjTitle }}</view> </view> <!-- 中间:其他数据 --> <view class="card-body-section"> <view class="card-row"> <text class="card-label">被测评人:</text> <text class="card-value">{{ item.dcName }}</text> </view> <view class="card-row"> <text class="card-label">部门:</text> <text class="card-value">{{ item.dcDept }}</text> </view> <view class="card-row"> <text class="card-label">创建时间:</text> <text class="card-value">{{ item.createTime }}</text> </view> <view class="card-row"> <text class="card-label">提交时间:</text> <text class="card-value">{{ item.updateTime || '-' }}</text> </view> </view> <!-- 底部:状态、得分和操作按钮 --> <view class="card-footer-section"> <view class="status-container"> <u-tag :type="item.state === '1' ? 'success' : 'info'"> {{ item.state === '1' ? '已提交' : '未提交' }} </u-tag> <view class="score">总分: {{ item.score || '0' }}</view> </view> <u-button size="small" type="primary" @click="handleView(item)" class="action-btn" > 编辑/查看 </u-button> </view> </view> <!-- 空数据提示 --> <u-empty v-if="tableData.length === 0" mode="data" /> </view> <!-- 分页控件 --> <view class="pagination-container"> <u-pagination v-model="pagination.current" :page-size="pagination.size" :total="pagination.total" :show-total="true" :show-pager="true" :page-count="5" @change="handlePageChange" /> </view> </u-card> </view> </template> <script setup> import { ref, reactive, onMounted, onUnmounted } from 'vue'; import { request } from '@/utils/request'; import { onLoad } from '@dcloudio/uni-app'; const API_BASE = import.meta.env.VITE_API_BASE || 'http://172.26.26.43/dev-api'; const API_URL = `${API_BASE}/wjdc/wj/listTx`; const BDR_API_URL = `${API_BASE}/wjdc/wj/getBdrList`; // 被测评人相关数据 const bdrOptions = ref([]); const bdrLoading = ref(false); const bdrCache = ref([]); // 表单数据 const formData = reactive({ dcWjTitle: '', dcId: [], dcDept: '', state: null }); // 表格数据 const tableData = ref([]); const loading = ref(false); // 分页配置 const pagination = reactive({ current: 1, size: 10, total: 0 }); // 请求取消令牌 let requestTask = null; // 处理被测评人输入框获取焦点 const handleBdrFocus = () => { if (bdrCache.value.length === 0) { fetchBdrList(''); } }; // 获取被测评人列表 const fetchBdrList = async (keyword = '') => { bdrLoading.value = true; try { const response = await request({ url: BDR_API_URL, method: 'GET' }); // 处理响应数据 if (Array.isArray(response)) { bdrCache.value = response; filterBdrOptions(keyword); } else if (response.code === 200) { bdrCache.value = response.data || []; filterBdrOptions(keyword); } else { uni.showToast({ title: '获取被测评人列表失败', icon: 'none' }); } } catch (error) { console.error('获取被测评人列表失败:', error); uni.showToast({ title: '获取被测评人列表失败', icon: 'none' }); } finally { bdrLoading.value = false; } }; // 过滤被测评人选项 const filterBdrOptions = (keyword) => { if (keyword) { const searchTerm = keyword.toLowerCase(); bdrOptions.value = bdrCache.value.filter(item => item.dcName && item.dcName.toLowerCase().includes(searchTerm) ).slice(0, 10); } else { bdrOptions.value = bdrCache.value.slice(0, 10); } }; // 搜索被测评人 let searchBdrTimer = null; const searchBdr = (query) => { if (searchBdrTimer) clearTimeout(searchBdrTimer); searchBdrTimer = setTimeout(() => { if (bdrCache.value.length === 0) { fetchBdrList(query); } else { filterBdrOptions(query); } }, 300); }; // 搜索按钮处理 let searchTimer = null; const handleSearch = () => { if (formData.dcId.length > 1) { uni.showToast({ title: '当前只能搜索一个被测人员', icon: 'none', duration: 3000 }); return; } if (searchTimer) clearTimeout(searchTimer); searchTimer = setTimeout(() => { pagination.current = 1; fetchData(); }, 300); }; // 重置按钮处理 const handleReset = () => { formData.dcWjTitle = ''; formData.dcId = []; formData.dcDept = ''; formData.state = null; handleSearch(); }; // 编辑/查看 const handleView = (row) => { uni.navigateTo({ url: `/pages/operation/index?id=${row.dcWjId}` }); }; // 分页大小改变 const handleSizeChange = (size) => { pagination.size = size; fetchData(); }; // 页码改变 const handlePageChange = (page) => { pagination.current = page; fetchData(); }; // 获取数据 const fetchData = async () => { // 取消之前的请求 if (requestTask) { requestTask.abort(); } loading.value = true; try { // 构造请求参数 const params = { pageNum: pagination.current, pageSize: pagination.size, ...formData, dcId: formData.dcId.join(',') }; // 调用API requestTask = uni.request({ url: API_URL, method: 'GET', data: params, success: (res) => { const data = res.data; if (data && data.code === 200) { tableData.value = data.rows || []; pagination.total = data.total || 0; if (tableData.value.length === 0) { uni.showToast({ title: '没有找到匹配的数据', icon: 'none' }); } } else { const errorMsg = data?.msg || '未知错误'; console.error('API返回错误:', errorMsg); uni.showToast({ title: `请求失败: ${errorMsg}`, icon: 'none' }); tableData.value = []; pagination.total = 0; } }, fail: (err) => { if (err.errMsg !== 'request:fail abort') { console.error('获取数据失败:', err); uni.showToast({ title: '网络请求失败', icon: 'none' }); } }, complete: () => { loading.value = false; requestTask = null; } }); } catch (error) { console.error('请求异常:', error); uni.showToast({ title: '请求异常', icon: 'none' }); loading.value = false; } }; onMounted(() => { fetchData(); }); onUnmounted(() => { if (requestTask) { requestTask.abort(); } }); </script> <style lang="scss" scoped> .detail-container { padding: 20rpx; } .index-card { border-radius: 16rpx; margin-bottom: 30rpx; } .form-row { display: flex; flex-wrap: wrap; gap: 20rpx; margin-bottom: 20rpx; } .inline-form-item { flex: 1; min-width: 300rpx; } .button-group { display: flex; gap: 20rpx; margin-top: 30rpx; .action-button { flex: 1; } } .data-card { border-radius: 16rpx; } .card-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(100%, 1fr)); gap: 24rpx; } .data-card-item { background: #fff; border-radius: 16rpx; padding: 24rpx; border: 1rpx solid #ebeef5; box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.05); } .card-header-section { padding-bottom: 16rpx; border-bottom: 1rpx solid #f0f2f5; margin-bottom: 16rpx; } .card-title { font-size: 32rpx; font-weight: bold; color: #303133; } .card-body-section { margin-bottom: 16rpx; } .card-row { display: flex; margin-bottom: 12rpx; font-size: 28rpx; } .card-label { color: #606266; min-width: 160rpx; } .card-value { color: #303133; flex: 1; } .card-footer-section { display: flex; justify-content: space-between; align-items: center; padding-top: 16rpx; border-top: 1rpx solid #f0f2f5; } .status-container { display: flex; align-items: center; gap: 16rpx; } .score { font-size: 28rpx; color: #e6a23c; font-weight: 500; } .pagination-container { margin-top: 40rpx; display: flex; justify-content: center; } .loading-container { display: flex; justify-content: center; align-items: center; height: 400rpx; } /* 响应式调整 */ @media (min-width: 768px) { .card-container { grid-template-columns: repeat(auto-fill, minmax(48%, 1fr)); } .inline-form-item { min-width: 45%; } } </style> ``` ## 关键迁移点说明 1. **请求模块迁移**: - 使用 `uni.request` 替代 `axios` - 实现 `request.js` 封装层,处理统一认证和错误处理 - 解决 `模块找不到` 错误问题 2. **组件替换**: - `el-card` → `u-card` - `el-form` → `u-form` - `el-select` → `u-select` - `el-pagination` → `u-pagination` 3. **路由系统变更**: - 使用 `uni.navigateTo` 替代 `router.push` - 路径格式改为 `/pages/operation/index?id=${id}` 4. **样式适配**: - 使用 `rpx` 替代 `px` 实现响应式 - 调整布局结构适应移动端 - 保留原有UI设计风格 5. **API 差异处理**: - 使用 `uni.getStorageSync` 替代 `localStorage` - 使用 `uni.showToast` 替代 `ElMessage` - 使用 `uni.request` 的 `abort` 方法取消请求 ## 迁移后验证步骤 1. 检查所有网络请求是否正常工作 2. 验证表单输入和选择功能 3. 测试分页和搜索功能 4. 确认页面跳转和参数传递 5. 在不同尺寸设备上测试响应式布局 ## 常见问题解决方案 1. **图标不显示问题**: ```javascript // 在 main.js 中全局引入 uView Plus 图标 import uView from 'uview-plus' import * as icons from 'uview-plus/icons' Object.keys(icons).forEach(key => { uni.$u.config.icons[key] = icons[key] }) app.use(uView) ``` 2. **分页组件中文显示**: ```javascript // main.js import uView from 'uview-plus' import zhCn from 'uview-plus/locale/lang/zh-CN' app.use(uView, { locale: zhCn }) ``` 3. **图片上传适配**: ```html <u-upload :fileList="fileList" @afterRead="afterRead" @delete="deleteFile" :maxCount="3" ></u-upload> ``` 迁移完成后,您的应用将完全兼容 UniApp 多端环境(H5、小程序、App),同时保持原有的功能和用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值