前端主流框架vue学习笔记第二篇


Posted in Javascript onJuly 26, 2017

接上篇,在本篇中,我们将要实现如下,功能,编辑和查询,我们当前的todolist程序,和线上其它的demo程序不同,我们会对其进行增删改查的基本操作,之后进行进一步的完善,按照常规的系统使用经验,一般我们新增和编辑都是在模态框中处理,这里我们不会去构建复杂的模态框,只用一个简单的div层来代替,后期接下来的文章中我们会重复造轮子,构建我们自己的轻量级框架(UI库)。

首先,我们对我们的页面结构进行一下简单的调整,加入bootstrap只是为了让页面不那么赤裸裸,对其它不会有任何影响

<!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">
 <title>demo1</title>
 <script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script>
 <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet">

</head>

<body class="container">
 <div id="app" class='row'>
 <div class="col-md-6">
  <table class="table table-bordered">
  <tr>
   <th>title</th>
   <th>desc</th>
   <th></th>
  </tr>
  <tr v-for="(todoItem,index) in todolist">
   <td>{{todoItem.title}}</td>
   <td>{{todoItem.desc}}</td>
   <td><input type="button" value="remove" @click="remove(index)" class="btn btn-danger" /></td>
  </tr>
  </table>
 </div>
 <div class="col-md-6">

  <div class="form-inline">
  <label for="title" class="control-label col-md-4">title:</label>
  <input type="text" v-model="title" class="form-control col-md-8">
  </div>
  <div class="form-inline">
  <label for="desc" class="control-label col-md-4">desc</label>
  <input type="text" v-model="desc" class="form-control col-md-8">
  </div>
  <div class="form-inline">
  <input type="button" value="OK" v-on:click="addItem()" class="btn btn-primary offset-md-10" />

  </div>

 </div>


 </div>
 <script>
 var TodoItem = function (title, desc) {
  this.title = title;
  this.desc = desc;
 }
 new Vue({
  el: '#app',
  data: {
  todolist: [],
  title: '',
  desc: ''
  },
  methods: {
  addItem: function () {
   this.todolist.push(new TodoItem(this.title, this.desc))

   this.title = this.desc = '';

  },
  remove: function (index) {
   this.todolist.splice(index, 1);
  }

  }
 })
 </script>
</body>

</html>

js没有任何变化,只是引入了bootstrap4之后,对html结构进行了微调整,由于我们需要增加编辑操作,我们把增加编辑操作归纳为以下几个步骤:

1、增加编辑按钮;

2、点击编辑按钮绑定所对应todoitem到表单进行编辑

3、点击表单中OK按钮,对编辑结果进行应用。

注意:这里需要区分,在点击OK按钮时,进行的是新增操作还是编辑操作,我们对我们数据结构加入自增ID来标示,如果编辑项目有ID,则为保存编辑操作,如果不存在ID则为新增保存操作,对我们的数据结构进行以下微调,由于新增了ID项目,那么在data属性中也要增加ID属性,这样每次新增属性都要直接修改data属性,这就是变化点,下面我们对变化点进行简单封装,修改代码如下:

data: {
  todolist: [],
  todoItem:{
   id:'',
   title:'',
   desc:''
  }
  },

另外我们需要实现自增ID,这里采用最直接的方式,全局ID,使其自增即可,对TodoItem进行简单的闭包处理:

var TodoItem = (function () {
  var id = 1;
  return function (title, desc) {
  this.title = title;
  this.desc = desc;

  this.id = id++;
  }
 })();

为了适应新数据结构的变化,则其它修改部分整体贴出来,变化部分见黄色:

<!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">
 <title>demo1</title>
 <script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script>
 <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet">

</head>

