-
前言
参照别人的效果图自己实现的过程,本想附上链接,但是来源很多,so pass。 -
效果
- 代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src='https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js'></script>
<title>小目标列表</title>
<style type='text/css'>
html{
font-size: 16px/1.6;
}
#goal-items{
min-width: 900px;
width: 80%;
margin: auto;
border: 2px solid #939393;
padding: 5px 20px 5px 20px;
font:1rem "Arial", "Microsoft YaHei", "黑体", "宋体", sans-serif;
box-sizing: border-box;
}
.input-goal{
line-height: 2;
font-size: 0.9rem;
width: 100%;
padding-left: 10px;
}
#goal-items{
font-size: 0.9rem;
}
#goal-items ul{
list-style: none;
padding: 0;
}
.item-out-div{
margin: 0;
padding: 0 8px 0 8px;
vertical-align: middle;
}
.item-out-div:hover{
border: 1px solid rgb(6, 104, 233);
}
.item-checkbox{
display: inline-block;
width: 8px;
height: 8px;
border: 2px solid #939393;
margin: auto;
margin-right: 10px;
}
.item-checkbox-checked{
border: 2px solid #1212ff;
background: #1212ff;
}
.item-input{
width: 90%;
line-height: 35px;
border: 0;
height: 35px;
box-sizing: border-box;
letter-spacing: 1;
}
.item-span{
display: inline-block;
width: 90%;
line-height: 35px;
border: 0;
height: 35px;
letter-spacing: 1;
}
.item-btn{
width: 40px;
border: 0;
background: transparent;
color: rgb(98, 48, 235);
outline: none;
visibility: hidden;
}
.item-out-div:hover .item-btn{
visibility: visible;
}
</style>
<script>
window.onload = function(){
Vue.component('goal-item', {
data(){
return {
checked: false
}
},
props: {
item: {
type: Object,
required: true,
}
},
template: `
<div>
<span
:class="{'item-checkbox': true, 'item-checkbox-checked': item.finished}"
@click='item.finished = !item.finished'
></span>
<input
type='text'
class="item-input"
ref='input'
:value='item.content'
@keyup.enter='changeInput($event.target.value, true)'
@keyup.esc='changeInput($event.target.value, false)'
@blur='changeInput($event.target.value, true)'
v-show='checked'
v-focus
/>
<span class="item-span" v-show='!checked' @click='changeCheck'>{{ item.content }}</span>
<button
class='item-btn'
@click='$emit("delete", item.id)'
>X</button>
</div>
`,
methods: {
changeInput(data, flag){
flag && data && (this.item.content = data);
this.checked = false;
},
changeCheck(){
this.checked = true;
// setTimeout(()=>{this.$refs.input.focus()}, 50)
}
},
directives: {
focus(el){
el.focus();
}
//focus: {bind:function(){}, update:function(){}}
//=focus:function(){}
//=focus(){}
}
})
var vm = new Vue({
el: '#goal-items',
data: {
indexGoal: 0,
radioCheck: 'all',
inputValue: '',
GoalItems: [
{
id: 0,
content: 'HTML5',
finished: false
},
{
id: 1,
content: 'CSS3',
finished: false
},
{
id: 2,
content: 'JavaScript',
finished: false
},
{
id: 3,
content: 'VUE',
finished: false
}
]
},
computed: {
allGoals(){
return this.GoalItems.length;
},
finishedGoals(){
return this.GoalItems.filter((goal)=>{
return goal.finished
}).length;
},
showGoals(){
if(this.radioCheck === 'all'){
return this.GoalItems;
}else if(this.radioCheck === 'finish'){
return this.GoalItems.filter(goal=>{
return goal.finished;
})
}else if(this.radioCheck === 'undone'){
return this.GoalItems.filter(goal=>{
return !goal.finished;
})
}else{
return []
}
}
},
methods: {
deleteItem(id){
this.GoalItems = this.GoalItems.filter((goal)=>{
return goal.id!==id;
})
},
addGoal(data){
data.trim() && this.GoalItems.push({
id: this.indexGoal++,
content: data,
finished: false
})
}
},
created(){
this.indexGoal = this.GoalItems.length;
}
})
}
</script>
</head>
<body>
<div id='goal-items'>
<h2>小目标列表</h2>
<h4>添加小目标</h4>
<input
class='input-goal'
type='text'
:value='inputValue'
placeholder="输入小目标后,按回车确认"
@keyup.enter='addGoal($event.target.value)'
>
<p>共有{{ allGoals }}个目标,已完成{{ finishedGoals }},还有{{ allGoals-finishedGoals }}条未完成</p>
<label><input type='radio' v-model:checked='radioCheck' value='all'>所有目标</label>
<label><input type='radio' v-model:checked='radioCheck' value='finish'>已完成目标</label>
<label><input type='radio' v-model:checked='radioCheck' value='undone'>未完成目标</label>
<ul>
<li
class='item-out-div'
is='goal-item'
v-for='item in showGoals'
:key='item.id'
:item='item'
@delete='deleteItem($event)'
></li>
</ul>
<p ></p>
</div>
</body>
</html>
- 复习的知识点
这里有部分修改: 就是input显示自动获得焦点
原先我是用setTimeout来实现的,当时也觉得不妥,没有更好的方法,后来看了人家的实现,是可以使用自定义指令的,自定义指令可以直接操作element
修改的截图:
代码修改了,原有的截图没有改。
- 总结
这里复习了几个知识点:
v-show 【我一开始真的没想到两个节点可以这样显示 我还在抠css class的display
v-model 【除了text textarea的input事件是value=Xevent.target.value 其他的都不简单。。
v-bind:class 【对象数组的绑定
vm.$refs.xx 【这里为了实现input聚焦或失焦focus()
计算属性有时候很重要!!
还有就是结构理解: 试过p span input各种 最后决定用的现在的标签 对 经验太少!
总体来说不难,为什么用了那么多的时间呢
1.组件结构的标签选择及样式浪费了很多时间(尤其是点击选项的时候显示为input --2h) --开写到结束: 4h
2.单选框用的时间稍久,因为自己在试图实现响应change的函数 为什么要实现这个呢 因为单选框改变要改变下面显示的项目 发现不能实现后 直接把项目遍历数组改成了计算属性 响应式改变 --2h
3. css抠的时间久了点
–下次再写什么东西都计好时,太浪费时间了!