| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- <template>
- <!-- renderjs 触发器:通过改变 prop 来触发文件选择 -->
- <view
- style="position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0;"
- :change:triggerPicker="renderJS.onTriggerChange"
- :triggerPicker="triggerFlag"
- :change:acceptProp="renderJS.acceptChanged"
- :acceptProp="accept">
- </view>
- </template>
- <script>
- export default {
- props: {
- // 触发标记(外部改变此值可触发文件选择)
- trigger: {
- type: Number,
- default: 0
- },
- // 接受的文件类型
- accept: {
- type: String,
- default: '*'
- }
- },
- data() {
- return {
- triggerFlag: 0
- }
- },
- watch: {
- // 监听外部 trigger 的变化
- trigger(newVal) {
- if (newVal) {
- this.triggerFlag = newVal
- }
- }
- },
- onLoad(res) {},
- methods: {
- // plus.io选择文件
- // 选择完文件后,拿到的是base64字符串,转成对应的数据
- parseJSONData(base64Str) {
- console.log('选择的文件base64Str', base64Str)
- let jsonStr = this.convertBase64ToUTF8(base64Str)
- if (base64Str.includes('application/json')) {
- let jsonData = JSON.parse(jsonStr)
- this.$emit('readJSONFinish', { jsonData })
- } else {
- this.$emit('readJSONFinish', { jsonStr })
- }
- },
- convertBase64ToUTF8(base64Str) {
- let base64Content = atob(base64Str.split(',')[1])
- base64Content = base64Content
- .split('')
- .map(function (c) {
- return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
- })
- .join('')
- try {
- let jsonStr = decodeURIComponent(base64Content)
- return jsonStr
- } catch (error) {
- console.error('读取失败', error)
- uni.showToast({
- title: '读取失败,不支持此格式文件',
- icon: 'none'
- })
- }
- },
- async receiveRenderFile(result) {
- console.log('receiveRenderFile 被调用,文件信息:', result)
-
- // 直接 emit 原始文件数据(包含 base64),不进行转换
- this.$emit('receiveRenderFile', result)
-
- // #ifdef APP-PLUS
- // 如果需要本地路径,可以进行转换(可选)
- // const fileUrl = await this.base64toPath(result.filePath, result.name)
- // this.fileName = fileUrl.relativePath
- // this.filePath = fileUrl.localAbsolutePath
- // #endif
- // #ifdef H5
- this.fileName = result.name
- this.filePath = result.filePath
- // #endif
- },
- //将base64转成路径
- async base64toPath(base64, attachName) {
- console.log('base64开始转化成文件')
- let _that = this
- return new Promise(function (resolve, reject) {
- const filePath = `_doc/yourFilePath/${attachName}`
- plus.io.resolveLocalFileSystemURL(
- '_doc',
- function (entry) {
- entry.getDirectory(
- 'yourFilePath',
- {
- create: true,
- exclusive: false
- },
- function (entry) {
- entry.getFile(
- attachName,
- {
- create: true,
- exclusive: false
- },
- function (entry) {
- entry.createWriter(function (writer) {
- writer.onwrite = function (res) {
- console.log('base64转化文件完成')
- const obj = {
- relativePath: filePath,
- localAbsolutePath:
- plus.io.convertLocalFileSystemURL(filePath)
- }
- resolve(obj)
- }
- writer.onerror = reject
- writer.seek(0)
- writer.writeAsBinary(
- _that.getSymbolAfterString(base64, ',')
- )
- }, reject)
- },
- reject
- )
- },
- reject
- )
- },
- reject
- )
- })
- },
- // 取某个符号后面的字符
- getSymbolAfterString(val, symbolStr) {
- if (val == undefined || val == null || val == '') {
- return ''
- }
- val = val.toString()
- const index = val.indexOf(symbolStr)
- if (index != -1) {
- val = val.substring(index + 1, val.length)
- return val
- } else {
- return val
- }
- }
- }
- }
- </script>
- <script module="renderJS" lang="renderjs">
- export default {
- data() {
- return {
- acceptType: '*'
- }
- },
- mounted() {
- // renderjs 的 mounted 不接收参数,acceptType 通过 acceptChanged 方法初始化
- console.log('cop-chooseFile renderJS mounted')
- },
- methods: {
- // 监听触发标记的变化
- onTriggerChange(newVal, oldVal, ownerVm, ins) {
- console.log('cop-chooseFile: 触发标记改变', newVal)
-
- if (newVal && newVal !== oldVal) {
- this.createFileInputDom(null, ownerVm)
- }
- },
-
- // 接收 accept 属性的变化
- acceptChanged(newVal) {
- this.acceptType = newVal || '*'
- },
-
- createFileInputDom(e, ownerVm) {
- console.log('cop-chooseFile: 开始选择文件')
-
- let fileInput = document.createElement('input')
- fileInput.setAttribute('type', 'file')
- fileInput.setAttribute('accept', this.acceptType)
- fileInput.style.display = 'none'
- document.body.appendChild(fileInput)
-
- fileInput.click()
- fileInput.addEventListener('change', e => {
- let file = e.target.files[0]
-
- if (file) {
- console.log('cop-chooseFile: 选择了文件', file.name, file.size)
-
- // #ifdef APP-PLUS
- let reader = new FileReader();
- reader.readAsDataURL(file);
- reader.onload = function(event) {
- const base64Str = event.target.result; // 文件的base64
- console.log('cop-chooseFile: 文件读取完成')
-
- // 先调用 receiveRenderFile 传递原始文件信息(用于所有文件类型)
- ownerVm.callMethod('receiveRenderFile', {
- name: file.name,
- filePath: base64Str,
- size: file.size,
- type: file.type
- })
-
- // 只对文本/JSON 文件调用 parseJSONData
- const isTextFile = file.type.includes('text') || file.type.includes('json') ||
- file.name.endsWith('.txt') || file.name.endsWith('.json')
-
- if (isTextFile) {
- try {
- ownerVm.callMethod('parseJSONData', base64Str)
- } catch(e) {
- console.log('parseJSONData failed:', e.message)
- }
- }
- }
- // #endif
- // #ifdef H5
- // 如果需要得到文件的本地路径,可以通过下面方法
- const filePath = URL.createObjectURL(file)
- ownerVm.callMethod('receiveRenderFile', {
- name: file.name,
- filePath: filePath,
- size: file.size,
- type: file.type
- })
- // #endif
- } else {
- console.log('cop-chooseFile: 未选择文件')
- }
-
- // 清理 input 元素
- setTimeout(function() {
- if (fileInput.parentNode) {
- document.body.removeChild(fileInput)
- console.log('cop-chooseFile: input 已清理')
- }
- }, 100)
- })
- }
- }
- }
- </script>
- <style scoped>
- /* 无样式,组件为隐藏触发器 */
- </style>
|