学习vue——图片、富文本的新增与修改回显

 

方法一

 1 <el-upload
 2       ref="RefUpload"
 3       class="avatar-uploader"
 4       :auto-upload="false"
 5       :show-file-list="false"
 6       :on-change="handleChange"
 7     >
 8       <img v-if="imageUrl" :src="imageUrl" class="avatar" />
 9       <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
10     </el-upload>
11     
12     <el-button type="primary" style="margin-top: 20px;" :icon="Plus" 
13     @click="RefUpload.$el.querySelector('input').click()" <--!--点击按钮调出文件选择框-->
14     >选择图片</el-button>
        <el-button type="primary" style="margin-top: 20px;" :icon="Upload" @click='uploadImage'>上传头像</el-button>
 
 1 const imageUrl = ref() 
 4 const RefUpload = ref() // 用于按钮调出文件选择框
 5 const submitImage = ref()
 6 // 预览图片
 7 const handleChange = (file) => {
 8   imageUrl.value = URL.createObjectURL(file.raw)
 9   submitImage.value = file.raw
10 }
11 // 上传图片到后端
12 const uploadImage = async () => {
13   const formData = new FormData()
14   formData.append('cover_img', submitImage.value)
15   const { data } = await artAddChannelService(formData)
16   console.log(data)
17 }

 

django

1 from django.conf import settings
2 import os
3 import base64
4 
5 file = request.FILES.get("image")
6 path = os.path.join(settings.STATICFILES_DIRS[0], 'xx3.jpeg')
7 if file:
8    with open(path, 'wb') as f:
9                 f.write(file.open())

 

方法二(byte)

 1 // 方法二
      const imageUrl = ref()
 2 const handleChange = (uploadFile) => {
 3   // 基于 FileReader 读取图片做预览
 4   const reader = new FileReader()
 5   reader.readAsDataURL(uploadFile.raw)
 6   reader.onload = () => {
 7     imageUrl.value = reader.result
 8   }
 9 }
10 const uploadImage = async () => {
11   console.log(imageUrl.value)
12   const { data } = await artAddChannelService(imageUrl.value)
13   console.log(data)
14 }

django

 1 path = os.path.join(settings.STATICFILES_DIRS[0], 'xx3.jpeg')
 2 image_base64 = request.body.decode()
 3 if image_base64:
 4         # 去掉 base64 图片数据中的前缀(如果有)
 5         image_base64 = image_base64.split(',')[1]
 6         print(image_base64)
 7         # 解码 base64 数据
 8         file = base64.b64decode(image_base64)    
 9         if file:
10             with open(path, 'wb') as f:
11                 f.write(file)

css

 1 </template>
 2 <style lang="scss" scoped>
 3 .avatar-uploader {
 4   :deep() {
 5     .avatar {
 6       width: 278px;
 7       height: 278px;
 8       display: block;
 9     }
10     .el-upload {
11       border: 1px dashed var(--el-border-color);
12       border-radius: 6px;
13       cursor: pointer;
14       position: relative;
15       overflow: hidden;
16       transition: var(--el-transition-duration-fast);
17     }
18     .el-upload:hover {
19       border-color: var(--el-color-primary);
20     }
21     .el-icon.avatar-uploader-icon {
22       font-size: 28px;
23       color: #8c939d;
24       width: 278px;
25       height: 278px;
26       text-align: center;
27     }
28   }
29 }
30 </style>
View Code

 

提要

富文本使用链接:https://vueup.github.io/vue-quill/

父组件

1 <tempalte>
2  <!-- 抽屉  -->
3   <drawer-page ref="open" @tijiao = EmitData></drawer-page>
4 </template>
 1 <script lang="ts" setup>
 2 const open = ref()
 3 
 4 const EmitData = (data) => {
 5   // .get 是FromDate 的获取方式
 6   console.log("cover_img:",data.get("cover_img"))
 7   // 子组件传来的数据,父组件负责新增、修改
 8   artAddChannelService(data)
 9 }
