概论:一个网站必须使用单调视图为前端,单调指的是不直接由Python加载数据库内容。一般地,该单调视图仅包含在浏览器上运行的JS,而该JS(即VUE)负责动态加载数据库内容。
PVAJP的目的是解放全站所有UI互动的可能性,增强网站的互动性和编程自由度,同时减少服务器端内存的压力(因为减少了页面在服务器端提前渲染的过程)。本质上是将小网站推向中上规模网站的必经之路(PVAJP是模仿bilibili而制作的)。
PVAJP实现了 “html模板页面”,“vue程序”,“Python数据” 三者的独立(互不影响),在编程上高度解绑,适合多个人同时编写代码的场景。
改造内容:
1.动态bulk改造,包括对动态详情改造
2.Message盒子改造(将点赞/投旗/评论/关注四个分类展示)
3.文章详情改造(主要是评论区)
具体实现
Vue-模块化
将所需的pva.html引入,其会自带.css和.js,而自带的pva.js的data里会引入一个在view.html里穿插的简单script内容的 transferbridge : window.transferbridge(其中包含各种local window 变量,且可用django方法写入变量)。
<script type="text/javascript">
transferbridge = {
"citizen":{% if citizen %}{{citizen}}{%else%}false{%endif%},
}
</script>
mounted: function(){
this.fetchjson(window.transferbridge["x"])
},
Vue-HTML部分
如果对使用变量不确定存在,则保证引用它时不再引用它的下级,它本身的引入会不显示,同时不引起bug。 但下级的使用会造成 父级 undefined 错误。
对于{% verbatim %}则看情况放置。
<div id="Visible" v-show="mainstreamvisible" style="display:none;">
<div v-for="(bulk, index) in bulky">
{% verbatim %}
{% endverbatim %}
</div>
<div class="global_wait" v-show="bulkywait">{% include 'wait.html' %}</div>
<span @click="adds()" v-show="!bulkywait">点击加载更多</span>
</div>
#Visible{
width: 100%;
height: auto;
flex-direction: column;
align-items: center;
}
Vue-AJAX部分
fetchjson
注意判断combag里是否有空的查询,只允许非空部分进入。
一般配合bulkywait使用,来完成加载前等待动画(CSS3)。
fetchjson 标准使用:最新内容在上,加载出的古老内容在下面(也即 加载更多按钮 在 内容 的下面) 。
- 注意在push之前,combag[i] 可以加入其它与数据源头无关的本地控制信息。比如一个UI开关的 status。
- 当然也可以加入combag[i][commebag] 评论包,在点开评论区后写入包内容,这叫附带包。但一开始是空包。直到另一个fetchjson push 加载入包。
new Vue({
el : '#Visible',
data : {
bulky : [],
bulkywait: true,
transferbridge : function(){
if(window.transferbridge){
return window.transferbridge
}else{
return {"a":null,}
}
},
},
watch : {},
methods : {
fetchjson : function(range){
this.bulkywait = true
axios.post('',{limit:range}).then(response => {
var res = response.data
var combag = Object.assign([], res.combag);
for (var i = 1; i < combag.length; i++) {
//预处理
combag[i]["???bag"] = []
var tapeui = '/static/pvajp/img/tapeui/v'
//status转icons
combag[i]["icons"]['comment'] = tapeui + 'comment.svg'
combag[i]["icons"]["flag"] = tapeui+'flag.svg'
combag[i]["icons"]["flaged"] = tapeui+'flaged.svg'
//推送
this.bulky.push(combag[i])
//index = this.bulky.push(combag[i]) - 1
//得到hostUI的index,在套娃fetch时候有用。
//例如this.fetchkid(bulkyid,index)
};
this.bulkywait = false
this.from += 10
this.to += 10
});
},
},
mounted: function(){
this.fetchjson([0,10])
},
})
fetchjson : function(range){
this.bulkywait = true
axios.post('',{from:range[0],to:range[1]}).then(response => {
var res = response.data
var combag = Object.assign([], res.combag);
for (var i = 1; i < combag.length; i++) {
//预处理
combag[i]["xxbag"] = []
var tapeui = '/static/pvajp/img/tapeui/v'
//status转icons
combag[i]["icons"]['comment'] = tapeui + 'comment.svg'
combag[i]["icons"]["flag"] = tapeui+'flag.svg'
combag[i]["icons"]["flaged"] = tapeui+'flaged.svg'
//推送
this.bulky.push(combag[i])
};
this.bulkywait = false
this.from += 10
this.to += 10
});
},
filterText
注意,这仅仅是所有VUE变量在html中被局部地处理的方法中的一种应用场景。
可以直接filter变量,将所有数据高消耗变形放在浏览器部分,例如inteltime。
例子中,filterText是 Vue里的method,而comme.text是变量。
*注意,涉及输出HTML标签的,要放在v-html里当作变量输出。
<span class="text" v-html="filterText(comme.text)"></span>
filterText : function(val){
return val.replace(/\n/g,'<br/>')
},
Vue 方法
更新bulk的属性
直接修改属性,不需要Vue.set()而能够直接动态响应修改。
注意:不能新建一个不存在的属性为数组后再定义数组的内部结构。
update : function(bulkyid){
this.bulky[bulkyid]["xxx"]= ""
}
update : function(bulkyid){
var pickout = this.bulky[bulkyid]
pickout["content"]["citizen"]["name"] = "被点击了,来自PVAJP"
}
两种方式都可以,用PICKOUT变量,可以让代码结构变得简约。
兼容性介绍:电脑端在 SAFARI ,CHROME,EDGE,搜狗浏览器有效。手机端在 SAFARI ,CHROME,夸克浏览器,QQ浏览器,百度APP有效。有效面积广大。
清空bulky
this.bulky = []
删除某个bulk
this.bulky.splice(bulkyid,1)
增加一个bulk (ajax请求后在头部添加)
if(res.combag[key]){
this.bulky.unshift(res.combag[key])
}
定位 $refs 和 $nextTick
reftranslate 将index数字转化为更special的字符串名片,例如 1 变为 apple_1。
[0]是必须的,否则.focus()找不到对象。
this.$refs[this.reftranslate(index)][0].focus()
一般用来做input/textarea的聚焦。
如果需要v-if/v-show展示后聚焦,需要
this.$nextTick(() =>{
this.$refs[this.reftranslate(index)][0].focus()
})
JSON-PYTHON部分
Status 规范
每一条的bulk数据包将自行携带一些信息,其中包括status属性。
(*一般将主要DICT放在 content 内)
bulk 在Vue时候将自行判断Status信息,用来指示用户一些操作。而用户能否使用该操作见Vue-Ajax部分。
#Status 设计
status = {}
if request.session.get('pass_print'):
status["pass"] = 1
#Flagship
waiter_f = Flagship.objects.filter(aflags=request.session['citizen']['id'], bisflaged=x['belongsto'], what_id=x['id'], what_type=1)
status["flag"] = 1 if waiter_f else None
#Likeship
waiter_l = Likeship.objects.filter(alikes=request.session['citizen']['id'], bisliked=x['belongsto'], what_id=x['id'], what_type=1)
status["like"] = 1 if waiter_l else None
else:
status["pass"] = None
status["flag"] = None
status["like"] = None
pass
注意,注入status的地方是count的地方,所以对象是bulk。
organised[count] = {'status':status,'content':content,...}
<img @click="flagit(index,bulk.content.id)" class="visibleicon" :class="{'red':bulk.status.flag}" />
lazyfetch
一个PVAJP重要特征,惰性加载(有需要才加载,被动)。
lazyfetch是一个类似视图的py文件,但它只会返回JSON数据 count - based DICT。
里面的方法在实现上很独立(不套叠)。
#
def lazy(request):
load = json.loads(request.body.decode("utf-8"))
#
inf = .objects.filter()
count = 1
combag = {}
for i in inf:
i = model_to_dict(i)
tem_i =.objects.get(id=i["id"])
i.update(model_to_dict(tem_i))
combag[count] = i
count += 1
return JsonResponse({"combag":combag})
在urls.py里设定
from . import lazyfetch
urlpatterns = [
#lazy
path('lazycomme', lazyfetch.comme),
path('lazyreply', lazyfetch.reply),
]
JSON只能处理DICT数据,因此Python返回的数据格式必须是 model_to_dict 后的,且不能包含图片对象。 如下法则处理最佳。
summarized = {} summarized.update(model_to_dict(waiter)) summarized.update(model_to_dict(waitress)) #平庸化 summarized["avatar"] = {} summarized["avatar"]["url"] = waitress.avatar.url summarized["bgcover"] = {} summarized["bgcover"]["url"] = waitress.bgcover.url
静态URL的处理(在tools类里面),比如 href 和 src。
vars = Capitalvars() summarized["href"] = vars['GENERAL_CITIZEN_PAGE'] + str(waiter.citizen_id)
<!--例子 1 --> <a :href="bulk.content.citizen.href" class="link"></a> <img :src="bulk.content.citizen.avatar.url" />
需要让URL在Python上处理好,VUE只负责绑定,绑定的时候使用 :src 这样类型。
这样是方便不必每次在VUE里重复重写数据。
开发规范
整数规范
models.IntegerField() 分类工作
消息规范
0-comme
(subtype: 0-comment,1-reply)
1-follow
2-like
(subtype: 0-dyna,1-arti,2-comme,3-reply)
3-flag
(subtype: 0-dyna,1-arti)