<body class="container">
 <div id="app" class='row'>
 <div class="col-md-6">
  <table class="table table-bordered">
  <tr>
   <th></th>
   <th>title</th>
   <th>desc</th>
   <th></th>
  </tr>
  <tr v-for="(todoItem,index) in todolist">
   <th>{{todoItem.id}}</th>
   <td>{{todoItem.title}}</td>
   <td>{{todoItem.desc}}</td>
   <td><input type="button" value="remove" @click="remove(index)" class="btn btn-danger" /></td>
  </tr>
  </table>
 </div>
 <div class="col-md-6">

  <div class="form-inline">
  <label for="title" class="control-label col-md-4">title:</label>
  <input type="hidden" v-bind:value="todoItem.id" />
  <input type="text" v-model="todoItem.title" class="form-control col-md-8">
  </div>
  <div class="form-inline">
  <label for="desc" class="control-label col-md-4">desc</label>
  <input type="text" v-model="todoItem.desc" class="form-control col-md-8">
  </div>
  <div class="form-inline">
  <input type="button" value="OK" v-on:click="addItem()" class="btn btn-primary offset-md-10" />

  </div>

 </div>


 </div>
 <script>
 var TodoItem = (function () {
  var id = 1;
  return function (title, desc) {
  this.title = title;
  this.desc = desc;

  this.id = id++;
  }
 })();
 new Vue({
  el: '#app',
  data: {
  todolist: [],
  todoItem: {
   id: '',
   title: '',
   desc: ''
  }
  },
  methods: {
  addItem: function () {
   // this.todolist.push(new TodoItem(this.title, this.desc))
   this.todolist.push(
   new TodoItem(
    this.todoItem.title,
    this.todoItem.desc
   )
   );

   this.todoItem={};

  },
  remove: function (index) {
   this.todolist.splice(index, 1);
  }

  }
 })
 </script>
</body>

</html>

刷新页面,测试效果如下:

前端主流框架vue学习笔记第二篇

自增ID已经完成,那么添加编辑时绑定,按照上面的步骤,先添加编辑按钮,在删除按钮后添加编辑按钮,并在methods对象中增加对应的回调函数,对edit操作进行响应,函数中主要实现对todoItem对象进行绑定操作,具体代码修改如下:

<table class="table table-bordered">
  <tr>
   <th></th>
   <th>title</th>
   <th>desc</th>
   <th></th>
  </tr>
  <tr v-for="(todoItem,index) in todolist">
   <th>{{todoItem.id}}</th>
   <td>{{todoItem.title}}</td>
   <td>{{todoItem.desc}}</td>
   <td>
   <input type="button" value="remove" @click="remove(index)" class="btn btn-danger" />
   <input type="button" value="edit" @click="edit(todoItem.id)" class="btn btn-info" />
   </td>
  </tr>
  </table>
methods: {
    edit: function (id) {
     //找到id值等于所传参数的todoitem
     var obj = this.todolist.filter(v => v.id === id)[0];
     //对数据进行绑定,则数据会响应到表单上
     this.todoItem = obj;
    },
   ...省略其它
}

这样有没有问题呢?我们运行看一下效果:

前端主流框架vue学习笔记第二篇

从运行结果上看,我们点击edit操作,的确完成了绑定,但是在我们修改编辑,还没有点击OK按钮的情况下,表单中的变化已经提现到了列表中,这就不符合正常逻辑了,为什么会有这样的情况呢,原因就在于this.todoItem=obj;这句代码就是所谓的引用赋值,所以todoitem和obj指向的是同一个地址,则对this.todoItem的修改,会直接反应到obj上,也就是todoList中的这个元素上,所以在列表中会直接提现出来,避免这种情况的发生的方法,只要避免饮用赋值即可,所以对上述代码进行如下修改:

//找到id值等于所传参数的todoitem
   var obj = this.todolist.filter(v => v.id === id)[0];
   //对数据进行绑定,则数据会响应到表单上
   this.todoItem = {
   id:obj.id,
   title:obj.title,
   desc:obj.desc
   };

刷新运行,发生程序按照预期运行了,接下来,增加更新保存操作,修改OK按钮的事件绑定方式为save,并通过id判断新增还是修改操作:

<div class="col-md-6">

  <div class="form-inline">
  <label for="title" class="control-label col-md-4">title:</label>
  <input type="hidden" v-bind:value="todoItem.id" />
  <input type="text" v-model="todoItem.title" class="form-control col-md-8">
  </div>
  <div class="form-inline">
  <label for="desc" class="control-label col-md-4">desc</label>
  <input type="text" v-model="todoItem.desc" class="form-control col-md-8">
  </div>
  <div class="form-inline">
  <input type="button" value="OK" v-on:click="save()" class="btn btn-primary offset-md-10" />
  </div>
 </div>
