vue

vue

vue+bootstrap4+tooltip.js 实现简单的tooltip

VUElopo1983 发表了文章 • 0 个评论 • 2272 次浏览 • 2018-01-24 17:33 • 来自相关话题

<template lang="pug">
button(:class="`btn btn-${size} btn-${stype}`",ref="button",@mouseover="initPopper")
<slot></slot>
<template v-if="!$slots.default">{{label}}</template>
</template>
<script>
import lib from '@/utils/lib'
import btn from '@/components/comp/button'
import Tooltip from 'tooltip.js'
export default {
name: 'vbaToolTip',
components: {
btn
},
props: {
label: String,
size: String,
stype: String,
placement: {
type: String,
default: 'top'
},
html: {
type: Boolean,
default: false
},
content: String
},
data() {
return {
popperInstance: null
}
},
methods: {
initPopper() {
if (!this.popperInstance) {
const vm = this
this.popperInstance = new Tooltip(this.$refs.button, {
placement: `${this.placement}`,
template: `<div class="tooltip bs-tooltip-${
this.placement
}" role="tooltip">
<div class="tooltip-arrow arrow"></div>
<div class="tooltip-inner">
</div>
</div>`,
title: this.content,
html:this.html,
contaier:document.getElementsByTagName('body'),
onCreate() {
vm.$emit('on-create', this.popperInstance)
},
onUpdate() {
vm.$emit('on-update', this.popperInstance)
}
})
}
}
}
}
</script>
<style lang="less">
.tooltip {
opacity: 1 !important;
}
</style> 查看全部
<template lang="pug">
button(:class="`btn btn-${size} btn-${stype}`",ref="button",@mouseover="initPopper")
<slot></slot>
<template v-if="!$slots.default">{{label}}</template>
</template>
<script>
import lib from '@/utils/lib'
import btn from '@/components/comp/button'
import Tooltip from 'tooltip.js'
export default {
name: 'vbaToolTip',
components: {
btn
},
props: {
label: String,
size: String,
stype: String,
placement: {
type: String,
default: 'top'
},
html: {
type: Boolean,
default: false
},
content: String
},
data() {
return {
popperInstance: null
}
},
methods: {
initPopper() {
if (!this.popperInstance) {
const vm = this
this.popperInstance = new Tooltip(this.$refs.button, {
placement: `${this.placement}`,
template: `<div class="tooltip bs-tooltip-${
this.placement
}" role="tooltip">
<div class="tooltip-arrow arrow"></div>
<div class="tooltip-inner">
</div>
</div>`,
title: this.content,
html:this.html,
contaier:document.getElementsByTagName('body'),
onCreate() {
vm.$emit('on-create', this.popperInstance)
},
onUpdate() {
vm.$emit('on-update', this.popperInstance)
}
})
}
}
}
}
</script>
<style lang="less">
.tooltip {
opacity: 1 !important;
}
</style>

vue2.x 将table 内容导出excel 下载(转换页面table数据)

VUElopo1983 发表了文章 • 0 个评论 • 2411 次浏览 • 2018-01-22 18:06 • 来自相关话题

目前仅支持chrome?downloadjs需自行引入加载 对应的tab HTMLCollection 也应根据你的UI组件进行替换









<template lang="pug">
btn(:stype="stype",:size="size",@click="exportOffice(tid)")
slot
template(v-if="!$slots.default") {{label}}
</template>

<script>
/**
* bootstrap 4.x --> components --> table-->table
*
* @param {String} label 按钮名称
* @param {String} stype 样式
* @param {String} size 大小
*
* 注意以上参数为内置按钮参数 可根据你目前使用的UI组件进行修改
*
* @param {String} tid 表格ID
* @param {String} xlsname excel名称
* @param {String} filters 需过滤的cell className
*
* @date 2018-1-22
*
* @version v1.0.0 beta
*
* @important 注意目前仅支持chrome下使用
*
**/
import download from 'downloadjs'
import btn from '@/components/comp/button'
export default {
name: 'tableToExcel',
components: {
btn
},
props: {
// btn 组件参数
label: String,
stype: String,
size: {
type: String,
default: 'sm'
},
tid: String,
xlsname:String,
filters: String
},
methods: {
base64ToBlob: function(data, mime) {
let base64 = window.btoa(window.unescape(encodeURIComponent(data)))
let bstr = atob(base64)
let n = bstr.length
let u8arr = new Uint8ClampedArray(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], { type: mime })
},
exportOffice(tableID) {
let elms = document.getElementById(tableID).cloneNode(true)
let table = elms.childNodes[1].childNodes[0]
// table根据你的ui组件修改对应的HTMLCollection
let rows = table.rows.length
let cells = table.rows.item(0).cells.length
let tableArr = table.getElementsByClassName(this.filters)
for (let i = 0; i < rows; i++) {
table.rows<em>.deleteCell(cells-1)
}
let excelContent = table.innerHTML
let excelFile = `<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html4 ... Bmeta name=ProgId content=Excel.Sheet> <meta name=Generator content="Microsoft Excel 11"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>${excelContent}</table></body></html>`
let blob = this.base64ToBlob(excelFile, 'application/vnd.ms-excel')
download(blob, this.xlsname||this.$route.name+moment().format('x'), 'application/vnd.ms-excel')
}
}
}
</script> 查看全部

目前仅支持chrome?downloadjs需自行引入加载 对应的tab HTMLCollection 也应根据你的UI组件进行替换



table.png


QQ图片20180122224557.png
<template lang="pug">
btn(:stype="stype",:size="size",@click="exportOffice(tid)")
slot
template(v-if="!$slots.default") {{label}}
</template>

<script>
/**
* bootstrap 4.x --> components --> table-->table
*
* @param {String} label 按钮名称
* @param {String} stype 样式
* @param {String} size 大小
*
* 注意以上参数为内置按钮参数 可根据你目前使用的UI组件进行修改
*
* @param {String} tid 表格ID
* @param {String} xlsname excel名称
* @param {String} filters 需过滤的cell className
*
* @date 2018-1-22
*
* @version v1.0.0 beta
*
* @important 注意目前仅支持chrome下使用
*
**/
import download from 'downloadjs'
import btn from '@/components/comp/button'
export default {
name: 'tableToExcel',
components: {
btn
},
props: {
// btn 组件参数
label: String,
stype: String,
size: {
type: String,
default: 'sm'
},
tid: String,
xlsname:String,
filters: String
},
methods: {
base64ToBlob: function(data, mime) {
let base64 = window.btoa(window.unescape(encodeURIComponent(data)))
let bstr = atob(base64)
let n = bstr.length
let u8arr = new Uint8ClampedArray(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], { type: mime })
},
exportOffice(tableID) {
let elms = document.getElementById(tableID).cloneNode(true)
let table = elms.childNodes[1].childNodes[0]
// table根据你的ui组件修改对应的HTMLCollection
let rows = table.rows.length
let cells = table.rows.item(0).cells.length
let tableArr = table.getElementsByClassName(this.filters)
for (let i = 0; i < rows; i++) {
table.rows<em>.deleteCell(cells-1)
}
let excelContent = table.innerHTML
let excelFile = `<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html4 ... Bmeta name=ProgId content=Excel.Sheet> <meta name=Generator content="Microsoft Excel 11"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>${excelContent}</table></body></html>`
let blob = this.base64ToBlob(excelFile, 'application/vnd.ms-excel')
download(blob, this.xlsname||this.$route.name+moment().format('x'), 'application/vnd.ms-excel')
}
}
}
</script>

vue2.x 将table 内容导出excel 下载(直接转换渲染数据)

VUElopo1983 发表了文章 • 0 个评论 • 2105 次浏览 • 2018-01-22 17:51 • 来自相关话题