10 </script>
// 新增
const pubulic = () => {
  open.value.open()
}
// 修改
const Edit = (row) => {
  console.log(row)
  // 调用子组件的方法open
  open.value.open(row)
}

 

子组件

 1 <template>
 2 <!-- 图片 -->
 3 <el-form-item label="cover_img" prop="cover_img">
 4                     <el-upload
 5                         class="avatar-uploader"
 6                         :show-file-list="false"
 7                         :auto-upload="false"
 8                         :on-change="upImage"
 9                     >
10                         <img v-if="imageUrl" :src="imageUrl" class="avatar" />
11                         <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
12                     </el-upload>
13 </el-form-item>
14 <!-- 富文本 -->
15 <el-form-item label="content">
16                     <div class="editor">
17                     <quill-editor ref="qedit" theme="snow"  
18                       v-model:content="ruleForm.content" content-type="html">
19                     </quill-editor>
20                     </div>
21 </el-form-item>
22 </template>
 1 <script lang="ts" setup>
 2 import { ref } from 'vue'
 3 import { ElMessageBox } from 'element-plus'
 4 import SearchSelect from './SearchSelect.vue';
 5 import { Plus } from '@element-plus/icons-vue'
 6 import { QuillEditor } from '@vueup/vue-quill'
 7 import '@vueup/vue-quill/dist/vue-quill.snow.css';
 8 
 9 
10 const defaultForm = {date:'',name:'',address:'',cover_img:'',content:''}
11 const ruleForm = ref({ ...defaultForm })
12 // 抽屉
13 const drawer = ref(false)
14 const cancelClick = () => {
15   drawer.value = false
16 }
17 
18 // 富文本,作用为了清空富文本
19 const qedit = ref()
20 // 本地预览图片
21 const imageUrl = ref('')
22 const upImage = (image) => {
23     console.log(image.raw)
24     // 本地预览
25     imageUrl.value = URL.createObjectURL(image.raw)
26     // 添加到要提交的数据里
27     ruleForm.value.cover_img = image.raw
28 }
29 
30 
31 // 父组件打开抽屉
32 const open = (row) => {
33     drawer.value = true
34     console.log(row)
35     if(row){
36         console.log("编辑")
37         // 回显数据
38         ruleForm.value = {...row}
39         // 回显图片
40         imageUrl.value = ruleForm.value.cover_img
41         
42     }else{
43         console.log("新建")
44         // 置空
45         ruleForm.value = { ...defaultForm }
46         imageUrl.value = ''
47         qedit.value.setHTML('')
48     }   
49 }
50 defineExpose({
51     open
52 })
53 
54 // 子组件触发提交
55 const emit = defineEmits(['tijiao'])
56 const confirmClick = () => {
57   ElMessageBox.confirm(`Are you confirm ?`)
58     .then(() => {
59       drawer.value = false
60       // 把图片做成对象的形式
61       const fd = new FormData()
62       for (const key in ruleForm.value) {
63             console.log(`key:${key},${ruleForm.value[key]}`)
64             fd.append(key, ruleForm.value[key])
65           }
66       // artAddChannelService(fd) 可以在子组件提交
67       // 交给父组件提交
68       emit('tijiao',fd)
69       
70     })
71     .catch(() => {
72       // catch error
73     })
74 }
75 
76 </script>

上传图片的css

 1 <style lang="scss" scoped>
 2 .avatar-uploader {
 3   :deep() {
 4     .avatar {
 5       width: 178px;
 6       height: 178px;
 7       display: block;
 8     }
 9     .el-upload {
10       border: 1px dashed var(--el-border-color);
11       border-radius: 6px;
12       cursor: pointer;
13       position: relative;
14       overflow: hidden;
15       transition: var(--el-transition-duration-fast);
16     }
17     .el-upload:hover {
18       border-color: var(--el-color-primary);
19     }
20     .el-icon.avatar-uploader-icon {
21       font-size: 28px;
22       color: #8c939d;
23       width: 178px;
24       height: 178px;
25       text-align: center;
26     }
27   }
28 }
29 
30 .editor {
31   width: 100%;
32   :deep(.ql-editor) {
33     min-height: 200px;
34   }
35 }
36 </style>

 完整版本