methods: {
  edit: function (id) {
   //找到id值等于所传参数的todoitem
   var obj = this.todolist.filter(v => v.id === id)[0];
   //对数据进行绑定,则数据会响应到表单上
   this.todoItem = {
   id: obj.id,
   title: obj.title,
   desc: obj.desc
   };
  },
  save: function () {
   if (this.todoItem.id) {
   //编辑保存
   var obj = this.todolist.filter(v => v.id === this.todoItem.id)[0];
   obj.title = this.todoItem.title;
   obj.desc = this.todoItem.desc;

   } else {
   //新增保存
   this.todolist.push(
    new TodoItem(
    this.todoItem.title,
    this.todoItem.desc
    )
   );
   }
   //重置表单 这部分笔误,在实际代码中已修改,但是贴上来的代码没有做修改,具体见最下面代码,错误原因见下方回复
   this.todoItem = {};
  },
  
  remove: function (index) {
   this.todolist.splice(index, 1);
  }

  }

代码比较简单,这里就不再赘述,可以看一下运行效果:

前端主流框架vue学习笔记第二篇

为了逼格更高一点,这里我再介绍一个指令,其实上面已经使用了,v-bind ,这个指令和v-on是类似的,两者的区别在于后面的参数不同,一般v-bind用来传递属性参数,一般使用缩写形式:attr,可以绑定自定义属性,上面代码中我们对Id值的绑定已经使用了v-bind:value="todoItem.id",这里相当于angular中ng-bind。基于对v-bind的了解,我们可以推理,给v-bind添加disable的属性,使OK按钮只有再title不为空的前提下再可用。

<div class="form-inline">
  <input type="button" value="OK" v-on:click="save()" class="btn btn-primary offset-md-10" :disabled='!todoItem.title'/>
  </div>

刷新运行:

前端主流框架vue学习笔记第二篇

上面代码能很好的运行,但是现在如果我需要修改一下验证规则,在title和desc都不为空的情况下,才使用OK按钮可用,如何做?你当然会说,很简单,直接加入一个&&条件不就行了,但是问题在于,现在我的模型比较小,属性比较少,如果我存在一个大量属性的对象,做类似的验证,这样来修改代码就是一个坑了,说到这里,其实已经可以想到,既然验证规则再变,那么可以考虑作为一个变化点封装起来,最直观的方式,是封装为一个方法,但是vue提供了更好的方式:computed,计算属性,这个计算属性应该是来自于knockout的概念,有兴趣的可以看一下knockout中计算属性,修改代码如下:

new Vue({
  el: '#app',
  data: {
  todolist: [],
  todoItem: {
   id: '',
   title: '',
   desc: ''
  }
  },
  computed:{
  canSave:function(){
   return !this.todoItem.title || !this.todoItem.desc;
  }
  },
  ...省略其它
  }
 })

可以看到computed属性是以方法的方式来定义的,这里是最简单方式,只读的方式,当然还可以通过get set方式进行读写控制,我们后期的代码中可能会见到,如果捉急,可以去查看官方文档。在computed使用的时候,和方法调用截然不同,而是和data属性中代理的模式一样,如果你使用过knockout,那么你对这种用法就见怪不怪了,html部分修改如下:

<div class="form-inline">
  <input type="button" value="OK" v-on:click="save()" class="btn btn-primary offset-md-10" :disabled='canSave'/>
  </div>

刷新页面,运行效果如图:

前端主流框架vue学习笔记第二篇

ok,编辑这部分内容就到这里吧,在没有后端接口的前提下,保存操作都是模拟的,接下来对我们的查询进行一下简单的介绍,这里查询,由于没有后端接口,咱们只做最简单的演示,对代码做如下处理:

1、增加查询输入框,keyword,添加查询按钮

2、点击查询操作,预期结果:根据输入的查询关键字,过滤列表

按照上面思路对我们代码进行修改:

<div class="row toolbar">
 <div class="col-md-8">
  keyword:
  <input type="text" v-model="keyword" />
  <input type="button" @click="query()" value="search" />
 </div>
 </div>

