vue@2.6.14小目标列表
阅读目录
运行效果
源码
html 代码中需要插入css 代码,在最下方需插入vue 代码即可运行。
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--插入css-->
</head>
<body>
<div id="app" class="main">
<h2>小目标列表</h2>
<div class="list">
<h3>添加小目标</h3>
<input type="text" class="text-keyword" placeholder="输入小目标后,按回车确认" @keyup.13='addList' v-model="addText"/>
<!--如果noend等于0,就是全部完成了就显示‘全部完成了’,如果没有就是显示已完成多少条(prolist.length-noend)和未完成多少条(noend)-->
<p>共有{{prolist.length}}个目标,{{noend==0?"全部完成了":'已完成'+(prolist.length-noend)+',还有'+noend+'条未完成'}}</p>
<p>
<input type="radio" name="chooseType" checked="true" @click='chooseList(1)'/><label>所有目标</label>
<input type="radio" name="chooseType" @click='chooseList(2)'/><label>已完成目标</label>
<input type="radio" name="chooseType" @click='chooseList(3)'/><label>未完成目标</label>
</p>
</div>
<ul>
<li class="li1" v-for="(list,index) in newList" :class="{'eidting':curIndex===index}">
<div>
<span class="status-span" @click="changeType(index)" :class="{'status-end':list.status}"></span>
<span @dblclick="curIndex=index">{{list.name}}</span>
<span class="close" @click='delectList(list)'>X</span>
</div>
<input type="text" class="text2" v-model='list.name' @keyup.esc='cancelEdit(list)' @blur='edited' @focus='editBefore(list.name)' @keyup.enter='edited' v-focus/>
</li>
</ul>
</div>
</body>
<!--插入js-->
</html>
CSS
<style>
body
{
font-family:微软雅黑;
font-size:14px;
}
input
{
font-size:14px;
}
body,ul,div,html
{
margin:0;
padding:0;
}
.main
{
width:800px;
margin:0 auto;
}
li
{
list-style-type:none;
line-height:40px;
position:relative;
border:1px solid transparent;
padding:0 20px;
}
li .status-span
{
display:block;
width:10px;
height:10px;
background:#ccc;
float:left;
margin:14px 10px 0 0;
}
li .status-span.status-end
{
background:#09f;
}
li .close
{
position:absolute;
color:red;
font-size:20px;
line-height:40px;
height:40px;
right:20px;
cursor:pointer;
display:none;
top:0;
}
li:hover
{
border:1px solid #09f;
}
.text-keyword
{
box-sizing:border-box;
width:100%;
height:40px;
padding-left:10px;
outline:none;
}
.hidden,li.eidting div
{
display:none;
}
li:hover .close,li div,li.eidting .text2
{
display:block;
}
li .text2,li .text-keyword
{
height:40px;
padding-left:10px;
box-sizing:border-box;
margin-left:10px;
width:80%;
display:none;
}
</style>
JS
<script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
<script type="text/javascript">
new Vue({
el: "#app",
data: {
addText:'',
//name-名称,status-完成状态
prolist:[
{name:"HTML5",status:false},
{name:"CSS3",status:false},
{name:"vue",status:false},
{name:"react",status:false}
],
newList:[],
curIndex:'',
beforeEditText:"",
curType:0
},
computed:{
//计算属性,返回未完成目标的条数,就是数组里面status=false的条数
noend:function(){
return this.prolist.filter(function(item){
return !item.status
}).length;
}
},
methods:{
addList(){
//添加进来默认status=false,就是未完成状态
this.prolist.push({
name:this.addText,
status:false
});
//添加后,清空addText
this.addText="";
},
chooseList(type){
//type=1时,选择所有目标
//type=2时,选择所有已完成目标
//type=3时,选择所有未完成目标
this.curType=type;
switch(type){
case 1:this.newList=this.prolist;break;
case 2:this.newList=this.prolist.filter(function(item){return item.status});break;
case 3:this.newList=this.prolist.filter(function(item){return !item.status});break;
}
},
/*改变单条数据的完成状态*/
changeType(index){
this.newList[index].status=!this.newList[index].status;
//更新数据
this.chooseList(this.curType);
},
delectList(list){
var index=this.prolist.indexOf(list);
//根据索引,删除数组某一项
this.prolist.splice(index,1);
//更新newList newList可能经过this.prolist.filter()赋值,这样的话,删除了prolist不会影响到newList 那么就要手动更新newList
//this.newList=this.prolist;
this.chooseList(this.curType);
},
//修改前
editBefore(name){
//先记录当前项(比如这一项,{name:"HTML5",status:false})
//beforeEditText="HTML5"
this.beforeEditText=name;
},
//修改完成后
edited(){
//修改完了,设置curIndex="",这样输入框就隐藏,其它元素就会显示。因为在li元素 写了::class="{'eidting':curIndex===index}" 当curIndex不等于index时,eidting类名就清除了!
//输入框利用v-model绑定了当前项(比如这一项,{name:"HTML5",status:false})的name,当在输入框编辑的时候,比如改成‘HTML’,实际上当前项的name已经变成了‘HTML’,所以,这一步只是清除eidting类名,隐藏输入框而已
//还有一个要注意的就是虽然li遍历的是newList,比如改了newList的这一项({name:"HTML5",status:false}),比如改成这样({name:"HTML",status:true})。实际上prolist的这一项({name:"HTML5",status:false}),也会被改成({name:"HTML",status:true})。因为这里是一个对象,而且公用一个堆栈!修改其中一个,另一个会被影响到
this.curIndex="";
},
//取消修改
cancelEdit(val){
//上面说了输入框利用v-model绑定了当前项(比如这一项,{name:"HTML5",status:false})的name,当在输入框编辑的时候,比如改成‘HTML’,实际上当前项的name已经变成了‘HTML’,所以,这一步就是把之前保存的beforeEditText赋值给当前项的name属性,起到一个恢复原来值得作用!
val.name=this.beforeEditText;
this.curIndex="";
}
},
mounted(){
//初始化,把prolist赋值给newList。默认显示所有目标
this.newList=this.prolist;
},
directives:{
"focus":{
update(el){
el.focus();
}
}
}
});
</script>
原理分析和实现
首先,还是先把布局写好,和引入vue,准备vue实例,这个不多说,代码如下。
步骤 1 布局和引入 vue
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
body {
font-family: "微软雅黑";
font-size: 14px;
}
input {
font-size: 14px;
}
body,
ul,
div,
html {
padding: 0;
margin: 0;
}
.hidden {
display: none;
}
.main {
width: 800px;
margin: 0 auto;
}
li {
list-style-type: none;
line-height: 40px;
position: relative;
border: 1px solid transparent;
padding: 0 20px;
}
li .type-span {
display: block;
width: 10px;
height: 10px;
background: #ccc;
margin: 14px 10px 0 0;
float: left;
}
li .close {
position: absolute;
color: #f00;
font-size: 20px;
line-height: 40px;
height: 40px;
right: 20px;
cursor: pointer;
display: none;
top: 0;
}
li:hover {
border: 1px solid #09f;
}
li:hover .close {
display: block;
}
li .text-keyword {
height: 40px;
padding-left: 10px;
box-sizing: border-box;
margin-left: 10px;
width: 80%;
display: none;
}
.text-keyword {
box-sizing: border-box;
width: 100%;
height: 40px;
padding-left: 10px;
outline: none;
}
</style>
</head>
<body>
<div id="app" class="main">
<h2>小目标列表</h2>
<div class="list">
<h3>添加小目标</h3>
<input type="text" class="text-keyword" placeholder="输入小目标后,按回车确认" />
<p>共有N个目标</p>
<p>
<input type="radio" name="chooseType" checked="true" /><label>所有目标</label>
<input type="radio" name="chooseType" /><label>已完成目标</label>
<input type="radio" name="chooseType" /><label>未完成目标</label>
</p>
</div>
<ul>
<li class="li1">
<div>
<span class="type-span"></span>
<span>html5</span>
<span class="close">X</span>
</div>
</li>
<li class="li1">
<div>
<span class="type-span"></span>
<span>css3</span>
<span class="close">X</span>
</div>
</li>
</ul>
</div>
</body>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
<script type="text/javascript">
new Vue({
el: "#app",
data: {},
computed: {},
methods: {}
});
</script>
</html>
布局有了,相当于一个骨架就有了,下面实现功能,一个一个来。
步骤 2 输入框回车要添加纪录
输入并回车,多一条记录,下面的记录文字也会改变。
首先,大的输入框回车要添加纪录,那么输入框必须绑定一个值和一个添加纪录的方法。
然后,下面的记录也要改变,所以,下面的记录也要帮一个值,因为这个记录可能会有多个,这个值就是一个数组,也可以看到,记录除了名称,还有记录是否完成的状态,所以,绑定记录的这个值肯定是一个对象数组!
为了着重表示我修改了什么地方,代码我现在只贴出修改的部分,大家对着上面的布局,就很容易知道我改的是什么地方了!
<!--利用v-model把addText绑定到input-->
<input type="text"
class="text-keyword"
placeholder="输入小目标后,按回车确认"
@keyup.13='addList' v-model="addText"/>
<p>共有{{prolist.length}}个目标</p>
<!--v-for遍历prolist-->
<li class="li1" v-for="list in prolist">
<div>
<span class="type-span"></span>
<span>{{list.name}}</span>
<span class="close">X</span>
</div>
</li>
new Vue({
el: "#app",
data: {
addText:'',
//name-名称,status-完成状态
prolist:[
{name:"HTML5",status:false},
{name:"CSS3",status:false},
{name:"vue",status:false},
{name:"react",status:false}
]
},
computed:{
},
methods:{
addList(){
//添加进来默认status=false,就是未完成状态
this.prolist.push({
name:this.addText,
status:false
});
//添加后,清空addText
this.addText="";
}
}
});
测试一下,没问题
步骤 3 点击切换,下面记录会改变
看到三个选项,也很简单,无非就是三个选择,一个是所有的目标,一个是所有已经完成的目标,一个是所有没完成的目标。
首先,新建一个新的变量(newList),储存 prolist。遍历的时候不再遍历 prolist,而是遍历 newList。改变也是改变 newList。
然后选择所有目标的时候,显示全部 prolist,把 prolist 赋值给 newList。
然后选择所有已经完成目标的时候,只显示 prolist 中,status 为 true 的目标,把 prolist中,status 为 true 的项赋值给 newList,最后.选择所有未完成目标的时候,只显示 status 为 false 的目标,把 prolist 中,status 为 false 的项赋值给 newList。
<ul>
<li class="li1" v-for="list in newList">
<div>
<span class="status-span"></span>
<span>{{list.name}}</span>
<span class="close" @click='delectList(index)'>X</span>
</div>
</li>
</ul>
new Vue({
el: "#app",
data: {
addText:'',
//name-名称,status-完成状态
prolist:[
{name:"HTML5",status:false},
{name:"CSS3",status:false},
{name:"vue",status:false},
{name:"react",status:false}
],
newList:[]
},
computed:{
noend:function(){
return this.prolist.filter(function(item){
return !item.status
}).length;
}
},
methods:{
addList(){
//添加进来默认status=false,就是未完成状态
this.prolist.push({
name:this.addText,
status:false
});
//添加后,清空addText
this.addText="";
},
chooseList(type){
//type=1时,选择所有目标
//type=2时,选择所有已完成目标
//type=3时,选择所有未完成目标
switch(type){
case 1:this.newList=this.prolist;break;
case 2:this.newList=this.prolist.filter(function(item){return item.status});break;
case 3:this.newList=this.prolist.filter(function(item){return !item.status});break;
}
},
delectList(index){
//根据索引,删除数组某一项
this.prolist.splice(index,1);
//更新newList newList可能经过this.prolist.filter()赋值,这样的话,删除了prolist不会影响到newList 那么就要手动更新newList
this.newList=this.prolist;
},
},
mounted(){
//初始化,把prolist赋值给newList。默认显示所有目标
this.newList=this.prolist;
}
});
运行结果
步骤 4 红色关闭标识,点击会删除该条记录
红色关闭标识,点击会删除该记录。前面按钮点击会切换该记录完成状态,颜色也改变,记录文字也跟着改变。
首先点击红色关闭标识,点击会删除该记录。
这个应该没什么问题,就是删除 prolist 的一条记录!
然后前面按钮点击会切换该记录完成状态。
这个也没什么,就是改变 prolist 的一条记录的 status 字段!
最后记录文字的改变,就是记录 prolist 中 status 为 false 的有多少条,prolist 中 status 为true 的有多少条而已。
<!--
如果 noend 等于0,就是全部完成了就显示‘全部完成了’,
如果没有就是显示已完成多少条(prolist.length-noend)和未完成多少条(noend)-->
<p>
共有{{prolist.length}}个目标,
{{noend==0?"全部完成了":'已完成'+(prolist.length-noend)+',
还有'+noend+'条未完成'}}
</p>
<ul>
<li class="li1" v-for="(list,index) in newList">
<div>
<span class="status-span"
@click="list.status=!list.status"
:class="{'status-end':list.status}">
</span>
<span>{{list.name}}</span>
<span class="close" @click='delectList(index)'>X</span>
</div>
</li>
</ul>
new Vue({
el: "#app",
data: {
addText:'',
//name-名称,status-完成状态
prolist:[
{name:"HTML5",status:false},
{name:"CSS3",status:false},
{name:"vue",status:false},
{name:"react",status:false}
],
newList:[]
},
computed:{
//计算属性,返回未完成目标的条数,就是数组里面status=false的条数
noend:function(){
return this.prolist.filter(function(item){
return !item.status
}).length;
}
},
methods:{
addList(){
//添加进来默认status=false,就是未完成状态
this.prolist.push({
name:this.addText,
status:false
});
//添加后,清空addText
this.addText="";
},
chooseList(type){
switch(type){
case 1:this.newList=this.prolist;break;
case 2:this.newList=this.prolist.filter(function(item){return item.status});break;
case 3:this.newList=this.prolist.filter(function(item){return !item.status});break;
}
},
delectList(index){
//根据索引,删除数组某一项
this.prolist.splice(index,1);
//更新newList newList可能经过this.prolist.filter()赋值,这样的话,删除了prolist不会影响到newList 那么就要手动更新newList
this.newList=this.prolist;
},
},
mounted(){
this.newList=this.prolist;
}
});
运行结果
步骤 5 文字双击会出现输入框,可输入文字
文字双击会出现输入框,可输入文字,如果回车或者失去焦点,就改变文字,如果按下ESC就恢复原来的文字。
首先.双击出现输入框,就是双击文字后,给当前的li设置一个类名(‘eidting’),然后写好样式。当li出现这个类名的时候,就出现输入框,并且隐藏其它内容。
然后回车或者失去焦点,就改变文字这个只需要操作一个,就是把类名(‘eidting’)清除掉。然后输入框就会隐藏,其它内容显示!
最后.按下ESC就恢复原来的文字,就是出现输入框的时候,用一个变量(‘beforeEditText’)先保存当前的内容,然后按下了ESC,就把变量(‘beforeEditText’)赋值给当前操作的值!
<ul>
<li class="li1"
v-for="(list,index) in newList"
:class="{'eidting':curIndex===index}">
<div>
<span class="status-span" @click="list.status=!list.status" :class="{'status-end':list.status}"></span>
<span @dblclick="curIndex=index">{{list.name}}</span>
<span class="close" @click='delectList(index)'>X</span>
</div>
<input type="text"
class="text2"
v-model='list.name'
@keyup.esc='cancelEdit(list)'
@blur='edited'
@focus='editBefore(list.name)'
@keyup.enter='edited'/>
</li>
</ul>
li div{display: block;}
li.eidting div{display: none;}
li .text2{height: 40px;padding-left: 10px;box-sizing: border-box;margin-left: 10px;width: 80%;display: none;}
li.eidting .text2{display: block;}
methods:{
addList(){
//添加进来默认status=false,就是未完成状态
this.prolist.push({
name:this.addText,
status:false
});
//添加后,清空addText
this.addText="";
},
chooseList(type){
//type=1时,选择所有目标
//type=2时,选择所有已完成目标
//type=3时,选择所有未完成目标
switch(type){
case 1:this.newList=this.prolist;break;
case 2:this.newList=this.prolist.filter(function(item){return item.status});break;
case 3:this.newList=this.prolist.filter(function(item){return !item.status});break;
}
},
delectList(index){
//根据索引,删除数组某一项
this.prolist.splice(index,1);
//更新newList newList可能经过this.prolist.filter()赋值,这样的话,删除了prolist不会影响到newList 那么就要手动更新newList
this.newList=this.prolist;
},
//修改前
editBefore(name){
//先记录当前项(比如这一项,{name:"HTML5",status:false})
//beforeEditText="HTML5"
this.beforeEditText=name;
},
//修改完成后
edited(){
//修改完了,设置curIndex="",这样输入框就隐藏,其它元素就会显示。因为在li元素 写了::class="{'eidting':curIndex===index}" 当curIndex不等于index时,eidting类名就清除了!
//输入框利用v-model绑定了当前项(比如这一项,{name:"HTML5",status:false})的name,当在输入框编辑的时候,比如改成‘HTML’,实际上当前项的name已经变成了‘HTML’,所以,这一步只是清除eidting类名,隐藏输入框而已
//还有一个要注意的就是虽然li遍历的是newList,比如改了newList的这一项({name:"HTML5",status:false}),比如改成这样({name:"HTML",status:true})。实际上prolist的这一项({name:"HTML5",status:false}),也会被改成({name:"HTML",status:true})。因为这里是一个对象,而且公用一个堆栈!修改其中一个,另一个会被影响到
this.curIndex="";
},
//取消修改
cancelEdit(val){
//上面说了输入框利用v-model绑定了当前项(比如这一项,{name:"HTML5",status:false})的name,当在输入框编辑的时候,比如改成‘HTML’,实际上当前项的name已经变成了‘HTML’,所以,这一步就是把之前保存的beforeEditText赋值给当前项的name属性,起到一个恢复原来值得作用!
val.name=this.beforeEditText;
this.curIndex="";
}
},
运行结果
还有一个小细节,大家可能注意到了,就是双击文字,出来输入框的时候,还要自己手动点击一下,才能获得焦点,我们想双击了,输入框出来的时候,自动获取焦点,怎么办?
自定义指令就行了!
computed:{...},
methods:{...},
mounted(){...},
directives:{
"focus":{
update(el){
el.focus();
}
}
}
<input type="text"
class="text2"
v-model='list.name'
@keyup.esc='cancelEdit(list)'
@blur='edited'
@focus='editBefore(list.name)'
@keyup.enter='edited' v-focus/>
相关文章
- (尚011)Vue事件处理
- (尚010)Vue列表的搜素和排序
- vue - webpack.dev.conf.js for CopyWebpackPlugin
- Vue - 搜索关键字标红高亮(用户输入关键词搜索后,在搜索结果的列表标题上匹配并标红加粗)怎么使内容文本标红高亮的最详细教程,Nuxt.js uni-app 也适用,搜索功能及搜索结果关键字高亮源码
- Vue - 列表分页懒加载 / 点击 “加载更多“ 按钮请求接口数据(如何实现类似用户手动点击 “查看更多“ ,然后请求分页懒加载数据填充)可适用于 Nuxt.js 、uni-app 等 Vue.js
- Vue - cli3 脚手架搭建项目步骤流程(windows)
- 初步整合vue-element-admin和GitDataV两个Vue开源框架方案实现大数据可视化
- Vue——详解MVVM模型在vue中的使用
- 一文带你理解vue创建一个后台管理系统流程(Vue+Element)
- Vue Hook Event 解读
- 超美观的 Vue+Element 开源后台管理 UI
- 【面试Vue全家桶】vue前端交互模式-es7的语法结构?async/await
- vue 调用接口配置
- Vue项目导入excel表,自动下载导入失败数据的excel表(使用ElementUI upload组件,自定义导入excel表)
- VUE-011-通过 v-if 和 v-for 实现特定值的列表循环匹配,并显示满足匹配条件的值
- vue学习笔记八:Jquery VS Vue之全局属性对照
- vue渲染列表时报错Avoid using non-primitive value as key, use string/number value instead.
- 使用vue-cli3搭建一个项目!!!
- Vue-cli 4在vue.config.js中配置别名
- Vue 之 插件 轮播组件 vue-awesome-swiper 的简单使用整理
- Vue学习第27天——路由vue-router的详解及案例练习
- Vue开发实例(17)之实现用户列表
- vue 遍历两个数组 拼接字符串
- vue a标签使用@click
- 浅谈vue中插件的使用方法Vue.use(xxx),原理及实现
- Vue列表渲染(v-for的使用)
- [Vue-Treeselect Warning] Are you meant to dynamically load options? You need to use "loadOptions" prop.
- vue 定时器:setInterval和setTimeout使用实例及区别