父组件

  1 <script lang="ts" setup>
  2 import { ref } from 'vue'
  3 import DrawerPage from './components/DrawerPage.vue';
  4 import SearchSelect from './components/SearchSelect.vue';
  5 import { formatTime } from '@/utils/formdate';
  6 import { artAddChannelService } from '@/api/article.js'
  7 import { useRouter } from 'vue-router'
  8 const router = useRouter()
  9 const cat = () => {
 10   console.log(value.value)
 11 }
 12 const open = ref()
 13 
 14 const tableData = [
 15   {
 16     id: 1,
 17     date: '2016-05-03 12:23:00',
 18     name: 'Tom',
 19     address: 'No. 189, Grove St, Los Angeles',
 20     cover_img:"http://127.0.0.1:8000/static/xx.jpeg",
 21     content:'<p style="color: red">1233</p>'
 22   },
 23   {
 24     id: 2,
 25     date: '2016-05-02',
 26     name: 'Tom',
 27     address: 'No. 189, Grove St, Los Angeles',
 28     cover_img:"http://127.0.0.1:8000/static/xx.jpeg",
 29     content:'<p style="color: red">1233</p>'
 30   },
 31   {
 32     id: 3,
 33     date: '2016-05-04',
 34     name: 'Tom',
 35     address: 'No. 189, Grove St, Los Angeles',
 36     cover_img:"http://127.0.0.1:8000/static/xx.jpeg",
 37     content:'<p style="color: red">1233</p>'
 38   },
 39   {
 40     id: 4,
 41     date: '2016-05-01',
 42     name: 'Tom',
 43     address: 'No. 189, Grove St, Los Angeles',
 44     cover_img:"http://127.0.0.1:8000/static/xx.jpeg",
 45     content:'<p style="color: red">1233</p>'
 46   },
 47 ]
 48 // 新增
 49 const pubulic = () => {
 50   open.value.open()
 51 }
 52 // 修改
 53 const Edit = (row) => {
 54   console.log(row)
 55   // 调用子组件的方法open
 56   open.value.open(row)
 57 }
 58 
 59 const EmitData = (data) => {
 60   // .get 是FromDate 的获取方式
 61   console.log("cover_img:",data.get("cover_img"))
 62   // 子组件传来的数据,父组件负责新增、修改
 63   artAddChannelService(data)
 64 }
 65 const value = ref({
 66   page: 1,
 67   size: 2,
 68   selectId : ""
 69 })
 70 </script>
 71 <template>
 72   <title-page title="文章管理">
 73     <template #extra>
 74       <div>
 75         <el-button @click="pubulic">发布文章</el-button>
 76       </div>
 77     </template>
 78     
 79       <el-form inline >
 80         <el-form-item label="文章标题" >
 81           <search-select v-model="value.selectId"></search-select>
 82         </el-form-item>
 83         <el-form-item label="发布状态">
 84           <el-select label="发布状态" >
 85             <el-option label="已发布" value=1>新闻</el-option>
 86             <el-option label="未发布" value=0>新闻</el-option>
 87           </el-select>
 88           
 89         </el-form-item>
 90         <el-form-item>
 91           <el-button  style="margin-left: 25px"type="primary">搜索</el-button>
 92           <el-button plan>重置</el-button>
 93           <el-button plan @click="cat">cat</el-button>
 94         </el-form-item>
 95       </el-form>
 96       
 97 
 98     
 99 
