這篇文章主要總結了一些在專案中遇到的一些小問題以及對應的解決方案,避免日後踩坑,後續補充中,如果你對這些問題有不同的解答,歡迎評論
1. 輸入框使用v-model 繫結值,但是不能改變
// 第一種情況
<el-input v-model="form.title"></el-input>
// 初始化
data () {
return {
form: {}
}
}
// 賦值,其中formData為父元件傳過來的資料
mounted (){
this.form.title = this.formData.title
}
// 這裡不生效的原因為title沒有初始化
data () {
return {
form: {title:''}}
}
// 第二種情況
在表單中使用時,用:model=""給輸入框賦值
<el-form :model="formData">
<el-form-item>
<el-input placeholder="請輸入" :model="formData.value" size="small"/>
</el-form-item>
</el-form>
// 解決方案,改為
<el-input placeholder="請輸入" v-model="formData.value" size="small"/>
複製程式碼
2. 文字內容不對html標籤轉譯
我想要輸入下面的內容,但是儲存資料後,就變成了aaa
解決辦法: 如果是html內容、javascript、xml或其他特殊內容,使用
<xmp></xmp>
如果是有空格和回車這樣的特殊字元的簡單文字 在文字外加<pre></pre>
標籤
3. 基礎匯出功能
SensitiveOperationExport(params).then(res => {
if (res.data.code === '200') {
// 這裡是匯出
window.location.href = res.data.data.path
this.$message({
message: '匯出成功!',
type: 'success'
})
} else {
this.$message.error({message: '匯出失敗!'})
}
})
複製程式碼
4. 使用element table 時,禁用部分核取方塊
<el-table-column type="selection" align="center" fixed :selectable="selectable"></el-table-column>
複製程式碼
官網上有這樣一個操作
selectable
, 僅對 type=selection 的列有效,型別為 Function,Function 的返回值用來決定這一行的 CheckBox 是否可以勾選
5.介面返回的資料為json型別,展示到表格中時,可以這樣轉換
// 資料結構 content: "{'title': '這是標題'}"
this.title = JSON.parse(content).title
複製程式碼
6. 列表中點選圖片放大功能
安裝viewer,可支援圖片的切換,旋轉,放大等功能,具體操作文件可百度檢視,使用在頁面中也非常簡單,第一步,全域性配置
// main.js 中引入配置
Viewer.setDefaults({
'zIndex': 9999,
'inline': false, // 是否預設展示縮圖
'button': true, // 右上角按鈕
'navbar': true, // 底部縮圖
'title': true, // 當前圖片標題
'toolbar': true, // 底部工具欄
'tooltip': true, // 顯示縮放百分比
'movable': false, // 是否可以移動
'zoomable': true, // 是否可以縮放
'rotatable': true, // 是否可旋轉
'scalable': true, // 是否可翻轉
'transition': true, // 使用 CSS3 過度
'fullscreen': true, // 播放時是否全屏
'keyboard': true, // 是否支援鍵盤
'url': 'data-source'
})
// 頁面中使用
<viewer>
<img :src="scope.row.content "/>
</viewer>
複製程式碼
7. 上移和下移操作
一般來說,上移和下移是掉介面操作的,但是也有不掉介面的
/ 上移
moveUp (index, row) {
if (index > 0) {
let upDate = this.tableData[index - 1]
this.tableData.splice(index - 1, 1)
this.tableData.splice(index, 0, upDate)
}
},
// 下移
moveDown (index, row) {
if ((index + 1) === this.tableData.length) {
console.log('已經是最後一條,不可下移')
} else {
let downDate = this.tableData[index + 1]
this.tableData.splice(index + 1, 1)
this.tableData.splice(index, 0, downDate)
}
}
複製程式碼
8. 表格的全選和反選
<el-table :data="tableData" border :select-all="allSelect" @selection-change="changeFun" ref="form" height="700"></el-table>
// tableData 是表格資料
<div>
<el-button @click="toggleSelect(tableData)">全選</el-button>
<el-button @click="reverseSelect(tableData)">反選</el-button>
</div>
// 全選
toggleSelect (rows) {
if (rows) {
rows.forEach(row => {
this.$refs.form.toggleRowSelection(row, !this.allSelect)
})
this.allSelect = !this.allSelect
}
},
// 反選
reverseSelect (rows) {
let checked = this.data
if (rows) {
rows.map(row => {
checked && checked.map(item => {
if (row.index !== item.index) {
this.$refs.form.toggleRowSelection(item, false)
this.$refs.form.toggleRowSelection(row, true)
} else {
this.$refs.form.toggleRowSelection(row, false)
}
})
})
if (checked.length === 0) {
rows.forEach(row => {
this.$refs.form.toggleRowSelection(row, true)
})
}
}
},
// 獲取選擇的資料
changeFun (val) {
this.data = val
}
複製程式碼
9. 按住說話功能
這個功能依賴於recorder.js, 上一篇文章已經介紹過用法了,這裡就不在細說
10. 表格編輯和儲存切換
// editColorShow: '' // 設定敏感操作預設顯示編輯
// clearEdit: '000' // 替換editColorShow的值
<el-table-column label="操作" align="center"
width="200">
<template slot-scope="scope">
<el-button size="small" v-if="editColorShow !== scope.$index" type="primary" @click="editColor(scope.$index, scope.row)">編輯</el-button>
<el-button size="small" v-if="editColorShow === scope.$index" type="primary" @click="submitSettingOperation(scope.$index, scope.row)">儲存</el-button>
</template>
</el-table-column>
// 方法中這樣
editColor (index, row) {
this.editColorShow = index
},
submitSettingOperation (index, data) {
this.editColorShow = this.clearEdit
}
複製程式碼
11. 深拷貝
第一種:
function copy(arr) {
var newObj = arr.constructor === Array ? [] : {}
if (typeof arr === 'object') {
for (var i in arr) {
if (typeof arr[i] === 'object') {
newObj[i] = copy(arr[i])
}
newObj[i] = arr[i]
}
return newObj
} else {
return
}
}
複製程式碼
第二種
function copy (obj) {
var newObj = obj.constructor === Array ? [] : {}
newObj = JSON.parse(JSON.stringify(obj))
return newObj
}
複製程式碼
12.表單重置問題
之前重置表單的時候都是this.form.xx='',如果是一兩個還好,但是如果表單很多的話就不是很適用了,發現了一個很便捷的操作,只要一行程式碼就搞定了
this.$refs['infoForm'].resetFields()
// 前提是要重置的輸入框必須設定prop屬性才可以
複製程式碼
13. txt檔案匯出,有兩種方式
第一種 純前端下載
fetch('https://xxxxx.com/' + item.path).then(res => res.blob().then(blob => {
var a = document.createElement('a')
var url = window.URL.createObjectURL(blob)
var filename = 'text.txt'
a.href = url
a.download = filename
a.click()
window.URL.revokeObjectURL(url)
}))
複製程式碼
第二種 獲取到txt的內容後下載
createDownload (fileName, content) {
var blob = new Blob([content])
var link = document.createElement('a')
var bodyEle = document.getElementsByTagName('body')[0]
link.innerHTML = fileName
link.download = fileName
link.href = URL.createObjectURL(blob)
bodyEle.appendChild(link)
link.click()
bodyEle.removeChild(link)
}
複製程式碼
雖然兩種都可以實現下載,但是要保證下載的介面可以在頁面中訪問到,不會有跨域等問題
14. 匯出exel
匯出表格這裡提供兩種方法,第一種依賴第三方,首先下載三個依賴
下載Blob.js和Export2Excel.js 兩個檔案,引入檔案中
// npm install file-saver xlsx script-loader --save
// 匯出
onExportExcel (formName) {
import('@/vendor/Export2Excel').then(excel => {
// 表格的title
const tHeader = ['訂單編號', '姓名', '員工編號', '手機號', '公司']
// 對應的欄位
const filterVal = ['sn', 'user_name', 'user_no', 'user_phone', 'user_company']
const data = this.formatJson(filterVal, this.dataTable)
excel.export_json_to_excel({
header: tHeader,
data,
filename: `訂單列表`
})
})
},
formatJson (filterVal, jsonData) {
let arr = jsonData.map(v => filterVal.map(j => v[j]))
return arr
}
複製程式碼
第二種 通過vue-json-excel,具體細節可參考vue-json-excel
// 安裝 npm install vue-json-excel,引入
// vue中使用
<download-excel
class = "btn btn-default"
:data = "json_data"
:fields = "json_fields"
worksheet = "My Worksheet"
name = "filename.xls">
</download-excel>
data(){
return {
// 要匯出的欄位
json_fields: {
'Complete name': 'name',
'City': 'city',
'Telephone': 'phone.mobile',
'Telephone 2' : {
field: 'phone.landline',
callback: (value) => {
return `Landline Phone - ${value}`;
}
},
},
// 要匯出的資料
json_data: [
{
'name': 'Tony Peña',
'city': 'New York',
'country': 'United States',
'birthdate': '1978-03-15',
'phone': {
'mobile': '1-541-754-3010',
'landline': '(541) 754-3010'
}
},
{
'name': 'Thessaloniki',
'city': 'Athens',
'country': 'Greece',
'birthdate': '1987-11-23',
'phone': {
'mobile': '+1 855 275 5071',
'landline': '(2741) 2621-244'
}
}
],
json_meta: [
[
{
'key': 'charset',
'value': 'utf-8'
}
]
]
}
}
複製程式碼
15.導航欄中使用iconfont,選中不變色問題
先來看看對比
專案是基於element-ui開發的,避免不了使用到圖示,所以阿里相簿是個很好的選擇,這裡遇到的問題是左側導航欄選中後,文字顏色發生變化,但是圖示卻一直不變,一般來說引用阿里相簿有三種方式:Unicode、Font Class 、symbol;我用的是symbol方式引用,具體如下
1.圖示選用的是svg格式,選擇要使用的圖示,下載svg格式
2.建立icon資料夾用於存放圖示,建立svgIcon資料夾用於使用圖示,使用如下
3.這裡導致圖示不變色的原因是下載的圖示本身就是帶有顏色的,那麼在通過symbol獲取圖示時會在svg的path中增加fill屬性,導致無法更改顏色,可以將圖示中fill屬性置空,這樣就可以解決了
16. vue模糊搜尋路由功能
需求: 導航欄中提供搜尋框,可根據輸入的頁面名稱,跳轉到指定頁面,程式碼如下
<template>
<div>
<el-select
ref="headerSearchSelect"
v-model="search"
:remote-method="querySearch" // 遠端搜尋方法
remote // 是否為遠端搜尋
filterable // 是否可搜尋
default-first-option // 輸入框按下回車,返回第一個匹配項,需搭配filterable或remote使用
placeholder="搜尋"
class="header-search-select"
@change="change"
>
<el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" />
</el-select>
</div>
</template>
<script>
import path from 'path';
export default {
// 獲取到當前賬戶下的所有可見頁面路由
props: {
routers: {
type: Array
}
},
data () {
return {
search: '',
options: [],
searchPool: []
}
},
computed: {
routes() {
return this.routers
}
},
mounted () {
this.searchPool = this.generateRoutes(this.routes)
},
methods: {
// 遠端搜尋
querySearch (query) {
if (query !== '') {
// 陣列去重
this.options = Array.from(new Set(this.searchQuery(query)))
} else {
this.options = []
}
},
// 改變時跳轉
change (val) {
// 判斷當前頁與搜尋的頁面是否一致,如一致則清空不跳轉,反之跳轉
if (val.path !== this.$router.history.current.path) {
this.$router.push(val.path)
// 跳轉路徑後清空搜尋框內容,也可以不清空
this.search = ''
this.options = []
} else {
this.search = ''
this.options = []
}
},
// 篩選符合條件的路由
searchQuery (query) {
const list = []
this.searchPool.map(item => {
item.title.filter(items => {
if (items.indexOf(query) > -1) {
list.push(item)
}
})
})
return list
},
// 處理路由資料
generateRoutes(routes, basePath = '/', prefixTitle = []) {
let res = []
for (const router of routes) {
if (router.hidden) { continue }
const data = {
path: path.resolve(basePath, router.path),
title: [...prefixTitle]
}
if (router.meta && router.meta.title) {
data.title = [...data.title, router.meta.title]
if (router.redirect !== 'noRedirect') {
res.push(data)
}
}
// recursive child routes
if (router.children) {
const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
if (tempRoutes.length >= 1) {
res = [...res, ...tempRoutes]
}
}
}
return res
}
}
}
</script>
複製程式碼
需要注意的點是路由的寫法,一定要有對應的title,例如這樣
// 當頁面沒有子級選單時
{
path: '/log',
component: Home,
name: 'Log',
redirect: '/redirect',
children: [
{
path: 'index',
name: 'LogIndex',
component: _import('log/Index'),
meta: {
title: '日誌管理',
roles: [RoleName.Super, RoleName.AfterSale],
icon: 'custom-rizhi'
}
}
]
}
// 當頁面有子級選單時
{
path: '/operation',
component: Home,
name: 'Operation',
redirect: '/redirect',
meta: { title: '運營管理', icon: 'custom-yunying1' }, // 區別在於這裡,有子級的一定要在這加上meta
children: [
{
path: 'payment',
name: 'OperationPayment',
component: _import('operation/Payment'),
meta: {
title: '支付管理',
roles: [RoleName.Operator] // 可通過roles判斷當前使用者是否有許可權檢視該頁面
}
},
{
path: 'shop',
name: 'OperationShop',
component: _import('operation/Shop'),
meta: {
title: '店鋪管理',
roles: [RoleName.Super, RoleName.Operator, RoleName.Staff, RoleName.Marketer]
}
},
{
path: 'banner',
name: 'OperationBanner',
component: _import('operation/Banner'),
meta: {
title: '圖片管理',
roles: [RoleName.Super, RoleName.Operator, RoleName.Staff, RoleName.Marketer]
}
}
]
}
複製程式碼
補充幾個關於路由的小問題
<router-link to=""></router-link>
: 解析成a標籤,通過to指定跳轉路徑<router-view>
:檢視渲染元件路由引入元件的兩種方式
import app from '@/view/app'
{
path: '/',
component: app, // 第一種:直接引入
component: () => import('@/view/app') // 第二種:懶載入
}
複製程式碼
- 動態路由
{
path: '/argu:name' // name為動態路由引數
// 巢狀路由
path: '/parent',
children: [
{
path: '/child'
}
],
// 命名路由
path: '/login',
name: 'name' // 命名,在router-link中可以:to="{name: 'login'}"跳轉
}
複製程式碼
- 命名檢視,可載入多個元件
<router-view/>
<router-view name="email"/>
{
path: 'names',
components: {
default: () => import('@/view/app'),
email: () => import('@/view/message')
}
}
複製程式碼
- 重定向三種寫法
{
path: '/email',
redirect: '/main', // 第一種
redirect: { // 第二種
name: 'main'
},
redirect: to => { // 第三種
return {
name: 'main'
}
}
}
複製程式碼
6.別名(訪問別名就相當於訪問當前路由)
// 例如,訪問main_index就相當於訪問main
{
path: '/main',
alias: '/main_index'
}
複製程式碼
7.跳轉
this.$router.push('/home') // 可直接跳轉到home頁
// 攜帶引數跳轉一
this.$router.push({
name: 'home',
querry: {
// 引數,顯示在位址列中
}
})
// 攜帶引數二
this.$router.push({
params: {
// 引數
}
})
// 攜帶引數三
this.$router.push({
// 第三種
name: '我是引數'
path:`/home${name}`
})
複製程式碼
8.替換(push和replace區別)
push瀏覽器會有記錄,返回上一頁,replace會把當前頁當為父級頁
舉個例子:當前頁為home,點選跳轉到about頁,點選push跳轉後在返回,上一頁為home
當前頁為home,點選跳轉到about頁,點選replace跳轉後在返回,上一頁為about
this.$router.replace({
name: 'home'
})
- props可以在router中傳值
{
path: '/about',
// 第一種
props: {
foood: 'apple'
},
// 第二種
props: router => {
food: router.query.food // 引數中傳遞了food值
}
}
// 頁面中獲取
props: {
foood: {
type: string,
default: 'orange'
}
}
複製程式碼
router
中配置mode: 'history'
可以去除位址列#,但需要後端配置支援router.before()
前置跳轉,可用於跳轉前判斷是否登入,是否有許可權