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

接上篇,在本篇中,我们将要实现如下,功能,编辑和查询,我们当前的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>

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

自增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;
    },
   ...省略其它
}

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

从运行结果上看,我们点击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);
  }

  }

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

为了逼格更高一点,这里我再介绍一个指令,其实上面已经使用了,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>

刷新运行:

上面代码能很好的运行,但是现在如果我需要修改一下验证规则,在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>

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

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);
  }

刷新页面运行效果如图:

代码部分注释中已经写的很清楚了,有疑问可提价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>

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

(0)

相关推荐

  • vue,angular,avalon这三种MVVM框架优缺点

    本文的主要内容是参考官方文档说明总结而来: Vue.js Vue.js @尤雨溪 老师写的一个用于创建 web 交互界面的库,是一个精简的 MVVM.从技术角度讲,Vue.js 专注于 MVVM 模型的 ViewModel 层.它通过双向数据绑定把 View 层和 Model 层连接了起来.实际的 DOM 封装和输出格式都被抽象为了Directives 和 Filters.Vue.js和其他库相比是一个小而美的库,作者的主要目的是通过一个尽量简单的 API 产生可反映的数据绑定和可组合的视图组件

  • 前端框架Vue.js中Directive知识详解

    Directive 看上去虽然和Angular中的定义类似,Directive 都是对DOM功能的一种拓展,但是 Vue 的 Directive 要弱的多.因为 Vue Component 其实本来就会包含对DOM的操作,所以大多数时候我们写一个通用组件都是一个Component 而不是一个 Directive,而 在 Angular 我们写一个通用的组件一般都是一个 Directive . 所以我说 Vue 的 Directive 相比于 Angular 要弱的多,也可以说纯粹的多,他就是对

  • 第一次接触神奇的前端框架vue.js

    前言 入手2016最火前端框架之一vue.js.大概从网上找了些资料看了下vue.js,从网上的资料来看只能惊叹其发展速度太快,让我意外的是其作者是华人的前提下作品这么受欢迎. 网上的博客和教程各种组合.以至于我都有些感觉out.各种vue+webpack.vue+react.vue+es6+npm等等.琳琅满目.真是三天不学习赶不上刘少奇. 开篇主要是初次了解下vue.js,包括v-model.v-if.v-else.v-show.v-for(2.0对$index和$key舍弃,2.0要用in

  • 前端框架学习总结之Angular、React与Vue的比较详解

    近几年前端的技术发展很快,细分下来,主要可以分成四个方面: 1.开发语言技术,主要是ES6&7,coffeescript,typescript等: 2.开发框架,如Angular,React,Vue.js,Angular2等: 3.开发工具的丰富和前端工程化,像Grunt,Gulp,Webpack,npm,eslint,mocha这些技术: 4.前端开发范围的扩展,如服务端的nodejs,express,koa,meteor,GraphQL;移动端和跨平台的PhoneGap,ionic,Reac

  • 利用VUE框架,实现列表分页功能示例代码

    先来看一下效果图: 功能描述: 1. 点击页面序号跳转到相应页面: 2. 点击单左/单右,向后/向前跳转一个页面: 3. 点击双左/双右,直接跳转到最后一页/第一页: 4. 一次显示当前页面的前三个与后三个页面: 5. 始终显示最后一个页面: HTML: <!-- 分页开始 --> <div class="u-pages" style="margin-bottom:20px; margin-top:10px;"> <ul> <

  • Vue2.0 UI框架ElementUI使用方法详解

    今天来介绍一下ElementUI的使用,在Vue2.0更新之后,很多UI框架也应运而生,这个框架是饿了么团队开发的一款适用于PC的一个UI框架,体验之后给我的个人感觉确实是有助于快速开发的一款UI框架,在饿了么GitHub中我下载了一个团队开发的官方Demo(GitHub链接为:https://github.com/taylorchen709/vue-admin)感觉可以应对初期团队项目为管理系统的开发这一类的网站,下面我就来仔细讲解下如何让官方的Demo运行起来 首先我们使用windows件+

  • 前端框架Vue.js构建大型应用浅析

    真正的模块化 前端模块化很早就开始了,无论是 require.js,browserify 进行模块化打包, 还是 Angular 进行依赖注入,我们都可以把JS代码分成一个个小的模块并组装起来.然后我们还会通过 less 或者 sass 来把CSS文件也拆成一个个小的模块来写,甚至我们在CSS代码中感受到了 封装,继承,多态 等面向对象的特性. 然而,在 webpack 出来之前,我们所谓的模块化根本不能算作模块化.为什么这么讲,因为我们存在一个重要的问题没有解决,就是JS模块对CSS模块的依赖

  • vue.js中mint-ui框架的使用方法

    本文为大家分享了vue.js中mint-ui框架的使用方法,具体内容如下 1.安装vue2.0的mint-ui框架 npm install mint-ui -save 2.引用和使用框架,我用的是全部组件,也可以按需选择加载相应的组件,不过要使用babel-plugin-component import Mint from 'mint-ui'; Vue.use(Mint); 3.创建一个header.vue组件,里面写入mint-ui的头部组件 <template> <mt-header

  • Vue.js 2.0 和 React、Augular等其他前端框架大比拼

    React React 和 Vue 有许多相似之处,它们都有: 使用 Virtual DOM 提供了响应式(Reactive)和组件化(Composable)的视图组件. 保持注意力集中在核心库,伴随于此,有配套的路由和负责处理全局状态管理的库. 相似的作用域,我们会用更多的时间来讲这一块的比较.不仅我们要保持技术的准确性,同时兼顾平衡.我们指出React比Vue更好的地方,例如,他们的生态系统和丰富的自定义渲染器. React社区在这里非常积极地帮助我们实现这一平衡,特别感谢来自 React

  • 基于Vuejs框架实现翻页组件

    翻页功能对前端后端都是个难题啊!今天终于给踩了!哈哈!整理下方法,我是基于vueJs写的,同样适用于angular哈! 封装下载地址:vue.js翻页组件 效果截图: 整体实现逻辑,当用户点击页码时,ajax从后端获取数据,包括:records(当前页查询到的记录),totalRecords: 121(所有记录),currentPage(当前页码),totalPage(总页码),size(当前页显示数量),之后用我封装的算法assemblePageTurnerParams,算出页面展示哪些页码.

随机推荐