https://github.com/jecovier/vue-json-excel
<template lang="pug">
btn(:stype="stype",:size="size",@click="generate")
slot
template(v-if="!$slots.default") {{label}}
</template>
<script>
// https://github.com/jecovier/vue-json-excel
import download from 'downloadjs'
import btn from '@/components/comp/button'
export default {
name: 'vbaJsonExcel',
components: {
btn
},
props: {
// btn 组件参数
label: String,
stype: String,
size: {
type: String,
default: 'sm'
},
// 设置导出格式 [xls, csv], 默认: xls
type: {
type: String,
default: 'xls'
},
// Json to download
data: {
type: Array,
required: true
},
// 导出的表格标题
// 若不设置将使用默认的json数据key
fields: {
type: Object,
required: true
},
// excel标题
title: {
type: String,
default: null
},
// 导出excel标题名称
name: {
type: String,
default: 'datas.xls'
},
meta: {
type: Array,
default: () =>
}
},
computed: {
// unique identifier
idName: function() {
var now = new Date().getTime()
return 'export_' + now
}
},
methods: {
generate() {
if (!this.data.length) {
return
}
let json = this.getProcessedJson(this.data, this.fields)
if (this.type == 'csv') {
return this.export(this.jsonToCSV(json), this.name, 'application/csv')
}
return this.export(
this.jsonToXLS(json),
this.name,
'application/vnd.ms-excel'
)
},
/*
Use downloadjs to generate the download link
*/
export: function(data, filename, mime) {
let blob = this.base64ToBlob(data, mime)
download(blob, filename, mime)
},
/*
jsonToXLS
---------------
Transform json data into an xml document with MS Excel format, sadly
this format show a prompt when open due to a default behavior
on Microsoft office. It's recommended to use CSV format instead.
*/
jsonToXLS: function(data) {
let xlsTemp =
'<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html4 ... Bmeta name=ProgId content=Excel.Sheet> <meta name=Generator content="Microsoft Excel 11"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>${table}</table></body></html>'
let xlsData = '<thead><tr>'

if (this.title != null) {
xlsData +=
'<tr><th colspan="' +
Object.keys(data[0]).length +
'">' +
this.title +
'<th></tr>'
}

for (let key in data[0]) {
xlsData += '<th>' + key + '</th>'
}
xlsData += '</tr></thead>'
xlsData += '<tbody>'

data.map(function(item, index) {
xlsData += '<tbody><tr>'
for (let key in item) {
xlsData += '<td>' + item[key] + '</td>'
}
xlsData += '</tr></tbody>'
})
return xlsTemp.replace('${table}', xlsData)
},
/*
jsonToCSV
---------------
Transform json data into an CSV file.
*/
jsonToCSV: function(data) {
var csvData = ''

if (this.title != null) {
csvData += this.title + '\r\n'
}

for (let key in data[0]) {
csvData += key + ','
}
csvData = csvData.slice(0, csvData.length - 1)
csvData += '\r\n'

data.map(function(item) {
for (let key in item) {
let escapedCSV = item[key] + '' // cast Numbers to string
if (escapedCSV.match(/[,"\n]/)) {
escapedCSV = '"' + escapedCSV.replace(/\"/g, '""') + '"'
}
csvData += escapedCSV + ','
}
csvData = csvData.slice(0, csvData.length - 1)
csvData += '\r\n'
})
return csvData
},
/*
getProcessedJson
---------------
Get only the data to export, if no fields are set return all the data
*/
getProcessedJson: function(data, header) {
let keys = this.getKeys(data, header)
let newData =
let _self = this
data.map(function(item, index) {
let newItem = {}
for (let label in keys) {
var iii = item
let property = keys[label]
newItem[label] = _self.getNestedData(property, item)
}
newData.push(newItem)
})

return newData
},
getKeys: function(data, header) {
if (header) {
return header
}

let keys = {}
for (let key in data[0]) {
keys[key] = key
}
return keys
},
getNestedData: function(key, item) {
let valueFromNestedKey = null
let keyNestedSplit = key.split('.')
valueFromNestedKey = item[keyNestedSplit[0]]
for (let j = 1; j < keyNestedSplit.length; j++) {
valueFromNestedKey = valueFromNestedKey[keyNestedSplit[j]]
}
return valueFromNestedKey
},
base64ToBlob: function(data, mime) {
let base64 = window.btoa(window.unescape(encodeURIComponent(data)))
let bstr = atob(base64)
let n = bstr.length
let u8arr = new Uint8ClampedArray(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], { type: mime })
}
} // end methods
}
</script>


fileds 获取(该组件需要对标题进行格式化)
?
methods
setFields() {
let _this = this
let Obj = new Object()
let arr = this.$refs.tables.$slots.default
.filter(e => e.componentInstance)
.map((column, index) => {
const instance = column.componentOptions.propsData
return instance
})
arr.forEach(element => {
if (!!element['prop']) {
_this.xlsfields[element['label']] = element['prop']
}
})
}mounted
mounted() {
this.setFields()
} 查看全部

https://github.com/jecovier/vue-json-excel


<template lang="pug">
btn(:stype="stype",:size="size",@click="generate")
slot
template(v-if="!$slots.default") {{label}}
</template>
<script>
// https://github.com/jecovier/vue-json-excel
import download from 'downloadjs'
import btn from '@/components/comp/button'
export default {
name: 'vbaJsonExcel',
components: {
btn
},
props: {
// btn 组件参数
label: String,
stype: String,
size: {
type: String,
default: 'sm'
},
// 设置导出格式 [xls, csv], 默认: xls
type: {
type: String,
default: 'xls'
},
// Json to download
data: {
type: Array,
required: true
},
// 导出的表格标题
// 若不设置将使用默认的json数据key
fields: {
type: Object,
required: true
},
// excel标题
title: {
type: String,
default: null
},
// 导出excel标题名称
name: {
type: String,
default: 'datas.xls'
},
meta: {
type: Array,
default: () =>
}
},
computed: {
// unique identifier
idName: function() {
var now = new Date().getTime()
return 'export_' + now
}
},
methods: {
generate() {
if (!this.data.length) {
return
}
let json = this.getProcessedJson(this.data, this.fields)
if (this.type == 'csv') {
return this.export(this.jsonToCSV(json), this.name, 'application/csv')
}
return this.export(
this.jsonToXLS(json),
this.name,
'application/vnd.ms-excel'
)
},
/*
Use downloadjs to generate the download link
*/
export: function(data, filename, mime) {
let blob = this.base64ToBlob(data, mime)
download(blob, filename, mime)
},
/*
jsonToXLS
---------------
Transform json data into an xml document with MS Excel format, sadly
this format show a prompt when open due to a default behavior
on Microsoft office. It's recommended to use CSV format instead.
*/
jsonToXLS: function(data) {
let xlsTemp =
'<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html4 ... Bmeta name=ProgId content=Excel.Sheet> <meta name=Generator content="Microsoft Excel 11"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>${table}</table></body></html>'
let xlsData = '<thead><tr>'

if (this.title != null) {
xlsData +=
'<tr><th colspan="' +
Object.keys(data[0]).length +
'">' +
this.title +
'<th></tr>'
}

for (let key in data[0]) {
xlsData += '<th>' + key + '</th>'
}
xlsData += '</tr></thead>'
xlsData += '<tbody>'

data.map(function(item, index) {
xlsData += '<tbody><tr>'
for (let key in item) {
xlsData += '<td>' + item[key] + '</td>'
}
xlsData += '</tr></tbody>'
})
return xlsTemp.replace('${table}', xlsData)
},
/*
jsonToCSV
---------------
Transform json data into an CSV file.
*/
jsonToCSV: function(data) {
var csvData = ''

if (this.title != null) {
csvData += this.title + '\r\n'
}

for (let key in data[0]) {
csvData += key + ','
}
csvData = csvData.slice(0, csvData.length - 1)
csvData += '\r\n'

data.map(function(item) {
for (let key in item) {
let escapedCSV = item[key] + '' // cast Numbers to string
if (escapedCSV.match(/[,"\n]/)) {
escapedCSV = '"' + escapedCSV.replace(/\"/g, '""') + '"'
}
csvData += escapedCSV + ','
}
csvData = csvData.slice(0, csvData.length - 1)
csvData += '\r\n'
})
return csvData
},
/*
getProcessedJson
---------------
Get only the data to export, if no fields are set return all the data
*/
getProcessedJson: function(data, header) {
let keys = this.getKeys(data, header)
let newData =
let _self = this
data.map(function(item, index) {
let newItem = {}
for (let label in keys) {
var iii = item
let property = keys[label]
newItem[label] = _self.getNestedData(property, item)
}
newData.push(newItem)
})

return newData
},
getKeys: function(data, header) {
if (header) {
return header
}

let keys = {}
for (let key in data[0]) {
keys[key] = key
}
return keys
},
getNestedData: function(key, item) {
let valueFromNestedKey = null
let keyNestedSplit = key.split('.')
valueFromNestedKey = item[keyNestedSplit[0]]
for (let j = 1; j < keyNestedSplit.length; j++) {
valueFromNestedKey = valueFromNestedKey[keyNestedSplit[j]]
}
return valueFromNestedKey
},
base64ToBlob: function(data, mime) {
let base64 = window.btoa(window.unescape(encodeURIComponent(data)))
let bstr = atob(base64)
let n = bstr.length
let u8arr = new Uint8ClampedArray(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], { type: mime })
}
} // end methods
}
</script>


fileds 获取(该组件需要对标题进行格式化)
?
methods
    setFields() {
let _this = this
let Obj = new Object()
let arr = this.$refs.tables.$slots.default
.filter(e => e.componentInstance)
.map((column, index) => {
const instance = column.componentOptions.propsData
return instance
})
arr.forEach(element => {
if (!!element['prop']) {
_this.xlsfields[element['label']] = element['prop']
}
})
}
mounted
mounted() {
this.setFields()
}

RESTful 标准的axios封装(vue2.x)

VUElopo1983 发表了文章 • 0 个评论 • 1746 次浏览 • 2018-01-04 16:54 • 来自相关话题

export function ajax(url, params, type) {
let config = { method: type || 'post' }
if (type === 'get') {
config.params = params
} else if (type === 'put' || type === 'patch' || type === 'delete') {
config.data = type ? {} : params
config.headers = { 'Content-Type': 'application/x-www-form-urlencoded' }
config.transformRequest = [
() => {
let ret = new URLSearchParams()
for (let key in params) {
ret.append(key, params[key])
}
return ret
}
]
} else {
config.data = type ? {} : params
}
return instance(url, config).then(response => {
return response.data
})
}?
?
instance.interceptors.response.use(
res => {
if (res.data.code) {
switch (res.data.code) {
case 401:
Lockr.rm('token')
window.location.href="/#/benjo/mphjo/"
break
}
} else {
}
return res
},
err => {
if (err && err.response) {
switch (err.response.status) {
case 400:
err.message = '请求错误'
break
case 401:
err.message = '授权失败,请检查token'
break
case 403:
err.message = '拒绝访问'
break
case 404:
err.message = `请求${err.response.config.url
.split('/')
.pop()
.replace(/\.html/, '')}接口出错`
break
case 408:
err.message = '请求超时'
break
case 500:
err.message = '万博manbetx手机在线登录网址内部错误'
break
case 501:
err.message = '服务未实现'
break
case 502:
err.message = '网关错误'
break
case 503:
err.message = '服务不可用'
break
case 504:
err.message = '网关超时'
break
case 505:
err.message = 'HTTP版本不受支持'
break
default:
}
}
store.commit('setModal', err.message)
return Promise.reject(err)
}
) 查看全部
export function ajax(url, params, type) {
let config = { method: type || 'post' }
if (type === 'get') {
config.params = params
} else if (type === 'put' || type === 'patch' || type === 'delete') {
config.data = type ? {} : params
config.headers = { 'Content-Type': 'application/x-www-form-urlencoded' }
config.transformRequest = [
() => {
let ret = new URLSearchParams()
for (let key in params) {
ret.append(key, params[key])
}
return ret
}
]
} else {
config.data = type ? {} : params
}
return instance(url, config).then(response => {
return response.data
})
}
?
?
instance.interceptors.response.use(
res => {
if (res.data.code) {
switch (res.data.code) {
case 401:
Lockr.rm('token')
window.location.href="/#/benjo/mphjo/"
break
}
} else {
}
return res
},
err => {
if (err && err.response) {
switch (err.response.status) {
case 400:
err.message = '请求错误'
break
case 401:
err.message = '授权失败,请检查token'
break
case 403:
err.message = '拒绝访问'
break
case 404:
err.message = `请求${err.response.config.url
.split('/')
.pop()
.replace(/\.html/, '')}接口出错`
break
case 408:
err.message = '请求超时'
break
case 500:
err.message = '万博manbetx手机在线登录网址内部错误'
break
case 501:
err.message = '服务未实现'
break
case 502:
err.message = '网关错误'
break
case 503:
err.message = '服务不可用'
break
case 504:
err.message = '网关超时'
break
case 505:
err.message = 'HTTP版本不受支持'
break
default:
}
}
store.commit('setModal', err.message)
return Promise.reject(err)
}
)

关于RESTful(仅供参考)

每天进步一点点lopo1983 发表了文章 • 0 个评论 • 1224 次浏览 • 2018-01-03 03:53 • 来自相关话题

Request 和 Response?
GET(SELECT):从万博manbetx手机在线登录网址取出资源(一项或多项)POST(CREATE):在万博manbetx手机在线登录网址新建一个资源PUT(UPDATE):在万博manbetx手机在线登录网址更新资源(客户端提供完整资源数据)PATCH(UPDATE):在万博manbetx手机在线登录网址更新资源(客户端提供需要修改的资源数据)DELETE(DELETE):从万博manbetx手机在线登录网址删除资源
??
PATCH 方法用来更新局部资源?
PUT 方法用来更新完整的资源
PATCH 与 PUT 属性上的一个重要区别还在于:PUT 是幂等的,而 PATCH 不是幂等的
?
参考?理解HTTP幂等性,RESTful 手册
??
当GET,PUT和PATCH请求成功时,要返回对应的数据,及状态码200,即SUCCESS当POST创建数据成功时,要返回创建的数据,及状态码201,即CREATED当DELETE删除数据成功时,不返回数据,状态码要返回204,即NO CONTENT当GET不到数据时,状态码要返回404,即NOT FOUND任何时候,如果请求有问题,如校验请求数据时发现错误,要返回状态码400,即BAD REQUEST当API 请求需要用户认证时,如果request中的认证信息不正确,要返回状态码401,即NOT AUTHORIZED当API 请求需要验证用户权限时,如果当前用户无相应权限,要返回状态码403,即FORBIDDEN

JSON
Number可以表示整数和浮点数。Boolean可以表示真假,值为true或false。String表示一个字符串。Null通常用于表示空对象。
?
返回的数据包含在http响应体中。数据?必须(MUST)?是一个JSON Object。该Object可能包含3个字段:状态,状态信息,数据,版本号(如需要的话)。
{
"code": 200,
"msg": {
"text": "参数错误",
"parameters": {
"email": "电子邮件格式不正确"
}
},
"data": {
"data": [
{
"name": "Google",
"url": "http://www.google.com"
}
],
"dateSelect": [
"2018-1-1",
"2018-1-3"
],
"has_next": true,
"has_prev": false,
"page": 0,
"pageSize": 1,
"keyword": "",
"totle": 20
},
"version": "3.0.2"
}?
URL Rules
?
包含版本信息/api/v1/order/
/api/v2/order/







url是指向资源的,而不是描述行为# Bad APIs
/api/getOrder/1/
/api/updateOrder/1/
/api/deleteOrder/1/

# Good APIs
/api/Order/1/
避免浏览器默认行为的安全问题 确保GET和HEAD方法必须始终是安全的# Bad APIs

# [DELETE]
/api/Order?id=1
通过url参数对资源进行过滤/api/Order&display=15&current=1&type=1
至于编写RESTful API时到底应采用哪种方式,TMD 你想怎么玩就这么玩 别挖坑就好。
?
? 查看全部
Request 和 Response?
  1. GET(SELECT):从万博manbetx手机在线登录网址取出资源(一项或多项)
  2. POST(CREATE):在万博manbetx手机在线登录网址新建一个资源
  3. PUT(UPDATE):在万博manbetx手机在线登录网址更新资源(客户端提供完整资源数据)
  4. PATCH(UPDATE):在万博manbetx手机在线登录网址更新资源(客户端提供需要修改的资源数据)
  5. DELETE(DELETE):从万博manbetx手机在线登录网址删除资源

??

PATCH 方法用来更新局部资源?
PUT 方法用来更新完整的资源
PATCH 与 PUT 属性上的一个重要区别还在于:PUT 是幂等的,而 PATCH 不是幂等的
?
参考?理解HTTP幂等性RESTful 手册


??
  • GET,PUTPATCH请求成功时,要返回对应的数据,及状态码200,即SUCCESS
  • POST创建数据成功时,要返回创建的数据,及状态码201,即CREATED
  • DELETE删除数据成功时,不返回数据,状态码要返回204,即NO CONTENT
  • GET不到数据时,状态码要返回404,即NOT FOUND
  • 任何时候,如果请求有问题,如校验请求数据时发现错误,要返回状态码400,即BAD REQUEST
  • 当API 请求需要用户认证时,如果request中的认证信息不正确,要返回状态码401,即NOT AUTHORIZED
  • 当API 请求需要验证用户权限时,如果当前用户无相应权限,要返回状态码403,即FORBIDDEN


  • JSON
  • Number可以表示整数和浮点数。
  • Boolean可以表示真假,值为true或false。
  • String表示一个字符串。
  • Null通常用于表示空对象。

  • ?

    返回的数据包含在http响应体中。数据?必须(MUST)?是一个JSON Object。该Object可能包含3个字段:状态,状态信息,数据,版本号(如需要的话)。


    {
    "code": 200,
    "msg": {
    "text": "参数错误",
    "parameters": {
    "email": "电子邮件格式不正确"
    }
    },
    "data": {
    "data": [
    {
    "name": "Google",
    "url": "http://www.google.com"
    }
    ],
    "dateSelect": [
    "2018-1-1",
    "2018-1-3"
    ],
    "has_next": true,
    "has_prev": false,
    "page": 0,
    "pageSize": 1,
    "keyword": "",
    "totle": 20
    },
    "version": "3.0.2"
    }
    ?
    URL Rules
    ?
    包含版本信息
    /api/v1/order/
    /api/v2/order/







    url是指向资源的,而不是描述行为
    # Bad APIs
    /api/getOrder/1/
    /api/updateOrder/1/
    /api/deleteOrder/1/

    # Good APIs
    /api/Order/1/

    避免浏览器默认行为的安全问题 确保GET和HEAD方法必须始终是安全的
    # Bad APIs

    # [DELETE]
    /api/Order?id=1

    通过url参数对资源进行过滤
    /api/Order&display=15&current=1&type=1

    至于编写RESTful API时到底应采用哪种方式,TMD 你想怎么玩就这么玩 别挖坑就好。
    ?
    ?

    http 错误代码表

    Nodejslopo1983 发表了文章 • 0 个评论 • 1064 次浏览 • 2017-12-18 12:01 • 来自相关话题

    所有 HTTP 状态代码及其定义。?
    代码??指示??
    2xx??成功??
    200??正常;请求已完成。??
    201??正常;紧接 POST 命令。??
    202??正常;已接受用于处理,但处理尚未完成。??
    203??正常;部分信息 — 返回的信息只是一部分。??
    204??正常;无响应 — 已接收请求,但不存在要回送的信息。??
    3xx??重定向??
    301??已移动 — 请求的数据具有新的位置且更改是永久的。??
    302??已找到 — 请求的数据临时具有不同 URI。??
    303??请参阅其它 — 可在另一 URI 下找到对请求的响应,且应使用 GET 方法检索此响应。??
    304??未修改 — 未按预期修改文档。??
    305??使用代理 — 必须通过位置字段中提供的代理来访问请求的资源。??
    306??未使用 — 不再使用;保留此代码以便将来使用。??
    4xx??客户机中出现的错误??
    400??错误请求 — 请求中有语法问题,或不能满足请求。??
    401??未授权 — 未授权客户机访问数据。??
    402??需要付款 — 表示计费系统已有效。??
    403??禁止 — 即使有授权也不需要访问。??
    404??找不到 — 万博manbetx手机在线登录网址找不到给定的资源;文档不存在。??
    407??代理认证请求 — 客户机首先必须使用代理认证自身。??
    415??介质类型不受支持 — 万博manbetx手机在线登录网址拒绝服务请求,因为不支持请求实体的格式。??
    5xx??万博manbetx手机在线登录网址中出现的错误??
    500??内部错误 — 因为意外情况,万博manbetx手机在线登录网址不能完成请求。??
    501??未执行 — 万博manbetx手机在线登录网址不支持请求的工具。??
    502??错误网关 — 万博manbetx手机在线登录网址接收到来自上游万博manbetx手机在线登录网址的无效响应。??
    503??无法获得服务 — 由于临时过载或维护,万博manbetx手机在线登录网址无法处理请求。
    ?
    --------------------------------------------------------------------------------------------------------
    ?
    HTTP?400?-?请求无效?
    HTTP?401.1?-?未授权:登录失败?
    HTTP?401.2?-?未授权:万博manbetx手机在线登录网址配置问题导致登录失败?
    HTTP?401.3?-?ACL?禁止访问资源?
    HTTP?401.4?-?未授权:授权被筛选器拒绝?
    HTTP?401.5?-?未授权:ISAPI?或?CGI?授权失败??
    HTTP?403?-?禁止访问?
    HTTP?403?-?对?Internet?服务管理器?(HTML)?的访问仅限于?Localhost?
    HTTP?403.1?禁止访问:禁止可执行访问?
    HTTP?403.2?-?禁止访问:禁止读访问?
    HTTP?403.3?-?禁止访问:禁止写访问?
    HTTP?403.4?-?禁止访问:要求?SSL?
    HTTP?403.5?-?禁止访问:要求?SSL?128?
    HTTP?403.6?-?禁止访问:IP?地址被拒绝?
    HTTP?403.7?-?禁止访问:要求客户证书?
    HTTP?403.8?-?禁止访问:禁止站点访问?
    HTTP?403.9?-?禁止访问:连接的用户过多?
    HTTP?403.10?-?禁止访问:配置无效?
    HTTP?403.11?-?禁止访问:密码更改?
    HTTP?403.12?-?禁止访问:映射器拒绝访问?
    HTTP?403.13?-?禁止访问:客户证书已被吊销?
    HTTP?403.15?-?禁止访问:客户访问许可过多?
    HTTP?403.16?-?禁止访问:客户证书不可信或者无效?
    HTTP?403.17?-?禁止访问:客户证书已经到期或者尚未生效?
    HTTP?404.1?-?无法找到?Web?站点?
    HTTP?404?-?无法找到文件?
    HTTP?405?-?资源被禁止?
    HTTP?406?-?无法接受?
    HTTP?407?-?要求代理身份验证?
    HTTP?410?-?永远不可用?
    HTTP?412?-?先决条件失败?
    HTTP?414?-?请求?-?URI?太长?
    HTTP?500?-?内部万博manbetx手机在线登录网址错误?
    HTTP?500.100?-?内部万博manbetx手机在线登录网址错误?-?ASP?错误?
    HTTP?500-11?万博manbetx手机在线登录网址关闭?
    HTTP?500-12?应用程序重新启动?
    HTTP?500-13?-?万博manbetx手机在线登录网址太忙?
    HTTP?500-14?-?应用程序无效?
    HTTP?500-15?-?不允许请求?global.asa?
    Error?501?-?未实现?
    HTTP?502?-?网关错误? 查看全部
    所有 HTTP 状态代码及其定义。?
    代码??指示??
    2xx??成功??
    200??正常;请求已完成。??
    201??正常;紧接 POST 命令。??
    202??正常;已接受用于处理,但处理尚未完成。??
    203??正常;部分信息 — 返回的信息只是一部分。??
    204??正常;无响应 — 已接收请求,但不存在要回送的信息。??
    3xx??重定向??
    301??已移动 — 请求的数据具有新的位置且更改是永久的。??
    302??已找到 — 请求的数据临时具有不同 URI。??
    303??请参阅其它 — 可在另一 URI 下找到对请求的响应,且应使用 GET 方法检索此响应。??
    304??未修改 — 未按预期修改文档。??
    305??使用代理 — 必须通过位置字段中提供的代理来访问请求的资源。??
    306??未使用 — 不再使用;保留此代码以便将来使用。??
    4xx??客户机中出现的错误??
    400??错误请求 — 请求中有语法问题,或不能满足请求。??
    401??未授权 — 未授权客户机访问数据。??
    402??需要付款 — 表示计费系统已有效。??
    403??禁止 — 即使有授权也不需要访问。??
    404??找不到 — 万博manbetx手机在线登录网址找不到给定的资源;文档不存在。??
    407??代理认证请求 — 客户机首先必须使用代理认证自身。??
    415??介质类型不受支持 — 万博manbetx手机在线登录网址拒绝服务请求,因为不支持请求实体的格式。??
    5xx??万博manbetx手机在线登录网址中出现的错误??
    500??内部错误 — 因为意外情况,万博manbetx手机在线登录网址不能完成请求。??
    501??未执行 — 万博manbetx手机在线登录网址不支持请求的工具。??
    502??错误网关 — 万博manbetx手机在线登录网址接收到来自上游万博manbetx手机在线登录网址的无效响应。??
    503??无法获得服务 — 由于临时过载或维护,万博manbetx手机在线登录网址无法处理请求。
    ?
    --------------------------------------------------------------------------------------------------------
    ?
    HTTP?400?-?请求无效?
    HTTP?401.1?-?未授权:登录失败?
    HTTP?401.2?-?未授权:万博manbetx手机在线登录网址配置问题导致登录失败?
    HTTP?401.3?-?ACL?禁止访问资源?
    HTTP?401.4?-?未授权:授权被筛选器拒绝?
    HTTP?401.5?-?未授权:ISAPI?或?CGI?授权失败??
    HTTP?403?-?禁止访问?
    HTTP?403?-?对?Internet?服务管理器?(HTML)?的访问仅限于?Localhost?
    HTTP?403.1?禁止访问:禁止可执行访问?
    HTTP?403.2?-?禁止访问:禁止读访问?
    HTTP?403.3?-?禁止访问:禁止写访问?
    HTTP?403.4?-?禁止访问:要求?SSL?
    HTTP?403.5?-?禁止访问:要求?SSL?128?
    HTTP?403.6?-?禁止访问:IP?地址被拒绝?
    HTTP?403.7?-?禁止访问:要求客户证书?
    HTTP?403.8?-?禁止访问:禁止站点访问?
    HTTP?403.9?-?禁止访问:连接的用户过多?
    HTTP?403.10?-?禁止访问:配置无效?
    HTTP?403.11?-?禁止访问:密码更改?
    HTTP?403.12?-?禁止访问:映射器拒绝访问?
    HTTP?403.13?-?禁止访问:客户证书已被吊销?
    HTTP?403.15?-?禁止访问:客户访问许可过多?
    HTTP?403.16?-?禁止访问:客户证书不可信或者无效?
    HTTP?403.17?-?禁止访问:客户证书已经到期或者尚未生效?
    HTTP?404.1?-?无法找到?Web?站点?
    HTTP?404?-?无法找到文件?
    HTTP?405?-?资源被禁止?
    HTTP?406?-?无法接受?
    HTTP?407?-?要求代理身份验证?
    HTTP?410?-?永远不可用?
    HTTP?412?-?先决条件失败?
    HTTP?414?-?请求?-?URI?太长?
    HTTP?500?-?内部万博manbetx手机在线登录网址错误?
    HTTP?500.100?-?内部万博manbetx手机在线登录网址错误?-?ASP?错误?
    HTTP?500-11?万博manbetx手机在线登录网址关闭?
    HTTP?500-12?应用程序重新启动?
    HTTP?500-13?-?万博manbetx手机在线登录网址太忙?
    HTTP?500-14?-?应用程序无效?
    HTTP?500-15?-?不允许请求?global.asa?
    Error?501?-?未实现?
    HTTP?502?-?网关错误?

    本站的VUE 实例中所用到的less 库

    CSS/SASS/SCSS/LESSlopo1983 发表了文章 • 0 个评论 • 1603 次浏览 • 2017-06-26 12:59 • 来自相关话题

    很多vue 文件里面会出来一个less 基础库 请下载放到assets>lib(可按照你习惯的路径安放 修改路径即可)
    下载地址如下?
    很多vue 文件里面会出来一个less 基础库 请下载放到assets>lib(可按照你习惯的路径安放 修改路径即可)
    下载地址如下?

    vue-form(vue表单验证插件 vue2.2+) 使用指南

    VUElopo1983 发表了文章 • 0 个评论 • 3171 次浏览 • 2017-06-13 10:40 • 来自相关话题

    vue-form 是一个在vue 中用于表单验证的插件 目前版本为4.1.1 ??Form validation for?Vue.js 2.2+
    官网地址:https://github.com/fergaldoyle/vue-form
    1.安装import VueForm from 'vue-form';
    // install globally
    Vue.use(VueForm);
    Vue.use(VueForm, options);
    // or use the mixin ...
    mixins: [VueForm]
    ...
    mixins: [new VueForm(options)]
    ...
    2.案例
    使用bootstrap样式的案例?https://jsfiddle.net/fergal_doyle/zfqt4yhq/
    密码验证的案例https://jsfiddle.net/fergal_doyle/9rn5kLkw/
    3.使用方法
    template: <vue-form :state="formstate" @submit.prevent="onSubmit">

    <validate tag="label">
    <span>Name *</span>
    <input v-model="model.name" required name="name" />

    <field-messages name="name">
    <div>Success!</div>
    <div slot="required">Name is a required field</div>
    </field-messages>
    </validate>

    <validate tag="label">
    <span>Email</span>
    <input v-model="model.email" name="email" type="email" required />

    <field-messages name="email">
    <div slot="required">Email is a required field</div>
    <div slot="email">Email is not valid</div>
    </field-messages>
    </validate>

    <button type="submit">Submit</button>
    </vue-form>
    scriptdata(){
    return{
    formstate: {},
    model: { name: '', email: 'invalid-email' } },
    }
    methods: {
    onSubmit: function () {
    if(this.formstate.$invalid) {
    // alert user and exit early
    return;
    }
    // otherwise submit form
    }
    }
    vue 中可直接通过FormData的方式提交数据 要获取该表单的所有数据 可给vue-form 添加ref属性来获取?let def = this.$refs.sendinfo.$el;
    验证信 息显示
    该插件使用field-messages标签来定义验证正确和错误的文字或其他形式的提示内容
    show 表示表单在何种状态下开始验证 vue-form 内置有$dirty,?$dirty && $touched,?$dirty || $touched,?$touched || $submitted
    示例:<field-messages name="name" show="$dirty && $touched">
    <div slot="errorKeyA">Error message A</div>
    <div slot="errorKeyB">Error message B</div>
    </field-messages>
    使用scope template<field-messages name="fieldName">
    <span>Success</span>
    <template slot="required" scope="state">
    <span v-if="state.$touched || state.$submitted">Name is a required field</span>
    </template>
    <template slot="errorKeyB" scope="state">
    <span v-if="state.$touched || state.$dirty">Error message B</span>
    </template>
    </field-messages>
    vue-form Validators
    默认自带验证类型type="email"
    type="url"
    type="number"
    required
    minlength
    maxlength
    pattern
    min (for type="number")
    max (for type="number")
    使用方法<!-- static validators -->
    <validate>
    <input type="email" name="email" v-model="model.email" required />
    </validate>
    <validate>
    <input type="text" name="name" v-model="model.name" maxlength="25" minlength="5" />
    </validate>

    <!-- bound validators -->
    <validate>
    <input type="email" name="email" v-model="model.email" :required="isRequired" />
    </validate>
    <validate>
    <input type="text" name="name" v-model="model.name" :maxlength="maxLen" :minlength="minLen" />
    </validate>
    自定义验证
    你可以全局或者局部注册自定义验证
    全部注册var options = {
    validators: {
    'my-custom-validator': function (value, attrValue, vnode) {
    // return true to set input as $valid, false to set as $invalid
    return value === 'custom';
    }
    }
    }

    Vue.use(VueForm, options);
    // or
    mixins: [new VueForm(options)]<validate>
    <input v-model="something" name="something" my-custom-validator />
    </validate>局部注册<validate :custom="{customValidator: customValidator}">
    <input v-model="something" name="something" />
    </validate>// ...
    methods: {
    customValidator: function (value) {
    // return true to set input as $valid, false to set as $invalid
    return value === 'custom';
    }
    }
    // ...Async 验证methods: {
    debounced: _.debounce(function (value, resolve, reject) {
    fetch('https://httpbin.org/get').then(function(response){
    resolve(response.isValid);
    });
    }, 500),
    customValidator (value) {
    return new Promise((resolve, reject) => {
    this.debounced(value, resolve, reject);
    });
    }
    }重置验证<vue-form ref="form" :state="formstate">

    resetState: function () {
    this.formstate._reset();
    // or
    this.$refs.form.reset();
    }
    未完待续..... 查看全部

    vue-form 是一个在vue 中用于表单验证的插件 目前版本为4.1.1 ??Form validation for?Vue.js 2.2+


    官网地址:https://github.com/fergaldoyle/vue-form


    1.安装
    import VueForm from 'vue-form'; 
    // install globally
    Vue.use(VueForm);
    Vue.use(VueForm, options);
    // or use the mixin ...
    mixins: [VueForm]
    ...
    mixins: [new VueForm(options)]
    ...

    2.案例
    使用bootstrap样式的案例?https://jsfiddle.net/fergal_doyle/zfqt4yhq/
    密码验证的案例https://jsfiddle.net/fergal_doyle/9rn5kLkw/
    3.使用方法
    template:
      <vue-form :state="formstate" @submit.prevent="onSubmit">

    <validate tag="label">
    <span>Name *</span>
    <input v-model="model.name" required name="name" />

    <field-messages name="name">
    <div>Success!</div>
    <div slot="required">Name is a required field</div>
    </field-messages>
    </validate>

    <validate tag="label">
    <span>Email</span>
    <input v-model="model.email" name="email" type="email" required />

    <field-messages name="email">
    <div slot="required">Email is a required field</div>
    <div slot="email">Email is not valid</div>
    </field-messages>
    </validate>

    <button type="submit">Submit</button>
    </vue-form>

    script
    data(){
    return{
    formstate: {},
    model: { name: '', email: 'invalid-email' } },
    }
    methods: {
    onSubmit: function () {
    if(this.formstate.$invalid) {
    // alert user and exit early
    return;
    }
    // otherwise submit form
    }
    }

    vue 中可直接通过FormData的方式提交数据 要获取该表单的所有数据 可给vue-form 添加ref属性来获取?let def = this.$refs.sendinfo.$el;


    验证信 息显示
    该插件使用field-messages标签来定义验证正确和错误的文字或其他形式的提示内容
    show 表示表单在何种状态下开始验证 vue-form 内置有$dirty,?$dirty && $touched,?$dirty || $touched,?$touched || $submitted
    示例:
    <field-messages name="name" show="$dirty && $touched">
    <div slot="errorKeyA">Error message A</div>
    <div slot="errorKeyB">Error message B</div>
    </field-messages>

    使用scope template
    <field-messages name="fieldName">
    <span>Success</span>
    <template slot="required" scope="state">
    <span v-if="state.$touched || state.$submitted">Name is a required field</span>
    </template>
    <template slot="errorKeyB" scope="state">
    <span v-if="state.$touched || state.$dirty">Error message B</span>
    </template>
    </field-messages>

    vue-form Validators
    默认自带验证类型
    type="email"
    type="url"
    type="number"
    required
    minlength
    maxlength
    pattern
    min (for type="number")
    max (for type="number")

    使用方法
    <!-- static validators -->
    <validate>
    <input type="email" name="email" v-model="model.email" required />
    </validate>
    <validate>
    <input type="text" name="name" v-model="model.name" maxlength="25" minlength="5" />
    </validate>

    <!-- bound validators -->
    <validate>
    <input type="email" name="email" v-model="model.email" :required="isRequired" />
    </validate>
    <validate>
    <input type="text" name="name" v-model="model.name" :maxlength="maxLen" :minlength="minLen" />
    </validate>

    自定义验证
    你可以全局或者局部注册自定义验证
    全部注册
    var options = {
    validators: {
    'my-custom-validator': function (value, attrValue, vnode) {
    // return true to set input as $valid, false to set as $invalid
    return value === 'custom';
    }
    }
    }

    Vue.use(VueForm, options);
    // or
    mixins: [new VueForm(options)]
    <validate>
    <input v-model="something" name="something" my-custom-validator />
    </validate>
    局部注册
    <validate :custom="{customValidator: customValidator}">
    <input v-model="something" name="something" />
    </validate>
    // ...
    methods: {
    customValidator: function (value) {
    // return true to set input as $valid, false to set as $invalid
    return value === 'custom';
    }
    }
    // ...
    Async 验证
    methods: {
    debounced: _.debounce(function (value, resolve, reject) {
    fetch('https://httpbin.org/get').then(function(response){
    resolve(response.isValid);
    });
    }, 500),
    customValidator (value) {
    return new Promise((resolve, reject) => {
    this.debounced(value, resolve, reject);
    });
    }
    }
    重置验证
    <vue-form ref="form" :state="formstate">

    resetState: function () {
    this.formstate._reset();
    // or
    this.$refs.form.reset();
    }

    未完待续.....

    百度BOS 上传 Vue 2.x封装

    VUElopo1983 发表了文章 • 0 个评论 • 1586 次浏览 • 2017-04-19 18:28 • 来自相关话题

    template
    <div class="fileup">
    <input type="file" ref="fileup" multiple="multiple" class="hide" name="fileUp" :id="rdid" @change="onFileChange" />
    <label class="btn btn-ces" :for="rdid"><span class="iconfont icon-add"></span>选择文件</label>
    <span>{{infomsg}}</span>
    <div class="fileup-area" v-show="files.length">
    <div class="col-md-2 files" v-for="(item,index) in files">
    <div class="thumbnail">
    <div class="thumbnail-object" :style="{'background-image':`url(${item.src})`}">
    <a class="ctr-bar" @click="delFile(index,item.key,item.status)">
    <span class="iconfont icon-del"></span>
    </a>
    </div>
    <div class="caption">
    <p class="name">{{item.name}}</p>
    <span class="iconfont icon-zhengque text-success" v-if="item.status==2"></span>
    <bsf-progress :state="item.progress" v-if="item.progress<100"></bsf-progress>
    </div>
    </div>
    </div>
    </div>
    <p class="btn-mix" v-if="files.length>0">
    <a class="btn btn-ces" @click="sendFile">提交</a>
    <a class="btn btn-default" @click="clearFile">取消</a>
    </p>
    </div>
    javascript
    import bos from '@/assets/js/bce-sdk-js/baidubce-sdk.bundle'
    import lib from "@/assets/js/lib"
    import bsfProgress from '@/components/comp/progress'
    import { bosConfig, bucket } from '@/config/bos'
    let client = new baidubce.sdk.BosClient(bosConfig);
    export default {
    name: "bosupt",
    components: {
    bsfProgress
    },
    props: {
    maxlength: {
    type: Number,
    default: 3
    },
    maxSize: {
    type: Number,
    default: 50000
    }
    },
    data() {
    return {
    files: [],
    infomsg:""
    }
    },
    computed: {
    rdid() {
    return "up" + Math.ceil(Math.random() * 1000, 3);
    }
    },
    methods: {
    onFileChange(evt) {
    let files = evt.target.files;
    let _this = this;
    if(files.length) {
    for(let i = 0, len = files.length; i < len; i++) {
    let file = files[i];
    let fcobj = {
    type: file.name.substring(file.name.lastIndexOf('.')).toLowerCase(),
    key: lib.randomStr(false, 5)
    };
    let o = {
    file: file, // File 对象
    status: 0, // 0:未上传 1:正在上传:2上传成功 3:上传失败
    progress: 0, // 上传进度
    type: fcobj.type,
    key: fcobj.key,
    name: file.name,
    size: file.size,
    path: "http://" + bucket + ".bj.bcebos.com/" + fcobj.key + fcobj.type
    };
    let reader = new FileReader()
    reader.readAsDataURL(file);
    reader.onload = (e) => {
    o.src = e.target.result // base64 可以作为判断是不是存在相同文件
    if(this.files.findIndex(f => f.src == o.src) > -1) {
    return false
    }
    if(o.size <= _this.maxSize) {
    this.files.push(o)
    } else {
    this.infomsg="图片太大了哦"
    return false
    }
    };
    };
    }
    Array.from(this.files).slice(0, this.maxlength)
    },
    delFile(index, key, status) {
    if(status == 2) {
    client.deleteObject(bucket, key).then(e => {
    e && this.files.splice(index, 1);
    }).catch(e => {
    console.log(e)
    })
    } else {
    this.files.splice(index, 1);
    }
    },
    clearFile() {
    let files = this.files;
    this.files = [];
    let ar = []
    this.$refs.fileup.value = "";
    this.$emit('clearfile', ar)
    },
    sendFile() {
    this.files.forEach(o => {
    if(o.status == 0) {
    let file = o.file
    let blob = file;
    let keytext = o.type;
    let key = o.key + keytext;
    const ext = key.split(/\./g).pop();
    let mimeType = baidubce.sdk.MimeType.guess(ext);
    if(/^text\//.test(mimeType)) {
    mimeType += '; charset=UTF-8';
    }
    let options = {
    'Content-Type': mimeType
    };
    client.putObjectFromBlob(bucket, key, blob, options)
    .then(function(res) {})
    .catch(function(err) {
    console.error(err);
    });
    client.on('progress', function(evt) {
    if(evt.lengthComputable) {
    o.progress = (evt.loaded / evt.total) * 100;
    o.status = 2;
    }
    });
    }
    });
    let ar = []
    this.files.forEach(e => {
    ar.push(e.path)
    });
    this.$emit('sendfile', ar)
    }
    },
    mounted: function() {
    this.$nextTick(function() {

    })
    }
    }
    BOS 配置
    bos.js
    const bosConfig = {
    credentials: {
    ak: '',
    sk: ''
    },
    endpoint: 'http://bj.bcebos.com'
    }
    const bucket = 'bucket名称';
    export{bosConfig,bucket}
    感谢戏子大爷 查看全部
    template
    <div class="fileup">
    <input type="file" ref="fileup" multiple="multiple" class="hide" name="fileUp" :id="rdid" @change="onFileChange" />
    <label class="btn btn-ces" :for="rdid"><span class="iconfont icon-add"></span>选择文件</label>
    <span>{{infomsg}}</span>
    <div class="fileup-area" v-show="files.length">
    <div class="col-md-2 files" v-for="(item,index) in files">
    <div class="thumbnail">
    <div class="thumbnail-object" :style="{'background-image':`url(${item.src})`}">
    <a class="ctr-bar" @click="delFile(index,item.key,item.status)">
    <span class="iconfont icon-del"></span>
    </a>
    </div>
    <div class="caption">
    <p class="name">{{item.name}}</p>
    <span class="iconfont icon-zhengque text-success" v-if="item.status==2"></span>
    <bsf-progress :state="item.progress" v-if="item.progress<100"></bsf-progress>
    </div>
    </div>
    </div>
    </div>
    <p class="btn-mix" v-if="files.length>0">
    <a class="btn btn-ces" @click="sendFile">提交</a>
    <a class="btn btn-default" @click="clearFile">取消</a>
    </p>
    </div>

    javascript
    import bos from '@/assets/js/bce-sdk-js/baidubce-sdk.bundle'
    import lib from "@/assets/js/lib"
    import bsfProgress from '@/components/comp/progress'
    import { bosConfig, bucket } from '@/config/bos'
    let client = new baidubce.sdk.BosClient(bosConfig);
    export default {
    name: "bosupt",
    components: {
    bsfProgress
    },
    props: {
    maxlength: {
    type: Number,
    default: 3
    },
    maxSize: {
    type: Number,
    default: 50000
    }
    },
    data() {
    return {
    files: [],
    infomsg:""
    }
    },
    computed: {
    rdid() {
    return "up" + Math.ceil(Math.random() * 1000, 3);
    }
    },
    methods: {
    onFileChange(evt) {
    let files = evt.target.files;
    let _this = this;
    if(files.length) {
    for(let i = 0, len = files.length; i < len; i++) {
    let file = files[i];
    let fcobj = {
    type: file.name.substring(file.name.lastIndexOf('.')).toLowerCase(),
    key: lib.randomStr(false, 5)
    };
    let o = {
    file: file, // File 对象
    status: 0, // 0:未上传 1:正在上传:2上传成功 3:上传失败
    progress: 0, // 上传进度
    type: fcobj.type,
    key: fcobj.key,
    name: file.name,
    size: file.size,
    path: "http://" + bucket + ".bj.bcebos.com/" + fcobj.key + fcobj.type
    };
    let reader = new FileReader()
    reader.readAsDataURL(file);
    reader.onload = (e) => {
    o.src = e.target.result // base64 可以作为判断是不是存在相同文件
    if(this.files.findIndex(f => f.src == o.src) > -1) {
    return false
    }
    if(o.size <= _this.maxSize) {
    this.files.push(o)
    } else {
    this.infomsg="图片太大了哦"
    return false
    }
    };
    };
    }
    Array.from(this.files).slice(0, this.maxlength)
    },
    delFile(index, key, status) {
    if(status == 2) {
    client.deleteObject(bucket, key).then(e => {
    e && this.files.splice(index, 1);
    }).catch(e => {
    console.log(e)
    })
    } else {
    this.files.splice(index, 1);
    }
    },
    clearFile() {
    let files = this.files;
    this.files = [];
    let ar = []
    this.$refs.fileup.value = "";
    this.$emit('clearfile', ar)
    },
    sendFile() {
    this.files.forEach(o => {
    if(o.status == 0) {
    let file = o.file
    let blob = file;
    let keytext = o.type;
    let key = o.key + keytext;
    const ext = key.split(/\./g).pop();
    let mimeType = baidubce.sdk.MimeType.guess(ext);
    if(/^text\//.test(mimeType)) {
    mimeType += '; charset=UTF-8';
    }
    let options = {
    'Content-Type': mimeType
    };
    client.putObjectFromBlob(bucket, key, blob, options)
    .then(function(res) {})
    .catch(function(err) {
    console.error(err);
    });
    client.on('progress', function(evt) {
    if(evt.lengthComputable) {
    o.progress = (evt.loaded / evt.total) * 100;
    o.status = 2;
    }
    });
    }
    });
    let ar = []
    this.files.forEach(e => {
    ar.push(e.path)
    });
    this.$emit('sendfile', ar)
    }
    },
    mounted: function() {
    this.$nextTick(function() {

    })
    }
    }

    BOS 配置
    bos.js
    const bosConfig = {
    credentials: {
    ak: '',
    sk: ''
    },
    endpoint: 'http://bj.bcebos.com'
    }
    const bucket = 'bucket名称';
    export{bosConfig,bucket}

    感谢戏子大爷

    vue+bootstrap4+tooltip.js 实现简单的tooltip

    VUElopo1983 发表了文章 • 0 个评论 • 2272 次浏览 • 2018-01-24 17:33 • 来自相关话题

    <template lang="pug">
    button(:class="`btn btn-${size} btn-${stype}`",ref="button",@mouseover="initPopper")
    <slot></slot>
    <template v-if="!$slots.default">{{label}}</template>
    </template>
    <script>
    import lib from '@/utils/lib'
    import btn from '@/components/comp/button'
    import Tooltip from 'tooltip.js'
    export default {
    name: 'vbaToolTip',
    components: {
    btn
    },
    props: {
    label: String,
    size: String,
    stype: String,
    placement: {
    type: String,
    default: 'top'
    },
    html: {
    type: Boolean,
    default: false
    },
    content: String
    },
    data() {
    return {
    popperInstance: null
    }
    },
    methods: {
    initPopper() {
    if (!this.popperInstance) {
    const vm = this
    this.popperInstance = new Tooltip(this.$refs.button, {
    placement: `${this.placement}`,
    template: `<div class="tooltip bs-tooltip-${
    this.placement
    }" role="tooltip">
    <div class="tooltip-arrow arrow"></div>
    <div class="tooltip-inner">
    </div>
    </div>`,
    title: this.content,
    html:this.html,
    contaier:document.getElementsByTagName('body'),
    onCreate() {
    vm.$emit('on-create', this.popperInstance)
    },
    onUpdate() {
    vm.$emit('on-update', this.popperInstance)
    }
    })
    }
    }
    }
    }
    </script>
    <style lang="less">
    .tooltip {
    opacity: 1 !important;
    }
    </style> 查看全部
    <template lang="pug">
    button(:class="`btn btn-${size} btn-${stype}`",ref="button",@mouseover="initPopper")
    <slot></slot>
    <template v-if="!$slots.default">{{label}}</template>
    </template>
    <script>
    import lib from '@/utils/lib'
    import btn from '@/components/comp/button'
    import Tooltip from 'tooltip.js'
    export default {
    name: 'vbaToolTip',
    components: {
    btn
    },
    props: {
    label: String,
    size: String,
    stype: String,
    placement: {
    type: String,
    default: 'top'
    },
    html: {
    type: Boolean,
    default: false
    },
    content: String
    },
    data() {
    return {
    popperInstance: null
    }
    },
    methods: {
    initPopper() {
    if (!this.popperInstance) {
    const vm = this
    this.popperInstance = new Tooltip(this.$refs.button, {
    placement: `${this.placement}`,
    template: `<div class="tooltip bs-tooltip-${
    this.placement
    }" role="tooltip">
    <div class="tooltip-arrow arrow"></div>
    <div class="tooltip-inner">
    </div>
    </div>`,
    title: this.content,
    html:this.html,
    contaier:document.getElementsByTagName('body'),
    onCreate() {
    vm.$emit('on-create', this.popperInstance)
    },
    onUpdate() {
    vm.$emit('on-update', this.popperInstance)
    }
    })
    }
    }
    }
    }
    </script>
    <style lang="less">
    .tooltip {
    opacity: 1 !important;
    }
    </style>

    vue2.x 将table 内容导出excel 下载(转换页面table数据)

    VUElopo1983 发表了文章 • 0 个评论 • 2411 次浏览 • 2018-01-22 18:06 • 来自相关话题

    目前仅支持chrome?downloadjs需自行引入加载 对应的tab HTMLCollection 也应根据你的UI组件进行替换









    <template lang="pug">
    btn(:stype="stype",:size="size",@click="exportOffice(tid)")
    slot
    template(v-if="!$slots.default") {{label}}
    </template>

    <script>
    /**
    * bootstrap 4.x --> components --> table-->table
    *
    * @param {String} label 按钮名称
    * @param {String} stype 样式
    * @param {String} size 大小
    *
    * 注意以上参数为内置按钮参数 可根据你目前使用的UI组件进行修改
    *
    * @param {String} tid 表格ID
    * @param {String} xlsname excel名称
    * @param {String} filters 需过滤的cell className
    *
    * @date 2018-1-22
    *
    * @version v1.0.0 beta
    *
    * @important 注意目前仅支持chrome下使用
    *
    **/
    import download from 'downloadjs'
    import btn from '@/components/comp/button'
    export default {
    name: 'tableToExcel',
    components: {
    btn
    },
    props: {
    // btn 组件参数
    label: String,
    stype: String,
    size: {
    type: String,
    default: 'sm'
    },
    tid: String,
    xlsname:String,
    filters: String
    },
    methods: {
    base64ToBlob: function(data, mime) {
    let base64 = window.btoa(window.unescape(encodeURIComponent(data)))
    let bstr = atob(base64)
    let n = bstr.length
    let u8arr = new Uint8ClampedArray(n)
    while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
    }
    return new Blob([u8arr], { type: mime })
    },
    exportOffice(tableID) {
    let elms = document.getElementById(tableID).cloneNode(true)
    let table = elms.childNodes[1].childNodes[0]
    // table根据你的ui组件修改对应的HTMLCollection
    let rows = table.rows.length
    let cells = table.rows.item(0).cells.length
    let tableArr = table.getElementsByClassName(this.filters)
    for (let i = 0; i < rows; i++) {
    table.rows<em>.deleteCell(cells-1)
    }
    let excelContent = table.innerHTML
    let excelFile = `<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html4 ... Bmeta name=ProgId content=Excel.Sheet> <meta name=Generator content="Microsoft Excel 11"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>${excelContent}</table></body></html>`
    let blob = this.base64ToBlob(excelFile, 'application/vnd.ms-excel')
    download(blob, this.xlsname||this.$route.name+moment().format('x'), 'application/vnd.ms-excel')
    }
    }
    }
    </script> 查看全部

    目前仅支持chrome?downloadjs需自行引入加载 对应的tab HTMLCollection 也应根据你的UI组件进行替换



    table.png


    QQ图片20180122224557.png
    <template lang="pug">
    btn(:stype="stype",:size="size",@click="exportOffice(tid)")
    slot
    template(v-if="!$slots.default") {{label}}
    </template>

    <script>
    /**
    * bootstrap 4.x --> components --> table-->table
    *
    * @param {String} label 按钮名称
    * @param {String} stype 样式
    * @param {String} size 大小
    *
    * 注意以上参数为内置按钮参数 可根据你目前使用的UI组件进行修改
    *
    * @param {String} tid 表格ID
    * @param {String} xlsname excel名称
    * @param {String} filters 需过滤的cell className
    *
    * @date 2018-1-22
    *
    * @version v1.0.0 beta
    *
    * @important 注意目前仅支持chrome下使用
    *
    **/
    import download from 'downloadjs'
    import btn from '@/components/comp/button'
    export default {
    name: 'tableToExcel',
    components: {
    btn
    },
    props: {
    // btn 组件参数
    label: String,
    stype: String,
    size: {
    type: String,
    default: 'sm'
    },
    tid: String,
    xlsname:String,
    filters: String
    },
    methods: {
    base64ToBlob: function(data, mime) {
    let base64 = window.btoa(window.unescape(encodeURIComponent(data)))
    let bstr = atob(base64)
    let n = bstr.length
    let u8arr = new Uint8ClampedArray(n)
    while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
    }
    return new Blob([u8arr], { type: mime })
    },
    exportOffice(tableID) {
    let elms = document.getElementById(tableID).cloneNode(true)
    let table = elms.childNodes[1].childNodes[0]
    // table根据你的ui组件修改对应的HTMLCollection
    let rows = table.rows.length
    let cells = table.rows.item(0).cells.length
    let tableArr = table.getElementsByClassName(this.filters)
    for (let i = 0; i < rows; i++) {
    table.rows<em>.deleteCell(cells-1)
    }
    let excelContent = table.innerHTML
    let excelFile = `<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html4 ... Bmeta name=ProgId content=Excel.Sheet> <meta name=Generator content="Microsoft Excel 11"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>${excelContent}</table></body></html>`
    let blob = this.base64ToBlob(excelFile, 'application/vnd.ms-excel')
    download(blob, this.xlsname||this.$route.name+moment().format('x'), 'application/vnd.ms-excel')
    }
    }
    }
    </script>

    vue2.x 将table 内容导出excel 下载(直接转换渲染数据)

    VUElopo1983 发表了文章 • 0 个评论 • 2105 次浏览 • 2018-01-22 17:51 • 来自相关话题

    https://github.com/jecovier/vue-json-excel
    <template lang="pug">
    btn(:stype="stype",:size="size",@click="generate")
    slot
    template(v-if="!$slots.default") {{label}}
    </template>
    <script>
    // https://github.com/jecovier/vue-json-excel
    import download from 'downloadjs'
    import btn from '@/components/comp/button'
    export default {
    name: 'vbaJsonExcel',
    components: {
    btn
    },
    props: {
    // btn 组件参数
    label: String,
    stype: String,
    size: {
    type: String,
    default: 'sm'
    },
    // 设置导出格式 [xls, csv], 默认: xls
    type: {
    type: String,
    default: 'xls'
    },
    // Json to download
    data: {
    type: Array,
    required: true
    },
    // 导出的表格标题
    // 若不设置将使用默认的json数据key
    fields: {
    type: Object,
    required: true
    },
    // excel标题
    title: {
    type: String,
    default: null
    },
    // 导出excel标题名称
    name: {
    type: String,
    default: 'datas.xls'
    },
    meta: {
    type: Array,
    default: () =>
    }
    },
    computed: {
    // unique identifier
    idName: function() {
    var now = new Date().getTime()
    return 'export_' + now
    }
    },
    methods: {
    generate() {
    if (!this.data.length) {
    return
    }
    let json = this.getProcessedJson(this.data, this.fields)
    if (this.type == 'csv') {
    return this.export(this.jsonToCSV(json), this.name, 'application/csv')
    }
    return this.export(
    this.jsonToXLS(json),
    this.name,
    'application/vnd.ms-excel'
    )
    },
    /*
    Use downloadjs to generate the download link
    */
    export: function(data, filename, mime) {
    let blob = this.base64ToBlob(data, mime)
    download(blob, filename, mime)
    },
    /*
    jsonToXLS
    ---------------
    Transform json data into an xml document with MS Excel format, sadly
    this format show a prompt when open due to a default behavior
    on Microsoft office. It's recommended to use CSV format instead.
    */
    jsonToXLS: function(data) {
    let xlsTemp =
    '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html4 ... Bmeta name=ProgId content=Excel.Sheet> <meta name=Generator content="Microsoft Excel 11"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>${table}</table></body></html>'
    let xlsData = '<thead><tr>'

    if (this.title != null) {
    xlsData +=
    '<tr><th colspan="' +
    Object.keys(data[0]).length +
    '">' +
    this.title +
    '<th></tr>'
    }

    for (let key in data[0]) {
    xlsData += '<th>' + key + '</th>'
    }
    xlsData += '</tr></thead>'
    xlsData += '<tbody>'

    data.map(function(item, index) {
    xlsData += '<tbody><tr>'
    for (let key in item) {
    xlsData += '<td>' + item[key] + '</td>'
    }
    xlsData += '</tr></tbody>'
    })
    return xlsTemp.replace('${table}', xlsData)
    },
    /*
    jsonToCSV
    ---------------
    Transform json data into an CSV file.
    */
    jsonToCSV: function(data) {
    var csvData = ''

    if (this.title != null) {
    csvData += this.title + '\r\n'
    }

    for (let key in data[0]) {
    csvData += key + ','
    }
    csvData = csvData.slice(0, csvData.length - 1)
    csvData += '\r\n'

    data.map(function(item) {
    for (let key in item) {
    let escapedCSV = item[key] + '' // cast Numbers to string
    if (escapedCSV.match(/[,"\n]/)) {
    escapedCSV = '"' + escapedCSV.replace(/\"/g, '""') + '"'
    }
    csvData += escapedCSV + ','
    }
    csvData = csvData.slice(0, csvData.length - 1)
    csvData += '\r\n'
    })
    return csvData
    },
    /*
    getProcessedJson
    ---------------
    Get only the data to export, if no fields are set return all the data
    */
    getProcessedJson: function(data, header) {
    let keys = this.getKeys(data, header)
    let newData =
    let _self = this
    data.map(function(item, index) {
    let newItem = {}
    for (let label in keys) {
    var iii = item
    let property = keys[label]
    newItem[label] = _self.getNestedData(property, item)
    }
    newData.push(newItem)
    })

    return newData
    },
    getKeys: function(data, header) {
    if (header) {
    return header
    }

    let keys = {}
    for (let key in data[0]) {
    keys[key] = key
    }
    return keys
    },
    getNestedData: function(key, item) {
    let valueFromNestedKey = null
    let keyNestedSplit = key.split('.')
    valueFromNestedKey = item[keyNestedSplit[0]]
    for (let j = 1; j < keyNestedSplit.length; j++) {
    valueFromNestedKey = valueFromNestedKey[keyNestedSplit[j]]
    }
    return valueFromNestedKey
    },
    base64ToBlob: function(data, mime) {
    let base64 = window.btoa(window.unescape(encodeURIComponent(data)))
    let bstr = atob(base64)
    let n = bstr.length
    let u8arr = new Uint8ClampedArray(n)
    while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
    }
    return new Blob([u8arr], { type: mime })
    }
    } // end methods
    }
    </script>


    fileds 获取(该组件需要对标题进行格式化)
    ?
    methods
    setFields() {
    let _this = this
    let Obj = new Object()
    let arr = this.$refs.tables.$slots.default
    .filter(e => e.componentInstance)
    .map((column, index) => {
    const instance = column.componentOptions.propsData
    return instance
    })
    arr.forEach(element => {
    if (!!element['prop']) {
    _this.xlsfields[element['label']] = element['prop']
    }
    })
    }mounted
    mounted() {
    this.setFields()
    } 查看全部

    https://github.com/jecovier/vue-json-excel


    <template lang="pug">
    btn(:stype="stype",:size="size",@click="generate")
    slot
    template(v-if="!$slots.default") {{label}}
    </template>
    <script>
    // https://github.com/jecovier/vue-json-excel
    import download from 'downloadjs'
    import btn from '@/components/comp/button'
    export default {
    name: 'vbaJsonExcel',
    components: {
    btn
    },
    props: {
    // btn 组件参数
    label: String,
    stype: String,
    size: {
    type: String,
    default: 'sm'
    },
    // 设置导出格式 [xls, csv], 默认: xls
    type: {
    type: String,
    default: 'xls'
    },
    // Json to download
    data: {
    type: Array,
    required: true
    },
    // 导出的表格标题
    // 若不设置将使用默认的json数据key
    fields: {
    type: Object,
    required: true
    },
    // excel标题
    title: {
    type: String,
    default: null
    },
    // 导出excel标题名称
    name: {
    type: String,
    default: 'datas.xls'
    },
    meta: {
    type: Array,
    default: () =>
    }
    },
    computed: {
    // unique identifier
    idName: function() {
    var now = new Date().getTime()
    return 'export_' + now
    }
    },
    methods: {
    generate() {
    if (!this.data.length) {
    return
    }
    let json = this.getProcessedJson(this.data, this.fields)
    if (this.type == 'csv') {
    return this.export(this.jsonToCSV(json), this.name, 'application/csv')
    }
    return this.export(
    this.jsonToXLS(json),
    this.name,
    'application/vnd.ms-excel'
    )
    },
    /*
    Use downloadjs to generate the download link
    */
    export: function(data, filename, mime) {
    let blob = this.base64ToBlob(data, mime)
    download(blob, filename, mime)
    },
    /*
    jsonToXLS
    ---------------
    Transform json data into an xml document with MS Excel format, sadly
    this format show a prompt when open due to a default behavior
    on Microsoft office. It's recommended to use CSV format instead.
    */
    jsonToXLS: function(data) {
    let xlsTemp =
    '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html4 ... Bmeta name=ProgId content=Excel.Sheet> <meta name=Generator content="Microsoft Excel 11"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>${table}</table></body></html>'
    let xlsData = '<thead><tr>'

    if (this.title != null) {
    xlsData +=
    '<tr><th colspan="' +
    Object.keys(data[0]).length +
    '">' +
    this.title +
    '<th></tr>'
    }

    for (let key in data[0]) {
    xlsData += '<th>' + key + '</th>'
    }
    xlsData += '</tr></thead>'
    xlsData += '<tbody>'

    data.map(function(item, index) {
    xlsData += '<tbody><tr>'
    for (let key in item) {
    xlsData += '<td>' + item[key] + '</td>'
    }
    xlsData += '</tr></tbody>'
    })
    return xlsTemp.replace('${table}', xlsData)
    },
    /*
    jsonToCSV
    ---------------
    Transform json data into an CSV file.
    */
    jsonToCSV: function(data) {
    var csvData = ''

    if (this.title != null) {
    csvData += this.title + '\r\n'
    }

    for (let key in data[0]) {
    csvData += key + ','
    }
    csvData = csvData.slice(0, csvData.length - 1)
    csvData += '\r\n'

    data.map(function(item) {
    for (let key in item) {
    let escapedCSV = item[key] + '' // cast Numbers to string
    if (escapedCSV.match(/[,"\n]/)) {
    escapedCSV = '"' + escapedCSV.replace(/\"/g, '""') + '"'
    }
    csvData += escapedCSV + ','
    }
    csvData = csvData.slice(0, csvData.length - 1)
    csvData += '\r\n'
    })
    return csvData
    },
    /*
    getProcessedJson
    ---------------
    Get only the data to export, if no fields are set return all the data
    */
    getProcessedJson: function(data, header) {
    let keys = this.getKeys(data, header)
    let newData =
    let _self = this
    data.map(function(item, index) {
    let newItem = {}
    for (let label in keys) {
    var iii = item
    let property = keys[label]
    newItem[label] = _self.getNestedData(property, item)
    }
    newData.push(newItem)
    })

    return newData
    },
    getKeys: function(data, header) {
    if (header) {
    return header
    }

    let keys = {}
    for (let key in data[0]) {
    keys[key] = key
    }
    return keys
    },
    getNestedData: function(key, item) {
    let valueFromNestedKey = null
    let keyNestedSplit = key.split('.')
    valueFromNestedKey = item[keyNestedSplit[0]]
    for (let j = 1; j < keyNestedSplit.length; j++) {
    valueFromNestedKey = valueFromNestedKey[keyNestedSplit[j]]
    }
    return valueFromNestedKey
    },
    base64ToBlob: function(data, mime) {
    let base64 = window.btoa(window.unescape(encodeURIComponent(data)))
    let bstr = atob(base64)
    let n = bstr.length
    let u8arr = new Uint8ClampedArray(n)
    while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
    }
    return new Blob([u8arr], { type: mime })
    }
    } // end methods
    }
    </script>


    fileds 获取(该组件需要对标题进行格式化)
    ?
    methods
        setFields() {
    let _this = this
    let Obj = new Object()
    let arr = this.$refs.tables.$slots.default
    .filter(e => e.componentInstance)
    .map((column, index) => {
    const instance = column.componentOptions.propsData
    return instance
    })
    arr.forEach(element => {
    if (!!element['prop']) {
    _this.xlsfields[element['label']] = element['prop']
    }
    })
    }
    mounted
    mounted() {
    this.setFields()
    }

    RESTful 标准的axios封装(vue2.x)

    VUElopo1983 发表了文章 • 0 个评论 • 1746 次浏览 • 2018-01-04 16:54 • 来自相关话题

    export function ajax(url, params, type) {
    let config = { method: type || 'post' }
    if (type === 'get') {
    config.params = params
    } else if (type === 'put' || type === 'patch' || type === 'delete') {
    config.data = type ? {} : params
    config.headers = { 'Content-Type': 'application/x-www-form-urlencoded' }
    config.transformRequest = [
    () => {
    let ret = new URLSearchParams()
    for (let key in params) {
    ret.append(key, params[key])
    }
    return ret
    }
    ]
    } else {
    config.data = type ? {} : params
    }
    return instance(url, config).then(response => {
    return response.data
    })
    }?
    ?
    instance.interceptors.response.use(
    res => {
    if (res.data.code) {
    switch (res.data.code) {
    case 401:
    Lockr.rm('token')
    window.location.href="/#/benjo/mphjo/"
    break
    }
    } else {
    }
    return res
    },
    err => {
    if (err && err.response) {
    switch (err.response.status) {
    case 400:
    err.message = '请求错误'
    break
    case 401:
    err.message = '授权失败,请检查token'
    break
    case 403:
    err.message = '拒绝访问'
    break
    case 404:
    err.message = `请求${err.response.config.url
    .split('/')
    .pop()
    .replace(/\.html/, '')}接口出错`
    break
    case 408:
    err.message = '请求超时'
    break
    case 500:
    err.message = '万博manbetx手机在线登录网址内部错误'
    break
    case 501:
    err.message = '服务未实现'
    break
    case 502:
    err.message = '网关错误'
    break
    case 503:
    err.message = '服务不可用'
    break
    case 504:
    err.message = '网关超时'
    break
    case 505:
    err.message = 'HTTP版本不受支持'
    break
    default:
    }
    }
    store.commit('setModal', err.message)
    return Promise.reject(err)
    }
    ) 查看全部
    export function ajax(url, params, type) {
    let config = { method: type || 'post' }
    if (type === 'get') {
    config.params = params
    } else if (type === 'put' || type === 'patch' || type === 'delete') {
    config.data = type ? {} : params
    config.headers = { 'Content-Type': 'application/x-www-form-urlencoded' }
    config.transformRequest = [
    () => {
    let ret = new URLSearchParams()
    for (let key in params) {
    ret.append(key, params[key])
    }
    return ret
    }
    ]
    } else {
    config.data = type ? {} : params
    }
    return instance(url, config).then(response => {
    return response.data
    })
    }
    ?
    ?
    instance.interceptors.response.use(
    res => {
    if (res.data.code) {
    switch (res.data.code) {
    case 401:
    Lockr.rm('token')
    window.location.href="/#/benjo/mphjo/"
    break
    }
    } else {
    }
    return res
    },
    err => {
    if (err && err.response) {
    switch (err.response.status) {
    case 400:
    err.message = '请求错误'
    break
    case 401:
    err.message = '授权失败,请检查token'
    break
    case 403:
    err.message = '拒绝访问'
    break
    case 404:
    err.message = `请求${err.response.config.url
    .split('/')
    .pop()
    .replace(/\.html/, '')}接口出错`
    break
    case 408:
    err.message = '请求超时'
    break
    case 500:
    err.message = '万博manbetx手机在线登录网址内部错误'
    break
    case 501:
    err.message = '服务未实现'
    break
    case 502:
    err.message = '网关错误'
    break
    case 503:
    err.message = '服务不可用'
    break
    case 504:
    err.message = '网关超时'
    break
    case 505:
    err.message = 'HTTP版本不受支持'
    break
    default:
    }
    }
    store.commit('setModal', err.message)
    return Promise.reject(err)
    }
    )

    关于RESTful(仅供参考)

    每天进步一点点lopo1983 发表了文章 • 0 个评论 • 1224 次浏览 • 2018-01-03 03:53 • 来自相关话题

    Request 和 Response?
    GET(SELECT):从万博manbetx手机在线登录网址取出资源(一项或多项)POST(CREATE):在万博manbetx手机在线登录网址新建一个资源PUT(UPDATE):在万博manbetx手机在线登录网址更新资源(客户端提供完整资源数据)PATCH(UPDATE):在万博manbetx手机在线登录网址更新资源(客户端提供需要修改的资源数据)DELETE(DELETE):从万博manbetx手机在线登录网址删除资源
    ??
    PATCH 方法用来更新局部资源?
    PUT 方法用来更新完整的资源
    PATCH 与 PUT 属性上的一个重要区别还在于:PUT 是幂等的,而 PATCH 不是幂等的
    ?
    参考?理解HTTP幂等性,RESTful 手册
    ??
    当GET,PUT和PATCH请求成功时,要返回对应的数据,及状态码200,即SUCCESS当POST创建数据成功时,要返回创建的数据,及状态码201,即CREATED当DELETE删除数据成功时,不返回数据,状态码要返回204,即NO CONTENT当GET不到数据时,状态码要返回404,即NOT FOUND任何时候,如果请求有问题,如校验请求数据时发现错误,要返回状态码400,即BAD REQUEST当API 请求需要用户认证时,如果request中的认证信息不正确,要返回状态码401,即NOT AUTHORIZED当API 请求需要验证用户权限时,如果当前用户无相应权限,要返回状态码403,即FORBIDDEN

    JSON
    Number可以表示整数和浮点数。Boolean可以表示真假,值为true或false。String表示一个字符串。Null通常用于表示空对象。
    ?
    返回的数据包含在http响应体中。数据?必须(MUST)?是一个JSON Object。该Object可能包含3个字段:状态,状态信息,数据,版本号(如需要的话)。
    {
    "code": 200,
    "msg": {
    "text": "参数错误",
    "parameters": {
    "email": "电子邮件格式不正确"
    }
    },
    "data": {
    "data": [
    {
    "name": "Google",
    "url": "http://www.google.com"
    }
    ],
    "dateSelect": [
    "2018-1-1",
    "2018-1-3"
    ],
    "has_next": true,
    "has_prev": false,
    "page": 0,
    "pageSize": 1,
    "keyword": "",
    "totle": 20
    },
    "version": "3.0.2"
    }?
    URL Rules
    ?
    包含版本信息/api/v1/order/
    /api/v2/order/







    url是指向资源的,而不是描述行为# Bad APIs
    /api/getOrder/1/
    /api/updateOrder/1/
    /api/deleteOrder/1/

    # Good APIs
    /api/Order/1/
    避免浏览器默认行为的安全问题 确保GET和HEAD方法必须始终是安全的# Bad APIs

    # [DELETE]
    /api/Order?id=1
    通过url参数对资源进行过滤/api/Order&display=15&current=1&type=1
    至于编写RESTful API时到底应采用哪种方式,TMD 你想怎么玩就这么玩 别挖坑就好。
    ?
    ? 查看全部
    Request 和 Response?
    1. GET(SELECT):从万博manbetx手机在线登录网址取出资源(一项或多项)
    2. POST(CREATE):在万博manbetx手机在线登录网址新建一个资源
    3. PUT(UPDATE):在万博manbetx手机在线登录网址更新资源(客户端提供完整资源数据)
    4. PATCH(UPDATE):在万博manbetx手机在线登录网址更新资源(客户端提供需要修改的资源数据)
    5. DELETE(DELETE):从万博manbetx手机在线登录网址删除资源

    ??

    PATCH 方法用来更新局部资源?
    PUT 方法用来更新完整的资源
    PATCH 与 PUT 属性上的一个重要区别还在于:PUT 是幂等的,而 PATCH 不是幂等的
    ?
    参考?理解HTTP幂等性RESTful 手册


    ??
  • GET,PUTPATCH请求成功时,要返回对应的数据,及状态码200,即SUCCESS
  • POST创建数据成功时,要返回创建的数据,及状态码201,即CREATED
  • DELETE删除数据成功时,不返回数据,状态码要返回204,即NO CONTENT
  • GET不到数据时,状态码要返回404,即NOT FOUND
  • 任何时候,如果请求有问题,如校验请求数据时发现错误,要返回状态码400,即BAD REQUEST
  • 当API 请求需要用户认证时,如果request中的认证信息不正确,要返回状态码401,即NOT AUTHORIZED
  • 当API 请求需要验证用户权限时,如果当前用户无相应权限,要返回状态码403,即FORBIDDEN


  • JSON
  • Number可以表示整数和浮点数。
  • Boolean可以表示真假,值为true或false。
  • String表示一个字符串。
  • Null通常用于表示空对象。

  • ?

    返回的数据包含在http响应体中。数据?必须(MUST)?是一个JSON Object。该Object可能包含3个字段:状态,状态信息,数据,版本号(如需要的话)。


    {
    "code": 200,
    "msg": {
    "text": "参数错误",
    "parameters": {
    "email": "电子邮件格式不正确"
    }
    },
    "data": {
    "data": [
    {
    "name": "Google",
    "url": "http://www.google.com"
    }
    ],
    "dateSelect": [
    "2018-1-1",
    "2018-1-3"
    ],
    "has_next": true,
    "has_prev": false,
    "page": 0,
    "pageSize": 1,
    "keyword": "",
    "totle": 20
    },
    "version": "3.0.2"
    }
    ?
    URL Rules
    ?
    包含版本信息
    /api/v1/order/
    /api/v2/order/







    url是指向资源的,而不是描述行为
    # Bad APIs
    /api/getOrder/1/
    /api/updateOrder/1/
    /api/deleteOrder/1/

    # Good APIs
    /api/Order/1/

    避免浏览器默认行为的安全问题 确保GET和HEAD方法必须始终是安全的
    # Bad APIs

    # [DELETE]
    /api/Order?id=1

    通过url参数对资源进行过滤
    /api/Order&display=15&current=1&type=1

    至于编写RESTful API时到底应采用哪种方式,TMD 你想怎么玩就这么玩 别挖坑就好。
    ?
    ?

    http 错误代码表

    Nodejslopo1983 发表了文章 • 0 个评论 • 1064 次浏览 • 2017-12-18 12:01 • 来自相关话题

    所有 HTTP 状态代码及其定义。?
    代码??指示??
    2xx??成功??
    200??正常;请求已完成。??
    201??正常;紧接 POST 命令。??
    202??正常;已接受用于处理,但处理尚未完成。??
    203??正常;部分信息 — 返回的信息只是一部分。??
    204??正常;无响应 — 已接收请求,但不存在要回送的信息。??
    3xx??重定向??
    301??已移动 — 请求的数据具有新的位置且更改是永久的。??
    302??已找到 — 请求的数据临时具有不同 URI。??
    303??请参阅其它 — 可在另一 URI 下找到对请求的响应,且应使用 GET 方法检索此响应。??
    304??未修改 — 未按预期修改文档。??
    305??使用代理 — 必须通过位置字段中提供的代理来访问请求的资源。??
    306??未使用 — 不再使用;保留此代码以便将来使用。??
    4xx??客户机中出现的错误??
    400??错误请求 — 请求中有语法问题,或不能满足请求。??
    401??未授权 — 未授权客户机访问数据。??
    402??需要付款 — 表示计费系统已有效。??
    403??禁止 — 即使有授权也不需要访问。??
    404??找不到 — 万博manbetx手机在线登录网址找不到给定的资源;文档不存在。??
    407??代理认证请求 — 客户机首先必须使用代理认证自身。??
    415??介质类型不受支持 — 万博manbetx手机在线登录网址拒绝服务请求,因为不支持请求实体的格式。??
    5xx??万博manbetx手机在线登录网址中出现的错误??
    500??内部错误 — 因为意外情况,万博manbetx手机在线登录网址不能完成请求。??
    501??未执行 — 万博manbetx手机在线登录网址不支持请求的工具。??
    502??错误网关 — 万博manbetx手机在线登录网址接收到来自上游万博manbetx手机在线登录网址的无效响应。??
    503??无法获得服务 — 由于临时过载或维护,万博manbetx手机在线登录网址无法处理请求。
    ?
    --------------------------------------------------------------------------------------------------------
    ?
    HTTP?400?-?请求无效?
    HTTP?401.1?-?未授权:登录失败?
    HTTP?401.2?-?未授权:万博manbetx手机在线登录网址配置问题导致登录失败?
    HTTP?401.3?-?ACL?禁止访问资源?
    HTTP?401.4?-?未授权:授权被筛选器拒绝?
    HTTP?401.5?-?未授权:ISAPI?或?CGI?授权失败??
    HTTP?403?-?禁止访问?
    HTTP?403?-?对?Internet?服务管理器?(HTML)?的访问仅限于?Localhost?
    HTTP?403.1?禁止访问:禁止可执行访问?
    HTTP?403.2?-?禁止访问:禁止读访问?
    HTTP?403.3?-?禁止访问:禁止写访问?
    HTTP?403.4?-?禁止访问:要求?SSL?
    HTTP?403.5?-?禁止访问:要求?SSL?128?
    HTTP?403.6?-?禁止访问:IP?地址被拒绝?
    HTTP?403.7?-?禁止访问:要求客户证书?
    HTTP?403.8?-?禁止访问:禁止站点访问?
    HTTP?403.9?-?禁止访问:连接的用户过多?
    HTTP?403.10?-?禁止访问:配置无效?
    HTTP?403.11?-?禁止访问:密码更改?
    HTTP?403.12?-?禁止访问:映射器拒绝访问?
    HTTP?403.13?-?禁止访问:客户证书已被吊销?
    HTTP?403.15?-?禁止访问:客户访问许可过多?
    HTTP?403.16?-?禁止访问:客户证书不可信或者无效?
    HTTP?403.17?-?禁止访问:客户证书已经到期或者尚未生效?
    HTTP?404.1?-?无法找到?Web?站点?
    HTTP?404?-?无法找到文件?
    HTTP?405?-?资源被禁止?
    HTTP?406?-?无法接受?
    HTTP?407?-?要求代理身份验证?
    HTTP?410?-?永远不可用?
    HTTP?412?-?先决条件失败?
    HTTP?414?-?请求?-?URI?太长?
    HTTP?500?-?内部万博manbetx手机在线登录网址错误?
    HTTP?500.100?-?内部万博manbetx手机在线登录网址错误?-?ASP?错误?
    HTTP?500-11?万博manbetx手机在线登录网址关闭?
    HTTP?500-12?应用程序重新启动?
    HTTP?500-13?-?万博manbetx手机在线登录网址太忙?
    HTTP?500-14?-?应用程序无效?
    HTTP?500-15?-?不允许请求?global.asa?
    Error?501?-?未实现?
    HTTP?502?-?网关错误? 查看全部
    所有 HTTP 状态代码及其定义。?
    代码??指示??
    2xx??成功??
    200??正常;请求已完成。??
    201??正常;紧接 POST 命令。??
    202??正常;已接受用于处理,但处理尚未完成。??
    203??正常;部分信息 — 返回的信息只是一部分。??
    204??正常;无响应 — 已接收请求,但不存在要回送的信息。??
    3xx??重定向??
    301??已移动 — 请求的数据具有新的位置且更改是永久的。??
    302??已找到 — 请求的数据临时具有不同 URI。??
    303??请参阅其它 — 可在另一 URI 下找到对请求的响应,且应使用 GET 方法检索此响应。??
    304??未修改 — 未按预期修改文档。??
    305??使用代理 — 必须通过位置字段中提供的代理来访问请求的资源。??
    306??未使用 — 不再使用;保留此代码以便将来使用。??
    4xx??客户机中出现的错误??
    400??错误请求 — 请求中有语法问题,或不能满足请求。??
    401??未授权 — 未授权客户机访问数据。??
    402??需要付款 — 表示计费系统已有效。??
    403??禁止 — 即使有授权也不需要访问。??
    404??找不到 — 万博manbetx手机在线登录网址找不到给定的资源;文档不存在。??
    407??代理认证请求 — 客户机首先必须使用代理认证自身。??
    415??介质类型不受支持 — 万博manbetx手机在线登录网址拒绝服务请求,因为不支持请求实体的格式。??
    5xx??万博manbetx手机在线登录网址中出现的错误??
    500??内部错误 — 因为意外情况,万博manbetx手机在线登录网址不能完成请求。??
    501??未执行 — 万博manbetx手机在线登录网址不支持请求的工具。??
    502??错误网关 — 万博manbetx手机在线登录网址接收到来自上游万博manbetx手机在线登录网址的无效响应。??
    503??无法获得服务 — 由于临时过载或维护,万博manbetx手机在线登录网址无法处理请求。
    ?
    --------------------------------------------------------------------------------------------------------
    ?
    HTTP?400?-?请求无效?
    HTTP?401.1?-?未授权:登录失败?
    HTTP?401.2?-?未授权:万博manbetx手机在线登录网址配置问题导致登录失败?
    HTTP?401.3?-?ACL?禁止访问资源?
    HTTP?401.4?-?未授权:授权被筛选器拒绝?
    HTTP?401.5?-?未授权:ISAPI?或?CGI?授权失败??
    HTTP?403?-?禁止访问?
    HTTP?403?-?对?Internet?服务管理器?(HTML)?的访问仅限于?Localhost?
    HTTP?403.1?禁止访问:禁止可执行访问?
    HTTP?403.2?-?禁止访问:禁止读访问?
    HTTP?403.3?-?禁止访问:禁止写访问?
    HTTP?403.4?-?禁止访问:要求?SSL?
    HTTP?403.5?-?禁止访问:要求?SSL?128?
    HTTP?403.6?-?禁止访问:IP?地址被拒绝?
    HTTP?403.7?-?禁止访问:要求客户证书?
    HTTP?403.8?-?禁止访问:禁止站点访问?
    HTTP?403.9?-?禁止访问:连接的用户过多?
    HTTP?403.10?-?禁止访问:配置无效?
    HTTP?403.11?-?禁止访问:密码更改?
    HTTP?403.12?-?禁止访问:映射器拒绝访问?
    HTTP?403.13?-?禁止访问:客户证书已被吊销?
    HTTP?403.15?-?禁止访问:客户访问许可过多?
    HTTP?403.16?-?禁止访问:客户证书不可信或者无效?
    HTTP?403.17?-?禁止访问:客户证书已经到期或者尚未生效?
    HTTP?404.1?-?无法找到?Web?站点?
    HTTP?404?-?无法找到文件?
    HTTP?405?-?资源被禁止?
    HTTP?406?-?无法接受?
    HTTP?407?-?要求代理身份验证?
    HTTP?410?-?永远不可用?
    HTTP?412?-?先决条件失败?
    HTTP?414?-?请求?-?URI?太长?
    HTTP?500?-?内部万博manbetx手机在线登录网址错误?
    HTTP?500.100?-?内部万博manbetx手机在线登录网址错误?-?ASP?错误?
    HTTP?500-11?万博manbetx手机在线登录网址关闭?
    HTTP?500-12?应用程序重新启动?
    HTTP?500-13?-?万博manbetx手机在线登录网址太忙?
    HTTP?500-14?-?应用程序无效?
    HTTP?500-15?-?不允许请求?global.asa?
    Error?501?-?未实现?
    HTTP?502?-?网关错误?

    本站的VUE 实例中所用到的less 库

    CSS/SASS/SCSS/LESSlopo1983 发表了文章 • 0 个评论 • 1603 次浏览 • 2017-06-26 12:59 • 来自相关话题

    很多vue 文件里面会出来一个less 基础库 请下载放到assets>lib(可按照你习惯的路径安放 修改路径即可)
    下载地址如下?
    很多vue 文件里面会出来一个less 基础库 请下载放到assets>lib(可按照你习惯的路径安放 修改路径即可)
    下载地址如下?

    vue-form(vue表单验证插件 vue2.2+) 使用指南

    VUElopo1983 发表了文章 • 0 个评论 • 3171 次浏览 • 2017-06-13 10:40 • 来自相关话题

    vue-form 是一个在vue 中用于表单验证的插件 目前版本为4.1.1 ??Form validation for?Vue.js 2.2+
    官网地址:https://github.com/fergaldoyle/vue-form
    1.安装import VueForm from 'vue-form';
    // install globally
    Vue.use(VueForm);
    Vue.use(VueForm, options);
    // or use the mixin ...
    mixins: [VueForm]
    ...
    mixins: [new VueForm(options)]
    ...
    2.案例
    使用bootstrap样式的案例?https://jsfiddle.net/fergal_doyle/zfqt4yhq/
    密码验证的案例https://jsfiddle.net/fergal_doyle/9rn5kLkw/
    3.使用方法
    template: <vue-form :state="formstate" @submit.prevent="onSubmit">

    <validate tag="label">
    <span>Name *</span>
    <input v-model="model.name" required name="name" />

    <field-messages name="name">
    <div>Success!</div>
    <div slot="required">Name is a required field</div>
    </field-messages>
    </validate>

    <validate tag="label">
    <span>Email</span>
    <input v-model="model.email" name="email" type="email" required />

    <field-messages name="email">
    <div slot="required">Email is a required field</div>
    <div slot="email">Email is not valid</div>
    </field-messages>
    </validate>

    <button type="submit">Submit</button>
    </vue-form>
    scriptdata(){
    return{
    formstate: {},
    model: { name: '', email: 'invalid-email' } },
    }
    methods: {
    onSubmit: function () {
    if(this.formstate.$invalid) {
    // alert user and exit early
    return;
    }
    // otherwise submit form
    }
    }
    vue 中可直接通过FormData的方式提交数据 要获取该表单的所有数据 可给vue-form 添加ref属性来获取?let def = this.$refs.sendinfo.$el;
    验证信 息显示
    该插件使用field-messages标签来定义验证正确和错误的文字或其他形式的提示内容
    show 表示表单在何种状态下开始验证 vue-form 内置有$dirty,?$dirty && $touched,?$dirty || $touched,?$touched || $submitted
    示例:<field-messages name="name" show="$dirty && $touched">
    <div slot="errorKeyA">Error message A</div>
    <div slot="errorKeyB">Error message B</div>
    </field-messages>
    使用scope template<field-messages name="fieldName">
    <span>Success</span>
    <template slot="required" scope="state">
    <span v-if="state.$touched || state.$submitted">Name is a required field</span>
    </template>
    <template slot="errorKeyB" scope="state">
    <span v-if="state.$touched || state.$dirty">Error message B</span>
    </template>
    </field-messages>
    vue-form Validators
    默认自带验证类型type="email"
    type="url"
    type="number"
    required
    minlength
    maxlength
    pattern
    min (for type="number")
    max (for type="number")
    使用方法<!-- static validators -->
    <validate>
    <input type="email" name="email" v-model="model.email" required />
    </validate>
    <validate>
    <input type="text" name="name" v-model="model.name" maxlength="25" minlength="5" />
    </validate>

    <!-- bound validators -->
    <validate>
    <input type="email" name="email" v-model="model.email" :required="isRequired" />
    </validate>
    <validate>
    <input type="text" name="name" v-model="model.name" :maxlength="maxLen" :minlength="minLen" />
    </validate>
    自定义验证
    你可以全局或者局部注册自定义验证
    全部注册var options = {
    validators: {
    'my-custom-validator': function (value, attrValue, vnode) {
    // return true to set input as $valid, false to set as $invalid
    return value === 'custom';
    }
    }
    }

    Vue.use(VueForm, options);
    // or
    mixins: [new VueForm(options)]<validate>
    <input v-model="something" name="something" my-custom-validator />
    </validate>局部注册<validate :custom="{customValidator: customValidator}">
    <input v-model="something" name="something" />
    </validate>// ...
    methods: {
    customValidator: function (value) {
    // return true to set input as $valid, false to set as $invalid
    return value === 'custom';
    }
    }
    // ...Async 验证methods: {
    debounced: _.debounce(function (value, resolve, reject) {
    fetch('https://httpbin.org/get').then(function(response){
    resolve(response.isValid);
    });
    }, 500),
    customValidator (value) {
    return new Promise((resolve, reject) => {
    this.debounced(value, resolve, reject);
    });
    }
    }重置验证<vue-form ref="form" :state="formstate">

    resetState: function () {
    this.formstate._reset();
    // or
    this.$refs.form.reset();
    }
    未完待续..... 查看全部

    vue-form 是一个在vue 中用于表单验证的插件 目前版本为4.1.1 ??Form validation for?Vue.js 2.2+


    官网地址:https://github.com/fergaldoyle/vue-form


    1.安装
    import VueForm from 'vue-form'; 
    // install globally
    Vue.use(VueForm);
    Vue.use(VueForm, options);
    // or use the mixin ...
    mixins: [VueForm]
    ...
    mixins: [new VueForm(options)]
    ...

    2.案例
    使用bootstrap样式的案例?https://jsfiddle.net/fergal_doyle/zfqt4yhq/
    密码验证的案例https://jsfiddle.net/fergal_doyle/9rn5kLkw/
    3.使用方法
    template:
      <vue-form :state="formstate" @submit.prevent="onSubmit">

    <validate tag="label">
    <span>Name *</span>
    <input v-model="model.name" required name="name" />

    <field-messages name="name">
    <div>Success!</div>
    <div slot="required">Name is a required field</div>
    </field-messages>
    </validate>

    <validate tag="label">
    <span>Email</span>
    <input v-model="model.email" name="email" type="email" required />

    <field-messages name="email">
    <div slot="required">Email is a required field</div>
    <div slot="email">Email is not valid</div>
    </field-messages>
    </validate>

    <button type="submit">Submit</button>
    </vue-form>

    script
    data(){
    return{
    formstate: {},
    model: { name: '', email: 'invalid-email' } },
    }
    methods: {
    onSubmit: function () {
    if(this.formstate.$invalid) {
    // alert user and exit early
    return;
    }
    // otherwise submit form
    }
    }

    vue 中可直接通过FormData的方式提交数据 要获取该表单的所有数据 可给vue-form 添加ref属性来获取?let def = this.$refs.sendinfo.$el;


    验证信 息显示
    该插件使用field-messages标签来定义验证正确和错误的文字或其他形式的提示内容
    show 表示表单在何种状态下开始验证 vue-form 内置有$dirty,?$dirty && $touched,?$dirty || $touched,?$touched || $submitted
    示例:
    <field-messages name="name" show="$dirty && $touched">
    <div slot="errorKeyA">Error message A</div>
    <div slot="errorKeyB">Error message B</div>
    </field-messages>

    使用scope template
    <field-messages name="fieldName">
    <span>Success</span>
    <template slot="required" scope="state">
    <span v-if="state.$touched || state.$submitted">Name is a required field</span>
    </template>
    <template slot="errorKeyB" scope="state">
    <span v-if="state.$touched || state.$dirty">Error message B</span>
    </template>
    </field-messages>

    vue-form Validators
    默认自带验证类型
    type="email"
    type="url"
    type="number"
    required
    minlength
    maxlength
    pattern
    min (for type="number")
    max (for type="number")

    使用方法
    <!-- static validators -->
    <validate>
    <input type="email" name="email" v-model="model.email" required />
    </validate>
    <validate>
    <input type="text" name="name" v-model="model.name" maxlength="25" minlength="5" />
    </validate>

    <!-- bound validators -->
    <validate>
    <input type="email" name="email" v-model="model.email" :required="isRequired" />
    </validate>
    <validate>
    <input type="text" name="name" v-model="model.name" :maxlength="maxLen" :minlength="minLen" />
    </validate>

    自定义验证
    你可以全局或者局部注册自定义验证
    全部注册
    var options = {
    validators: {
    'my-custom-validator': function (value, attrValue, vnode) {
    // return true to set input as $valid, false to set as $invalid
    return value === 'custom';
    }
    }
    }

    Vue.use(VueForm, options);
    // or
    mixins: [new VueForm(options)]
    <validate>
    <input v-model="something" name="something" my-custom-validator />
    </validate>
    局部注册
    <validate :custom="{customValidator: customValidator}">
    <input v-model="something" name="something" />
    </validate>
    // ...
    methods: {
    customValidator: function (value) {
    // return true to set input as $valid, false to set as $invalid
    return value === 'custom';
    }
    }
    // ...
    Async 验证
    methods: {
    debounced: _.debounce(function (value, resolve, reject) {
    fetch('https://httpbin.org/get').then(function(response){
    resolve(response.isValid);
    });
    }, 500),
    customValidator (value) {
    return new Promise((resolve, reject) => {
    this.debounced(value, resolve, reject);
    });
    }
    }
    重置验证
    <vue-form ref="form" :state="formstate">

    resetState: function () {
    this.formstate._reset();
    // or
    this.$refs.form.reset();
    }

    未完待续.....

    百度BOS 上传 Vue 2.x封装

    VUElopo1983 发表了文章 • 0 个评论 • 1586 次浏览 • 2017-04-19 18:28 • 来自相关话题

    template
    <div class="fileup">
    <input type="file" ref="fileup" multiple="multiple" class="hide" name="fileUp" :id="rdid" @change="onFileChange" />
    <label class="btn btn-ces" :for="rdid"><span class="iconfont icon-add"></span>选择文件</label>
    <span>{{infomsg}}</span>
    <div class="fileup-area" v-show="files.length">
    <div class="col-md-2 files" v-for="(item,index) in files">
    <div class="thumbnail">
    <div class="thumbnail-object" :style="{'background-image':`url(${item.src})`}">
    <a class="ctr-bar" @click="delFile(index,item.key,item.status)">
    <span class="iconfont icon-del"></span>
    </a>
    </div>
    <div class="caption">
    <p class="name">{{item.name}}</p>
    <span class="iconfont icon-zhengque text-success" v-if="item.status==2"></span>
    <bsf-progress :state="item.progress" v-if="item.progress<100"></bsf-progress>
    </div>
    </div>
    </div>
    </div>
    <p class="btn-mix" v-if="files.length>0">
    <a class="btn btn-ces" @click="sendFile">提交</a>
    <a class="btn btn-default" @click="clearFile">取消</a>
    </p>
    </div>
    javascript
    import bos from '@/assets/js/bce-sdk-js/baidubce-sdk.bundle'
    import lib from "@/assets/js/lib"
    import bsfProgress from '@/components/comp/progress'
    import { bosConfig, bucket } from '@/config/bos'
    let client = new baidubce.sdk.BosClient(bosConfig);
    export default {
    name: "bosupt",
    components: {
    bsfProgress
    },
    props: {
    maxlength: {
    type: Number,
    default: 3
    },
    maxSize: {
    type: Number,
    default: 50000
    }
    },
    data() {
    return {
    files: [],
    infomsg:""
    }
    },
    computed: {
    rdid() {
    return "up" + Math.ceil(Math.random() * 1000, 3);
    }
    },
    methods: {
    onFileChange(evt) {
    let files = evt.target.files;
    let _this = this;
    if(files.length) {
    for(let i = 0, len = files.length; i < len; i++) {
    let file = files[i];
    let fcobj = {
    type: file.name.substring(file.name.lastIndexOf('.')).toLowerCase(),
    key: lib.randomStr(false, 5)
    };
    let o = {
    file: file, // File 对象
    status: 0, // 0:未上传 1:正在上传:2上传成功 3:上传失败
    progress: 0, // 上传进度
    type: fcobj.type,
    key: fcobj.key,
    name: file.name,
    size: file.size,
    path: "http://" + bucket + ".bj.bcebos.com/" + fcobj.key + fcobj.type
    };
    let reader = new FileReader()
    reader.readAsDataURL(file);
    reader.onload = (e) => {
    o.src = e.target.result // base64 可以作为判断是不是存在相同文件
    if(this.files.findIndex(f => f.src == o.src) > -1) {
    return false
    }
    if(o.size <= _this.maxSize) {
    this.files.push(o)
    } else {
    this.infomsg="图片太大了哦"
    return false
    }
    };
    };
    }
    Array.from(this.files).slice(0, this.maxlength)
    },
    delFile(index, key, status) {
    if(status == 2) {
    client.deleteObject(bucket, key).then(e => {
    e && this.files.splice(index, 1);
    }).catch(e => {
    console.log(e)
    })
    } else {
    this.files.splice(index, 1);
    }
    },
    clearFile() {
    let files = this.files;
    this.files = [];
    let ar = []
    this.$refs.fileup.value = "";
    this.$emit('clearfile', ar)
    },
    sendFile() {
    this.files.forEach(o => {
    if(o.status == 0) {
    let file = o.file
    let blob = file;
    let keytext = o.type;
    let key = o.key + keytext;
    const ext = key.split(/\./g).pop();
    let mimeType = baidubce.sdk.MimeType.guess(ext);
    if(/^text\//.test(mimeType)) {
    mimeType += '; charset=UTF-8';
    }
    let options = {
    'Content-Type': mimeType
    };
    client.putObjectFromBlob(bucket, key, blob, options)
    .then(function(res) {})
    .catch(function(err) {
    console.error(err);
    });
    client.on('progress', function(evt) {
    if(evt.lengthComputable) {
    o.progress = (evt.loaded / evt.total) * 100;
    o.status = 2;
    }
    });
    }
    });
    let ar = []
    this.files.forEach(e => {
    ar.push(e.path)
    });
    this.$emit('sendfile', ar)
    }
    },
    mounted: function() {
    this.$nextTick(function() {

    })
    }
    }
    BOS 配置
    bos.js
    const bosConfig = {
    credentials: {
    ak: '',
    sk: ''
    },
    endpoint: 'http://bj.bcebos.com'
    }
    const bucket = 'bucket名称';
    export{bosConfig,bucket}
    感谢戏子大爷 查看全部
    template
    <div class="fileup">
    <input type="file" ref="fileup" multiple="multiple" class="hide" name="fileUp" :id="rdid" @change="onFileChange" />
    <label class="btn btn-ces" :for="rdid"><span class="iconfont icon-add"></span>选择文件</label>
    <span>{{infomsg}}</span>
    <div class="fileup-area" v-show="files.length">
    <div class="col-md-2 files" v-for="(item,index) in files">
    <div class="thumbnail">
    <div class="thumbnail-object" :style="{'background-image':`url(${item.src})`}">
    <a class="ctr-bar" @click="delFile(index,item.key,item.status)">
    <span class="iconfont icon-del"></span>
    </a>
    </div>
    <div class="caption">
    <p class="name">{{item.name}}</p>
    <span class="iconfont icon-zhengque text-success" v-if="item.status==2"></span>
    <bsf-progress :state="item.progress" v-if="item.progress<100"></bsf-progress>
    </div>
    </div>
    </div>
    </div>
    <p class="btn-mix" v-if="files.length>0">
    <a class="btn btn-ces" @click="sendFile">提交</a>
    <a class="btn btn-default" @click="clearFile">取消</a>
    </p>
    </div>

    javascript
    import bos from '@/assets/js/bce-sdk-js/baidubce-sdk.bundle'
    import lib from "@/assets/js/lib"
    import bsfProgress from '@/components/comp/progress'
    import { bosConfig, bucket } from '@/config/bos'
    let client = new baidubce.sdk.BosClient(bosConfig);
    export default {
    name: "bosupt",
    components: {
    bsfProgress
    },
    props: {
    maxlength: {
    type: Number,
    default: 3
    },
    maxSize: {
    type: Number,
    default: 50000
    }
    },
    data() {
    return {
    files: [],
    infomsg:""
    }
    },
    computed: {
    rdid() {
    return "up" + Math.ceil(Math.random() * 1000, 3);
    }
    },
    methods: {
    onFileChange(evt) {
    let files = evt.target.files;
    let _this = this;
    if(files.length) {
    for(let i = 0, len = files.length; i < len; i++) {
    let file = files[i];
    let fcobj = {
    type: file.name.substring(file.name.lastIndexOf('.')).toLowerCase(),
    key: lib.randomStr(false, 5)
    };
    let o = {
    file: file, // File 对象
    status: 0, // 0:未上传 1:正在上传:2上传成功 3:上传失败
    progress: 0, // 上传进度
    type: fcobj.type,
    key: fcobj.key,
    name: file.name,
    size: file.size,
    path: "http://" + bucket + ".bj.bcebos.com/" + fcobj.key + fcobj.type
    };
    let reader = new FileReader()
    reader.readAsDataURL(file);
    reader.onload = (e) => {
    o.src = e.target.result // base64 可以作为判断是不是存在相同文件
    if(this.files.findIndex(f => f.src == o.src) > -1) {
    return false
    }
    if(o.size <= _this.maxSize) {
    this.files.push(o)
    } else {
    this.infomsg="图片太大了哦"
    return false
    }
    };
    };
    }
    Array.from(this.files).slice(0, this.maxlength)
    },
    delFile(index, key, status) {
    if(status == 2) {
    client.deleteObject(bucket, key).then(e => {
    e && this.files.splice(index, 1);
    }).catch(e => {
    console.log(e)
    })
    } else {
    this.files.splice(index, 1);
    }
    },
    clearFile() {
    let files = this.files;
    this.files = [];
    let ar = []
    this.$refs.fileup.value = "";
    this.$emit('clearfile', ar)
    },
    sendFile() {
    this.files.forEach(o => {
    if(o.status == 0) {
    let file = o.file
    let blob = file;
    let keytext = o.type;
    let key = o.key + keytext;
    const ext = key.split(/\./g).pop();
    let mimeType = baidubce.sdk.MimeType.guess(ext);
    if(/^text\//.test(mimeType)) {
    mimeType += '; charset=UTF-8';
    }
    let options = {
    'Content-Type': mimeType
    };
    client.putObjectFromBlob(bucket, key, blob, options)
    .then(function(res) {})
    .catch(function(err) {
    console.error(err);
    });
    client.on('progress', function(evt) {
    if(evt.lengthComputable) {
    o.progress = (evt.loaded / evt.total) * 100;
    o.status = 2;
    }
    });
    }
    });
    let ar = []
    this.files.forEach(e => {
    ar.push(e.path)
    });
    this.$emit('sendfile', ar)
    }
    },
    mounted: function() {
    this.$nextTick(function() {

    })
    }
    }

    BOS 配置
    bos.js
    const bosConfig = {
    credentials: {
    ak: '',
    sk: ''
    },
    endpoint: 'http://bj.bcebos.com'
    }
    const bucket = 'bucket名称';
    export{bosConfig,bucket}

    感谢戏子大爷