第十八天 实战练习(5)
今天计划用Python继续一个web开发的实战项目练习,学习项目及练习源码地址:
GitHub源码
文章内容的编写与提交
富文本编辑器
我选择了TinyMCE,原因很简单,用的人多,而且支持的浏览器多,这两个理由足够了。
虽然中文文档比较少,但这个不是重要的,做一个东西,兼容性还是要考虑下的。
使用起步:
首先,需要下载一份copy,
然后:
<script src="/static/tinymce/tinymce.min.js"></script>
其次:将TinyMCE初始化为页面的一部分
<!DOCTYPE html>
<html>
<head>
<script src='/static/tinymce/tinymce.min.js'></script>
<script>
tinymce.init({
selector: '#mytextarea'
});
</script>
</head>
<body>
<h1>TinyMCE快速开始示例</h1>
<form method="post">
<textarea id="mytextarea">Hello, World!</textarea>
</form>
</body>
</html>
最后:数据提交
当form提交时,TinyMCE会将内容塞进textarea,你可以通过正常的post方法获取到编辑器中的内容,行为与普通textarea完全一致。
一个内联示例:
<div>
<div id="doc-app" style="display: block;">
<div class="toolbar"></div>
<div class="box">
<div class="tit"><input type="text" placeholder="请输入标题……"></div>
<div class="doc-cnt mce-content-body mce-edit-focus" id="tinydemo-doc" contenteditable="true" spellcheck="false" style="position: relative;"><blockquote><ul><li style="text-align: justify;" data-mce-style="text-align: justify;">在这里输入文字</li></ul></blockquote></div>
</div>
</div>
</div>
<script>
tinymce.init({
selector: '#tinydemo-doc',
language:'zh_CN',
menubar:false,
inline: true,
plugins: 'print preview searchreplace autolink fullscreen image link media code codesample table charmap hr pagebreak nonbreaking anchor advlist lists textpattern help emoticons autosave bdmap indent2em lineheight formatpainter axupimgs',
toolbar: 'code undo redo restoredraft | cut copy | forecolor backcolor bold italic underline strikethrough link | alignleft aligncenter alignright alignjustify | bullist numlist blockquote subscript superscript removeformat | \
formatselect fontselect fontsizeselect | \
table image media charmap emoticons hr pagebreak print preview | fullscreen | bdmap indent2em lineheight formatpainter axupimgs',
fixed_toolbar_container:'#doc-app .toolbar',
custom_ui_selector: 'body',
//auto_focus: true,
toolbar_drawer: false,
toolbar_sticky: true,
autosave_ask_before_unload: false,
fontsize_formats: '12px 14px 16px 18px 24px 36px 48px 56px 72px',
font_formats: '微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats;知乎配置=BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, WenQuanYi Micro Hei, sans-serif;小米配置=Helvetica Neue,Helvetica,Arial,Microsoft Yahei,Hiragino Sans GB,Heiti SC,WenQuanYi Micro Hei,sans-serif',
images_upload_base_path: '/demo',
images_upload_handler: function (blobInfo, succFun, failFun) {
succFun('/demo/images/img.jpg');
},
init_instance_callback: function(editor){
$('#doc-app').fadeIn(1500);
editor.execCommand('selectAll');
editor.selection.getRng().collapse(false);
editor.focus();
}
});
</script>
图片上传
设置初始化参数:images_upload_handler:upload_pic
var upload_pic = function (blobInfo, succFun, failFun) {
var file = blobInfo.blob();//转化为易于理解的file对象
var formData = new FormData();
formData.append('file', file, file.name );//此处与源文档不一样
console.log(formData.get('file')); //FormData私有类对象,访问不到,可以通过get判断值是否传进去
var config = {
headers: { 'Content-Type': 'multipart/form-data' }
}; //添加请求头
axios.post('/upload', formData, config)
.then(response => {
console.log(response.data);
succFun(response.data.filename);
})
.catch(error=>{
failFun(error)
})
}
图片处理服务端示例:
@post('/upload')
async def storefile(request):
try:
reader = await request.multipart()
file = await reader.next()
exts = ['.jpg','.jpeg','.png','.gif','.bpm']
filename = file.filename if file.filename else 'undefined'
suffix = os.path.splitext(filename)
filename = '{}{}'.format(short_uuid(),suffix[1])
filepath = '{}/{}'.format(config.app.uploaddir,filename)
size = 0
with open(filepath, 'wb') as f:
while True:
chunk = await file.read_chunk() # 默认是8192个字节。
if not chunk:
break
size += len(chunk)
f.write(chunk)
text = {'res': '上传成功','filename':'{}{}'.format('/static/uploads/',filename)}
result = text
return result
except Exception as e:
print(e)
result = {'success':False,'error': e}
return result
文件上传
类似于图片上传,这里不再举例
文档内容的保存
设置初始化参数:save_onsavecallback: saveConent
前端js代码:
var saveConent = function (el) {
// do the work on html
var title = $('#b_title').val();
var content = el.getContent()
var data = {
title: title || "",
content: content || ""
}
console.log(data);
axios.post('/b/0',data)
.then(res=>{
console.log(res);
})
.catch(err=>{
console.log(err);
})
}
后端处理:
'''
还没有作入数据库的处理,这里需要用户信息,所以需要处理session判定用户的合法性等
'''
@post('/b/{id}')
async def save_content(*,id,title,content,request):
result = {'success':False}
return result
网友评论