data中增加keyword属性,以实现对输入框的绑定,在methods中添加query方法:

//全局变量,用来缓存所有数据
 var list = [];
 data: {
  todolist: [],
  todoItem: {
   id: '',
   title: '',
   desc: ''
  },
  keyword:''
  },
query: function () {
   //过滤title中不包含keyword的数据
   //这里必须通过list全局变量过滤,而不能通过this.todolist,因为需要给this.todolist赋值,赋值后无法还原原来的列表。
   this.todolist = list.filter(v => v.title.indexOf(this.keyword) !== -1);
  }

刷新页面运行效果如图:

前端主流框架vue学习笔记第二篇

代码部分注释中已经写的很清楚了,有疑问可提价comment。本章就到这里,文章有点水,在(三)中会加入添加服务端支持,并使用axios和服务端rest接口进行交互敬请期待,准备睡觉。

<!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">
 <title>demo1</title>
 <script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script>
 <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet">

</head>

<body class="container">
 <div id="app">
 <div class="row toolbar">
  <div class="col-md-8">
  keyword:
  <input type="text" v-model="keyword" />
  <input type="button" @click="query()" value="search" />
  </div>
 </div>
 <div class='row'>

  <div class="col-md-6">
  <table class="table table-bordered">
   <tr>
   <th></th>
   <th>title</th>
   <th>desc</th>
   <th></th>
   </tr>
   <tr v-for="(todoItem,index) in todolist">
   <th>{{todoItem.id}}</th>
   <td>{{todoItem.title}}</td>
   <td>{{todoItem.desc}}</td>
   <td>
    <input type="button" value="remove" @click="remove(index)" class="btn btn-danger" />
    <input type="button" value="edit" @click="edit(todoItem.id)" class="btn btn-info" />
   </td>
   </tr>
  </table>
  </div>
  <div class="col-md-6">

  <div class="form-inline">
   <label for="title" class="control-label col-md-4">title:</label>
   <input type="hidden" v-bind:value="todoItem.id" />
   <input type="text" v-model="todoItem.title" class="form-control col-md-8">
  </div>
  <div class="form-inline">
   <label for="desc" class="control-label col-md-4">desc</label>
   <input type="text" v-model="todoItem.desc" class="form-control col-md-8">
  </div>
  <div class="form-inline">
   <input type="button" value="OK" v-on:click="save()" class="btn btn-primary offset-md-10" :disabled='canSave' />
  </div>
  </div>


 </div>
 </div>
 <script>
 var list=[];
 var TodoItem = (function () {
  var id = 1;
  return function (title, desc) {
  this.title = title;
  this.desc = desc;

  this.id = id++;
  }
 })();
 new Vue({
  el: '#app',
  data: {
  todolist: [],
  todoItem: {
   id: '',
   title: '',
   desc: ''
  },
  keyword: ''
  }, computed: {
  canSave: function () {
   return !this.todoItem.title || !this.todoItem.desc;
  }
  },
  methods: {
  query: function () {
   //过滤title中不包含keyword的数据
   //这里必须通过list全局变量过滤,而不能通过this.todolist,因为需要给this.todolist赋值,赋值后无法还原原来的列表。
   this.todolist = list.filter(v => v.title.indexOf(this.keyword) !== -1);
  },
  edit: function (id) {
   //找到id值等于所传参数的todoitem
   var obj = this.todolist.filter(v => v.id === id)[0];
   //对数据进行绑定,则数据会响应到表单上
   this.todoItem = {
   id: obj.id,
   title: obj.title,
   desc: obj.desc
   };
  },
  save: function () {
   if (this.todoItem.id) {
   //编辑保存
   var obj = this.todolist.filter(v => v.id === this.todoItem.id)[0];
   obj.title = this.todoItem.title;
   obj.desc = this.todoItem.desc;

   } else {
   //新增保存
   this.todolist.push(
    new TodoItem(
    this.todoItem.title,
    this.todoItem.desc
    )
   );
   }
   //重置表单
   this.todoItem = { title: '', desc: '' };
  },

  remove: function (index) {
   this.todolist.splice(index, 1);
  }

  }
 })
 </script>
</body>

