vue

vue

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

VUElopo1983 发表了文章 • 0 个评论 • 1976 次浏览 • 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 个评论 • 2110 次浏览 • 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 个评论 • 1789 次浏览 • 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 个评论 • 1401 次浏览 • 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 = '/#/admin/login/'
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 = '服务器内部错误'
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 = '/#/admin/login/'
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 = '服务器内部错误'
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 个评论 • 1018 次浏览 • 2018-01-03 03:53 • 来自相关话题

Request 和 Response?
GET(SELECT):从服务器取出资源(一项或多项)POST(CREATE):在服务器新建一个资源PUT(UPDATE):在服务器更新资源(客户端提供完整资源数据)PATCH(UPDATE):在服务器更新资源(客户端提供需要修改的资源数据)DELETE(DELETE):从服务器删除资源
??
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):从服务器取出资源(一项或多项)
  2. POST(CREATE):在服务器新建一个资源
  3. PUT(UPDATE):在服务器更新资源(客户端提供完整资源数据)
  4. PATCH(UPDATE):在服务器更新资源(客户端提供需要修改的资源数据)
  5. DELETE(DELETE):从服务器删除资源

??

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 个评论 • 866 次浏览 • 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??找不到 — 服务器找不到给定的资源;文档不存在。??
407??代理认证请求 — 客户机首先必须使用代理认证自身。??
415??介质类型不受支持 — 服务器拒绝服务请求,因为不支持请求实体的格式。??
5xx??服务器中出现的错误??
500??内部错误 — 因为意外情况,服务器不能完成请求。??
501??未执行 — 服务器不支持请求的工具。??
502??错误网关 — 服务器接收到来自上游服务器的无效响应。??
503??无法获得服务 — 由于临时过载或维护,服务器无法处理请求。
?
--------------------------------------------------------------------------------------------------------
?
HTTP?400?-?请求无效?
HTTP?401.1?-?未授权:登录失败?
HTTP?401.2?-?未授权:服务器配置问题导致登录失败?
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?-?内部服务器错误?
HTTP?500.100?-?内部服务器错误?-?ASP?错误?
HTTP?500-11?服务器关闭?
HTTP?500-12?应用程序重新启动?
HTTP?500-13?-?服务器太忙?
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??找不到 — 服务器找不到给定的资源;文档不存在。??
407??代理认证请求 — 客户机首先必须使用代理认证自身。??
415??介质类型不受支持 — 服务器拒绝服务请求,因为不支持请求实体的格式。??
5xx??服务器中出现的错误??
500??内部错误 — 因为意外情况,服务器不能完成请求。??
501??未执行 — 服务器不支持请求的工具。??
502??错误网关 — 服务器接收到来自上游服务器的无效响应。??
503??无法获得服务 — 由于临时过载或维护,服务器无法处理请求。
?
--------------------------------------------------------------------------------------------------------
?
HTTP?400?-?请求无效?
HTTP?401.1?-?未授权:登录失败?
HTTP?401.2?-?未授权:服务器配置问题导致登录失败?
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?-?内部服务器错误?
HTTP?500.100?-?内部服务器错误?-?ASP?错误?
HTTP?500-11?服务器关闭?
HTTP?500-12?应用程序重新启动?
HTTP?500-13?-?服务器太忙?
HTTP?500-14?-?应用程序无效?
HTTP?500-15?-?不允许请求?global.asa?
Error?501?-?未实现?
HTTP?502?-?网关错误?

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

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

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

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

VUElopo1983 发表了文章 • 0 个评论 • 2822 次浏览 • 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 个评论 • 1351 次浏览 • 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 个评论 • 1976 次浏览 • 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 个评论 • 2110 次浏览 • 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 个评论 • 1789 次浏览 • 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 个评论 • 1401 次浏览 • 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 = '/#/admin/login/'
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 = '服务器内部错误'
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 = '/#/admin/login/'
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 = '服务器内部错误'
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 个评论 • 1018 次浏览 • 2018-01-03 03:53 • 来自相关话题

Request 和 Response?
GET(SELECT):从服务器取出资源(一项或多项)POST(CREATE):在服务器新建一个资源PUT(UPDATE):在服务器更新资源(客户端提供完整资源数据)PATCH(UPDATE):在服务器更新资源(客户端提供需要修改的资源数据)DELETE(DELETE):从服务器删除资源
??
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):从服务器取出资源(一项或多项)
  2. POST(CREATE):在服务器新建一个资源
  3. PUT(UPDATE):在服务器更新资源(客户端提供完整资源数据)
  4. PATCH(UPDATE):在服务器更新资源(客户端提供需要修改的资源数据)
  5. DELETE(DELETE):从服务器删除资源

??

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 个评论 • 866 次浏览 • 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??找不到 — 服务器找不到给定的资源;文档不存在。??
407??代理认证请求 — 客户机首先必须使用代理认证自身。??
415??介质类型不受支持 — 服务器拒绝服务请求,因为不支持请求实体的格式。??
5xx??服务器中出现的错误??
500??内部错误 — 因为意外情况,服务器不能完成请求。??
501??未执行 — 服务器不支持请求的工具。??
502??错误网关 — 服务器接收到来自上游服务器的无效响应。??
503??无法获得服务 — 由于临时过载或维护,服务器无法处理请求。
?
--------------------------------------------------------------------------------------------------------
?
HTTP?400?-?请求无效?
HTTP?401.1?-?未授权:登录失败?
HTTP?401.2?-?未授权:服务器配置问题导致登录失败?
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?-?内部服务器错误?
HTTP?500.100?-?内部服务器错误?-?ASP?错误?
HTTP?500-11?服务器关闭?
HTTP?500-12?应用程序重新启动?
HTTP?500-13?-?服务器太忙?
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??找不到 — 服务器找不到给定的资源;文档不存在。??
407??代理认证请求 — 客户机首先必须使用代理认证自身。??
415??介质类型不受支持 — 服务器拒绝服务请求,因为不支持请求实体的格式。??
5xx??服务器中出现的错误??
500??内部错误 — 因为意外情况,服务器不能完成请求。??
501??未执行 — 服务器不支持请求的工具。??
502??错误网关 — 服务器接收到来自上游服务器的无效响应。??
503??无法获得服务 — 由于临时过载或维护,服务器无法处理请求。
?
--------------------------------------------------------------------------------------------------------
?
HTTP?400?-?请求无效?
HTTP?401.1?-?未授权:登录失败?
HTTP?401.2?-?未授权:服务器配置问题导致登录失败?
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?-?内部服务器错误?
HTTP?500.100?-?内部服务器错误?-?ASP?错误?
HTTP?500-11?服务器关闭?
HTTP?500-12?应用程序重新启动?
HTTP?500-13?-?服务器太忙?
HTTP?500-14?-?应用程序无效?
HTTP?500-15?-?不允许请求?global.asa?
Error?501?-?未实现?
HTTP?502?-?网关错误?

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

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

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

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

VUElopo1983 发表了文章 • 0 个评论 • 2822 次浏览 • 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 个评论 • 1351 次浏览 • 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}

感谢戏子大爷