“最难不过坚持”
本人承接扒站仿站,php网站维护,病毒查杀,网站编辑,网站改版,html制作
有需要网站维护,改版,病毒查杀,网站编辑,网站备案,html制作等相关的工作可以联系我。
本人有多年相关工作经验,也可提供免费咨询,交个朋友。
有需要探讨问题的朋友,也可以加我微信,共同探讨!
微信:15011482830 QQ:408917339
- https://jueru.net/
-
评 留言
- :weixiao:
-
评 留言
- :shuijiao: :weiqu: :zhenbang: :leng:
-
评 留言
- :yiwen: :yiwen: :yiwen: :yiwen:
-
评 EasySass: could not generate CSS file. See Output panel for details.
- 这个业务逻辑多少都有点奇怪了,阅读浏览次数增值在新闻详情页的控制器方法里setInc,这怎么还写进模型事件里了。如果非要用onAfterRead也可以,把新闻文章的内容单独分出来一个news_content表,然后把它和news做关联,然后给news_content表的onAfterRead事件做增值处理,这样点进新闻页内查询到文章内容时才会触发它。
-
评 TP6模型事件-查询后onAfterRead不好用
案例的效果如下
一、组件化编码流程:
(1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
(2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:
1).一个组件在用:放在组件自身即可。
2). 一些组件在用:放在他们共同的父组件上(状态提升)。
(3).实现交互:从绑定事件开始。
拆分好的页面结构如下:
1,App组件
<template>
<div id="app">
<TodoHeader/>
<TodoList :todos="todos"/>
<TodoFooter :todos="todos"/>
</div>
</template>
<script>
import pubsub from 'pubsub-js'
import TodoHeader from './components/TodoHeader.vue'
import TodoList from './components/TodoList.vue'
import TodoFooter from './components/TodoFooter.vue'
export default {
name: 'App',
components: {
TodoHeader,TodoList,TodoFooter
},
data(){
return{
// todos:[
// {id:'001',title:'吃饭',done:true},
// {id:'002',title:'睡觉',done:false},
// {id:'003',title:'打豆豆',done:false},
// ]
todos:JSON.parse(localStorage.getItem('todos')) || []
}
},
// 监视
watch:{
todos:{
deep:true, // 深度监视
handler(value){
localStorage.setItem('todos',JSON.stringify(value))
}
}
},
methods: {
// 添加任务
addTodo(_,obj){
this.todos.unshift(obj)
},
// 选中/取消
checkTodo(_,id){
this.todos.forEach((todo)=>{
if(todo.id === id) todo.done = !todo.done
})
},
// 删除
deleteTodo(_,id){
this.todos = this.todos.filter((todo)=>{
return todo.id != id
})
},
// 修改
updateTodo(_,data){
// console.log('updateTodo:',data.title);
this.todos.forEach((todo)=>{
if(todo.id == data.id) todo.title = data.title
})
},
// 清除已完成
clearAllTodo(){
this.todos = this.todos.filter((todo)=>{
return !todo.done
})
},
// 全选
checkAllTodo(_,done){
this.todos.forEach((todo)=>{
todo.done = done
})
}
},
// 挂载
mounted() {
// 消息订阅与发布-订阅
this.addTodoId = pubsub.subscribe('addTodo',this.addTodo)
this.checkTodoId = pubsub.subscribe('checkTodo',this.checkTodo)
this.deleteTodoId = pubsub.subscribe('deleteTodo',this.deleteTodo)
this.updateTodoId = pubsub.subscribe('updateTodo',this.updateTodo)
this.clearAllTodoId = pubsub.subscribe('clearAllTodo',this.clearAllTodo)
this.checkAllTodoId = pubsub.subscribe('checkAllTodo',this.checkAllTodo)
},
// 销毁前
beforeDestroy() {
pubsub.unsubscribe(this.addTodoId)
pubsub.unsubscribe(this.checkTodoId)
pubsub.unsubscribe(this.deleteTodoId)
pubsub.unsubscribe(this.updateTodoId)
pubsub.unsubscribe(this.clearAllTodoId)
pubsub.unsubscribe(this.checkAllTodoId)
},
}
</script>
<style>
</style>
2,TodoHeader组件
<template>
<div>
<input type="text" @keyup.enter="add">
</div>
</template>
<script>
import {nanoid} from 'nanoid'
import pubsub from 'pubsub-js'
export default {
name:'TodoHeader',
methods: {
add(e){
if(!e.target.value.trim()) return alert('输入不能为空')
const todoObj = {id:nanoid(),title:e.target.value,done:false}
// console.log(todoObj);
// 消息订阅与发布-发布
pubsub.publish('addTodo',todoObj)
e.target.value = ''
}
},
}
</script>
<style>
</style>
3,TodoList组件
<template>
<div>
<ul>
<TodoItem v-for="todo in todos" :key="todo.id" :todo="todo"/>
</ul>
</div>
</template>
<script>
import TodoItem from './TodoItem.vue'
export default {
name:'TodoList',
components:{
TodoItem
},
props:['todos']
}
</script>
<style>
</style>
4,TodoItem组件
<template>
<li>
<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)">
<span v-show="!todo.isEdit">{{todo.title}}</span>
<input type="text" v-show="todo.isEdit" :value="todo.title" @blur="handleBlur(todo,$event)" ref="inputTitle">
<button v-show="!todo.isEdit" @click="handleEdit(todo)">编辑</button>
<button @click="handleDelete(todo.id)">删除</button>
</li>
</template>
<script>
import pubsub from 'pubsub-js'
export default {
name:'TodoItem',
props:['todo'],
methods: {
// 选中/取消
handleCheck(id){
pubsub.publish('checkTodo',id)
},
// 删除
handleDelete(id){
pubsub.publish('deleteTodo',id)
},
// 编辑
handleEdit(todo){
// 判断是否保护isEdit属性
if(todo.hasOwnProperty('isEdit')){
todo.isEdit = true
}else{
this.$set(todo,'isEdit',true)
}
// 点击编辑按钮,输入框自动获得焦点
this.$nextTick(function(){
this.$refs.inputTitle.focus()
})
},
// 失去焦点,提交修改
handleBlur(todo,e){
// 编辑状态改为false
todo.isEdit = false
if(!e.target.value.trim()) return alert('输入不能为空')
// console.log(e.target.value);
pubsub.publish('updateTodo',{id:todo.id,title:e.target.value})
}
},
}
</script>
<style scoped>
button{
display: none;
}
li:hover{
background: #eee;
}
li:hover button{
display: inline;
}
</style>
5,TotoFooter组件
<template>
<div v-show="total">
<!-- 方式一 -->
<!-- <input type="checkbox" :checked="isAll" @change="checkAll"> -->
<!-- 方式二 -->
<input type="checkbox" v-model="isAll">
已完成{{doneTotal}} / 全部 {{total}}
<button @click="clearAll">清除已完成</button>
</div>
</template>
<script>
import pubsub from 'pubsub-js'
export default {
name:'TodoFooter',
props:['todos'],
computed:{
total(){
return this.todos.length
},
doneTotal(){
return this.todos.reduce((pre,todo)=>{
return pre + (todo.done ? 1 : 0)
},0)
},
isAll:{
get(){
return this.total === this.doneTotal
},
set(value){
pubsub.publish('checkAllTodo',value)
}
}
},
methods:{
clearAll(){
// 消息订阅与发布-发布
pubsub.publish('clearAllTodo')
},
checkAll(e){
pubsub.publish('checkAllTodo',e.target.checked)
}
}
}
</script>
<style>
</style>
其他:
1,nanoid生成唯一id
安装:
npm i nanoid
使用:
import { nanoid } from 'nanoid';
let id = nanoid()
2,pubsub-js消息订阅与发布
安装:
npm i pubsub-js
使用:
import PubSub from 'pubsub-js'
// 发布消息
PubSub.publish('msg', data)
// 订阅消息
PubSub.subscribe('msg', function(msg, data){})
3,本地存储
Window.sessionStorage--存储的内容会随着浏览器窗口关闭而消失
Window.localStorage --存储的内容,需要手动清除才会消失。
以上两种存储方式,它们的API是完全相同的。主要区别就在是否是会存储到本地。相关API如下:
☆添加:xxxxxStorage.setItem('key', 'value');
☆获取:xxxxxStorage.getItem('person');
☆删除:xxxxxStorage.removeItem('key');
☆清空:xxxxxStorage.clear()
在必要的时候搭配JSON.stringify和JSON.parse方法使用。
注意:xxxxxStorage.getItem(xxx) 如果xxx对应的value获取不到,那么getItem的返回值是null。JSON.parse(null)的结果依然是null。