</html>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
原生javascript获取元素样式属性值的方法
Dec 25 Javascript
jQuery-Easyui 1.2 实现多层菜单效果的代码
Jan 13 Javascript
node.js [superAgent] 请求使用示例
Mar 13 Javascript
js简单实现Select互换数据的方法
Aug 17 Javascript
jquery性能优化高级技巧
Aug 24 Javascript
Backbone.js框架中简单的View视图编写学习笔记
Feb 14 Javascript
JQuery Mobile 弹出式登录框的实现方法
May 28 Javascript
Bootstrap基本样式学习笔记之图片(6)
Dec 07 Javascript
使用jQuery实现一个类似GridView的编辑,更新,取消和删除的功能
Mar 15 Javascript
JavaScript选择排序算法原理与实现方法示例
Aug 06 Javascript
JavaScript的级联函数用法简单示例【链式调用】
Mar 26 Javascript
VSCode launch.json配置详细教程
Jun 18 Javascript
浅谈vue.js中v-for循环渲染
Jul 26 #Javascript
前端主流框架vue学习笔记第一篇
Jul 26 #Javascript
关于vue.js组件数据流的问题
Jul 26 #Javascript
Vue.js弹出模态框组件开发的示例代码
Jul 26 #Javascript
VueJs单页应用实现微信网页授权及微信分享功能示例
Jul 26 #Javascript
node实现简单的反向代理服务器
Jul 26 #Javascript
Angular项目中$scope.$apply()方法的使用详解
Jul 26 #Javascript
You might like
php获取文件夹路径内的图片以及分页显示示例
2014/03/11 PHP
PHP SplObjectStorage使用实例
2015/05/12 PHP
Laravel 中创建 Zip 压缩文件并提供下载的实现方法
2019/04/02 PHP
使用Jquery Aajx访问WCF服务(GET、POST、PUT、DELETE)
2012/03/16 Javascript
JS的replace方法介绍
2012/10/20 Javascript
JS实现匀速运动的代码实例
2013/11/29 Javascript
js转化毫秒为时间格式代码
2014/04/10 Javascript
JavaScript取得WEB安全颜色列表的方法
2015/07/14 Javascript
JavaScript数据类型学习笔记
2016/01/25 Javascript
详解Angularjs filter过滤器
2016/02/06 Javascript
利用JS实现数字增长
2016/07/28 Javascript
AngularJS自定义服务与fliter的混合使用
2016/11/24 Javascript
angular-ui-sortable实现可拖拽排序列表
2016/12/28 Javascript
简单易懂的天气插件(代码分享)
2017/02/04 Javascript
nodejs个人博客开发第三步 载入页面
2017/04/12 NodeJs
令按钮悬浮在(手机)页面底部的实现方法
2017/05/02 Javascript
JavaScript中重名的函数与对象示例详析
2017/09/28 Javascript
angular之ng-template模板加载
2017/11/09 Javascript
解决微信浏览器缓存站点入口文件(IIS部署Vue项目)
2019/06/17 Javascript
Vue实现图书管理案例
2021/01/20 Vue.js
[40:03]RNG vs VG 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
[02:42]岂曰无衣,与子同袍!DOTA2致敬每一位守护人
2020/02/17 DOTA
Linux环境下MySQL-python安装过程分享
2015/02/02 Python
更改Ubuntu默认python版本的两种方法python-&gt; Anaconda
2016/12/18 Python
python list元素为tuple时的排序方法
2018/04/18 Python
对python中 math模块下 atan 和 atan2的区别详解
2020/01/17 Python
python GUI库图形界面开发之PyQt5图片显示控件QPixmap详细使用方法与实例
2020/02/27 Python
tensorflow中tf.reduce_mean函数的使用
2020/04/19 Python
Django-Scrapy生成后端json接口的方法示例
2020/10/06 Python
css3媒体查询中device-width和width的区别详解
2020/03/27 HTML / CSS
PHP面试题及答案一
2012/06/18 面试题
高中生的自我鉴定范文
2014/01/24 职场文书
公务员考察材料范文
2014/12/23 职场文书
用电申请报告范文
2015/05/18 职场文书
2016七夕情人节感言
2015/12/09 职场文书
2019银行员工个人工作自我鉴定
2019/06/27 职场文书