100     <el-table :data="tableData" style="width: 100%">
101       <el-table-column type="index" label="index" width="180" />
102       <el-table-column prop="date" label="Date" width="180" >
103         <template #default="{ row }">
104           {{ formatTime(row.date) }}
105         </template>
106       </el-table-column>
107       
108       <el-table-column prop="name" label="Name" width="180" >
109         <template #default="{ row }">
110           <el-link @click="router.push(`/article/detail/?aid=${row.id}`)" type="primary" :underline="false">{{ row.name }}</el-link>
111           <!-- <el-link @click="router.push(`/article/detail/${row.id}`)" type="primary" :underline="false">{{ row.name }}</el-link> -->
112         </template>
113       </el-table-column>
114       <el-table-column prop="address" label="Address" />
115       
116       <el-table-column label="Operations">
117       <template #default="scope">
118         <el-button size="small" circle icon="Edit" @click="Edit(scope.row)"></el-button>
119         <el-button
120           size="small"
121           type="danger"
122           circle
123           icon="Delete"
124           
125         >
126           
127         </el-button>
128       </template>
129     </el-table-column>
130     
131     <template #empty>
132       <el-empty description="暂无数据"></el-empty>
133     </template>
134     
135     </el-table>
136 
137     <el-pagination
138      v-if="tableData.length>0"
139       v-model:current-page=value.page
140       v-model:page-size=value.size
141       :page-sizes="[5, 10, 20, 100]"
142      
143   
144       :background="true"
145       layout="jumper,total, sizes, prev, pager, next "
146       :total="10"
147       style="justify-content: flex-end;"
148       next-text="下一页"
149       prev-text="上一页"
150 
151     />
152   </title-page>
153   
154   <!-- 抽屉  -->
155   <drawer-page ref="open" @tijiao = EmitData></drawer-page>
156 </template>
157 <style scoped>
158 .sear{
159 margin-bottom: 10px;
160 }
161 </style>
View Code

子组件

  1 <script lang="ts" setup>
  2 import { ref } from 'vue'
  3 import { ElMessageBox } from 'element-plus'
  4 import SearchSelect from './SearchSelect.vue';
  5 import { Plus } from '@element-plus/icons-vue'
  6 import { QuillEditor } from '@vueup/vue-quill'
  7 import '@vueup/vue-quill/dist/vue-quill.snow.css';
  8 
  9 
 10 const defaultForm = {date:'',name:'',address:'',cover_img:'',content:''}
 11 const ruleForm = ref({ ...defaultForm })
 12 // 抽屉
 13 const drawer = ref(false)
 14 const cancelClick = () => {
 15   drawer.value = false
 16 }
 17 
 18 // 富文本,作用为了清空富文本
 19 const qedit = ref()
 20 // 本地预览图片
 21 const imageUrl = ref('')
 22 const upImage = (image) => {
 23     console.log(image.raw)
 24     // 本地预览
 25     imageUrl.value = URL.createObjectURL(image.raw)
 26     // 添加到要提交的数据里
 27     ruleForm.value.cover_img = image.raw
 28 }
 29 
 30 
 31 // 父组件打开抽屉
 32 const open = (row) => {
 33     drawer.value = true
 34     console.log(row)
 35     if(row){
 36         console.log("编辑")
 37         // 回显数据
 38         ruleForm.value = {...row}
 39         // 回显图片
 40         imageUrl.value = ruleForm.value.cover_img
 41         
 42     }else{
 43         console.log("新建")
 44         // 置空
 45         ruleForm.value = { ...defaultForm }
 46         imageUrl.value = ''
 47         qedit.value.setHTML('')
 48     }   
 49 }
 50 defineExpose({
 51     open
 52 })
 53 
 54 // 子组件触发提交
 55 const emit = defineEmits(['tijiao'])
 56 const confirmClick = () => {
 57   ElMessageBox.confirm(`Are you confirm ?`)
 58     .then(() => {
 59       drawer.value = false
 60       // 把图片做成对象的形式
 61       const fd = new FormData()
 62       for (const key in ruleForm.value) {
 63             console.log(`key:${key},${ruleForm.value[key]}`)
 64             fd.append(key, ruleForm.value[key])
 65           }
 66       // artAddChannelService(fd) 可以在子组件提交
 67       // 交给父组件提交
 68       emit('tijiao',fd)
 69       
 70     })
 71     .catch(() => {
 72       // catch error
 73     })
 74 }
 75 // 富文本:https://vueup.github.io/vue-quill/
 76 </script>
 77 <template>
 78     <div>
 79         <el-drawer
 80             v-model="drawer"
 81             :title="ruleForm.name ? '编辑' : '新增' "
 82             direction="rtl"
 83             size=40%
 84         >
 85             <el-form label-width="auto" label-position="right"    :model="ruleForm">
 86                 <!-- <el-form-item label="name" prop="name">
 87                         <search-select v-model="articleId" width="100%" ></search-select>
 88                 </el-form-item> -->
 89                 <!-- 图片 -->
 90                 <el-form-item label="cover_img" prop="cover_img">
 91                     <el-upload
 92                         class="avatar-uploader"
 93                         :show-file-list="false"
 94                         :auto-upload="false"
 95                         :on-change="upImage"
 96                     >
 97                         <img v-if="imageUrl" :src="imageUrl" class="avatar" />
 98                         <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
 99                     </el-upload>
