这篇文章主要总结了一些在项目中遇到的一些小问题以及对应的解决方案,避免往后踩坑,后续补充中,若是你对这些问题有不一样的解答,欢迎评论javascript
// 第一种状况
<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"/>
复制代码
我想要输入下面的内容,可是保存数据后,就变成了aaahtml
解决办法: 若是是html内容、javascript、xml或其余特殊内容,使用
<xmp></xmp>
若是是有空格和回车这样的特殊字符的简单文本 在文本外加<pre></pre>
标签前端
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: '导出失败!'})
}
})
复制代码
<el-table-column type="selection" align="center" fixed :selectable="selectable"></el-table-column>
复制代码
官网上有这样一个操做
selectable
, 仅对 type=selection 的列有效,类型为 Function,Function 的返回值用来决定这一行的 CheckBox 是否能够勾选vue
// 数据结构 content: "{'title': '这是标题'}"
this.title = JSON.parse(content).title
复制代码
安装viewer,可支持图片的切换,旋转,放大等功能,具体操做文档可百度查看,使用在页面中也很是简单,第一步,全局配置java
// 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>
复制代码
通常来讲,上移和下移是掉接口操做的,可是也有不掉接口的web
/ 上移
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)
}
}
复制代码
<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
}
复制代码
这个功能依赖于recorder.js, 上一篇文章已经介绍过用法了,这里就不在细说npm
// 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
}
复制代码
第一种:element-ui
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
}
}
复制代码
第二种json
function copy (obj) {
var newObj = obj.constructor === Array ? [] : {}
newObj = JSON.parse(JSON.stringify(obj))
return newObj
}
复制代码
以前重置表单的时候都是this.form.xx='',若是是一两个还好,可是若是表单不少的话就不是很适用了,发现了一个很便捷的操做,只要一行代码就搞定了后端
this.$refs['infoForm'].resetFields()
// 前提是要重置的输入框必须设置prop属性才能够
复制代码
第一种 纯前端下载
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)
}
复制代码
虽然两种均可以实现下载,可是要保证下载的接口能够在页面中访问到,不会有跨域等问题
导出表格这里提供两种方法,第一种依赖第三方,首先下载三个依赖
下载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'
}
]
]
}
}
复制代码
先来看看对比
项目是基于element-ui开发的,避免不了使用到图标,因此阿里图库是个很好的选择,这里遇到的问题是左侧导航栏选中后,文字颜色发生变化,可是图标却一直不变,通常来讲引用阿里图库有三种方式:Unicode、Font Class 、symbol;我用的是symbol方式引用,具体以下
1.图标选用的是svg格式,选择要使用的图标,下载svg格式
2.建立icon文件夹用于存放图标,建立svgIcon文件夹用于使用图标,使用以下
需求: 导航栏中提供搜索框,可根据输入的页面名称,跳转到指定页面,代码以下
<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()
前置跳转,可用于跳转前判断是否登陆,是否有权限