100                 </el-form-item>
101                 <!-- 富文本 -->
102                 <el-form-item label="content">
103                     <div class="editor">
104                     <quill-editor ref="qedit" theme="snow" v-model:content="ruleForm.content" content-type="html">
105                     </quill-editor>
106                     </div>
107                 </el-form-item>
108                 <el-form-item label="name" prop="name" >
109                     <el-input v-model="ruleForm.name" />
110                 </el-form-item>
111                 <el-form-item label="date" prop="date" >
112                     <el-input v-model="ruleForm.date" />
113                 </el-form-item>
114                 <el-form-item label="address" prop="address" >
115                     <el-input v-model="ruleForm.address" />
116                 </el-form-item>
117             </el-form>
118             <template #footer>
119             <div style="flex: auto">
120                 <el-button @click="cancelClick">cancel</el-button>
121                 <el-button type="primary" @click="confirmClick">confirm</el-button>
122             </div>
123             </template>
124         </el-drawer>
125     </div>
126 </template>
127 <style lang="scss" scoped>
128 .avatar-uploader {
129   :deep() {
130     .avatar {
131       width: 178px;
132       height: 178px;
133       display: block;
134     }
135     .el-upload {
136       border: 1px dashed var(--el-border-color);
137       border-radius: 6px;
138       cursor: pointer;
139       position: relative;
140       overflow: hidden;
141       transition: var(--el-transition-duration-fast);
142     }
143     .el-upload:hover {
144       border-color: var(--el-color-primary);
145     }
146     .el-icon.avatar-uploader-icon {
147       font-size: 28px;
148       color: #8c939d;
149       width: 178px;
150       height: 178px;
151       text-align: center;
152     }
153   }
154 }
155 
156 .editor {
157   width: 100%;
158   :deep(.ql-editor) {
159     min-height: 200px;
160   }
161 }
162 </style>
View Code

 django

 1 setting.py
 2 STATIC_URL = '/static/'
 3 STATICFILES_DIRS = (
 4     os.path.join(BASE_DIR, 'static'),
 5 )
 6 
 7 url.py
 8 from book import views
 9 from django.conf.urls import url
10 from django.conf import settings
11 from django.conf.urls.static import static
12 urlpatterns = [
13     # 大事件项目
14     url('/reg', views.reg),
15     url('/login', views.login),
16     url('/cate/list', views.articleList),
17     url('/cate/add', views.addAticle),
18 
19 ]+static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
View Code

 

posted @ 2024-10-25 17:51  东方不败--Never  阅读(24)  评论(0编辑  收藏  举报