vue快速入门的三个小实例

12691282 7年前
   <h2>1.前言</h2>    <p>用vue做项目也有一段时间了,之前也是写过关于vue和webpack构建项目的相关文章,大家有兴趣可以去看下 <a href="/misc/goto?guid=4959751644156714885" rel="nofollow,noindex">webpack+vue项目实战(一,搭建运行环境和相关配置)</a> (这个系列一共有5篇文章,这是第一篇,其它几篇文章链接就不贴了)。但是关于vue入门基础的文章,我还没有写过,那么今天就写vue入门的三个小实例,这三个小实例是我刚接触vue的时候的练手作品,难度从很简单到简单,都是入门级的。希望能帮到大家更好的学习和了解vue,也是让自己能够复习一下vue。如果发现文章写得有什么不好,写错了,或者有什么建议!欢迎大家指点迷津!</p>    <p>1.本篇文章使用的vue版本是 2.4.2 ,大家要注意版本问题</p>    <p>2.现在我也是假设您有基础的html,css,javascript的知识,也已经看过了 <a href="/misc/goto?guid=4959751644251712428" rel="nofollow,noindex">官网</a> 的基本介绍,对vue有了一个大概的认识了,了解了常用的vue指令(v-model,v-show,v-if,v-for,v-on,v-bind等)!如果刚接触前端的话,你看着文章可能会蒙圈,建议先学习基础,掌握了基础知识再来看!</p>    <p>3.下面的实例,建议大家边看文章边动手做!这样思路会非常清晰,不易混乱!也不会觉得文章长!如果只看文章,你可能未必会看完,因为文章我讲得比较细,比较长!</p>    <h2>2.什么是vue</h2>    <p>vue是现在很火的一个前端MVVM框架,它以数据驱动和组件化的思想构建,与angular和react并称前端三大框架。相比angular和react,vue更加轻巧、高性能、也很容易上手。大家也可以移步,看一下vue的介绍和核心功能 <a href="/misc/goto?guid=4959751644342736815" rel="nofollow,noindex">官网介绍</a> 。简单粗暴的理解就是:用vue开发的时候,就是操作数据,然后vue就会处理,以数据驱动去改变DOM(不知道有没有理解错,理解错了指点下)。</p>    <p>下面就是一个最简单的说明例子</p>    <p>代码如下</p>    <p>html</p>    <pre>  <code class="language-html"><div id="app">    <p>{{ message }}</p>    <input v-model="message">  </div></code></pre>    <p>js</p>    <pre>  <code class="language-html">new Vue({    el: '#app',    data: {      message: 'Hello Vue!'    }  })</code></pre>    <p>栗子</p>    <p>相信也不难理解,就是 input 绑定了 message 这个值,然后在 input 修改的时候, message 就改了,由于双向绑定,同时页面的html( {{ message }} )进行了修改!</p>    <p>好,下面进入例子学习!</p>    <h2>3.选项卡</h2>    <h3>运行效果</h3>    <p><img src="https://simg.open-open.com/show/caace91db65eea894c859287514b7e98.gif"></p>    <h3>原理分析和实现</h3>    <p>这个很简单,无非就是一个点击切换显示而已。但是大家也要实现。如果这个看明白了,再看下面两个!这个实例应该只是一个热身和熟悉的作用!</p>    <p>这个的步骤只有一步,原理也没什么。我直接在代码打注释,看了注释,大家就明白了!</p>    <h3>完整代码</h3>    <p><!DOCTYPE html></p>    <p><html lang="en"></p>    <p><head></p>    <pre>  <code class="language-html"><meta charset="UTF-8">  <title>Title</title></code></pre>    <p></head></p>    <p><style></p>    <pre>  <code class="language-html">body{      font-family:"Microsoft YaHei";  }  #tab{      width: 600px;      margin: 0 auto;  }  .tab-tit{      font-size: 0;      width: 600px;  }  .tab-tit a{      display: inline-block;      height: 40px;      line-height: 40px;      font-size: 16px;      width: 25%;      text-align: center;      background: #ccc;      color: #333;      text-decoration: none;  }  .tab-tit .cur{      background: #09f;      color: #fff;  }  .tab-con div{      border: 1px solid #ccc;      height: 400px;      padding-top: 20px;  }</code></pre>    <p></style></p>    <p><body></p>    <p><div id="tab"></p>    <pre>  <code class="language-html"><div class="tab-tit">      <!--点击设置curId的值  如果curId等于0,第一个a添加cur类名,如果curId等于1,第二个a添加cur类名,以此类推。添加了cur类名,a就会改变样式 @click,:class ,v-show这三个是vue常用的指令或添加事件的方式-->      <a href="javascript:;" @click="curId=0" :class="{'cur':curId===0}">html</a>      <a href="javascript:;" @click="curId=1" :class="{'cur':curId===1}">css</a>      <a href="javascript:;" @click="curId=2" :class="{'cur':curId===2}">javascript</a>      <a href="javascript:;" @click="curId=3" :class="{'cur':curId===3}">vue</a>  </div>  <div class="tab-con">      <!--根据curId的值显示div,如果curId等于0,第一个div显示,其它三个div不显示。如果curId等于1,第二个div显示,其它三个div不显示。以此类推-->      <div v-show="curId===0">          html<br/>      </div>      <div v-show="curId===1">          css      </div>      <div v-show="curId===2">          javascript      </div>      <div v-show="curId===3">          vue      </div>  </div></code></pre>    <p></div></p>    <p></body></p>    <p><script src="vue.min.js"></script></p>    <p><script></p>    <pre>  <code class="language-html">new Vue({      el: '#tab',      data: {          curId: 0      },      computed: {},      methods: {},      mounted: function () {      }  })</code></pre>    <p></script></p>    <p></html></p>    <h2>4.统计总价</h2>    <h3>运行效果</h3>    <p><img src="https://simg.open-open.com/show/d4d8c06ba353ea6b86171ad5602bd6f6.gif"></p>    <h3>原理分析和实现</h3>    <p>首先,还是先把布局写好,和引入vue,准备vue实例,这个不多说,代码如下</p>    <pre>  <code class="language-html"><!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>Title</title>      <style>          .fl{              float: left;          }          .fr{              float: right;          }         blockquote, body, dd, div, dl, dt, fieldset, form, h1, h2, h3, h4, h5, h6, img, input, li, ol, p, table, td, textarea, th, ul {              margin: 0;              padding: 0;          }         .clearfix{            zoom: 1;         }          .clearfix:after {              clear: both;          }          .clearfix:after {              content: '.';              display: block;              overflow: hidden;              visibility: hidden;              font-size: 0;              line-height: 0;              width: 0;              height: 0;          }          a{              text-decoration: none;              color: #333;          }          img{vertical-align: middle;}          .page-shopping-cart {              width: 1200px;              margin: 50px auto;              font-size: 14px;              border: 1px solid #e3e3e3;              border-top: 2px solid #317ee7; }          .page-shopping-cart .cart-title {              color: #317ee7;              font-size: 16px;              text-align: left;              padding-left: 20px;              line-height: 68px; }          .page-shopping-cart .red-text {              color: #e94826; }          .page-shopping-cart .check-span {              display: block;              width: 24px;              height: 20px;              background: url("shopping_cart.png") no-repeat 0 0; }          .page-shopping-cart .check-span.check-true {              background: url("shopping_cart.png") no-repeat 0 -22px; }          .page-shopping-cart .td-check {              width: 70px; }          .page-shopping-cart .td-product {              width: 460px; }          .page-shopping-cart .td-num, .page-shopping-cart .td-price, .page-shopping-cart .td-total {              width: 160px; }          .page-shopping-cart .td-do {              width: 150px; }          .page-shopping-cart .cart-product-title {              text-align: center;              height: 38px;              line-height: 38px;              padding: 0 20px;              background: #f7f7f7;              border-top: 1px solid #e3e3e3;              border-bottom: 1px solid #e3e3e3; }          .page-shopping-cart .cart-product-title .td-product {              text-align: center;              font-size: 14px; }          .page-shopping-cart .cart-product-title .td-check {              text-align: left; }          .page-shopping-cart .cart-product-title .td-check .check-span {              margin: 9px 6px 0 0; }          .page-shopping-cart .cart-product {              padding: 0 20px;              text-align: center; }          .page-shopping-cart .cart-product table {              width: 100%;              text-align: center;              font-size: 14px; }          .page-shopping-cart .cart-product table td {              padding: 20px 0; }          .page-shopping-cart .cart-product table tr {              border-bottom: 1px dashed #e3e3e3; }          .page-shopping-cart .cart-product table tr:last-child {              border-bottom: none; }          .page-shopping-cart .cart-product table .product-num {              border: 1px solid #e3e3e3;              display: inline-block;              text-align: center; }          .page-shopping-cart .cart-product table .product-num .num-do {              width: 24px;              height: 28px;              display: block;              background: #f7f7f7; }          .page-shopping-cart .cart-product table .product-num .num-reduce span {              background: url("shopping_cart.png") no-repeat -40px -22px;              display: block;              width: 6px;              height: 2px;              margin: 13px auto 0 auto; }          .page-shopping-cart .cart-product table .product-num .num-add span {              background: url("shopping_cart.png") no-repeat -60px -22px;              display: block;              width: 8px;              height: 8px;              margin: 10px auto 0 auto; }          .page-shopping-cart .cart-product table .product-num .num-input {              width: 42px;              height: 28px;              line-height: 28px;              border: none;              text-align: center; }          .page-shopping-cart .cart-product table .td-product {              text-align: left;              font-size: 12px;              line-height: 20px; }          .page-shopping-cart .cart-product table .td-product img {              border: 1px solid #e3e3e3;              margin-right: 10px; }          .page-shopping-cart .cart-product table .td-product .product-info {              display: inline-block;              vertical-align: middle; }          .page-shopping-cart .cart-product table .td-do {              font-size: 12px; }          .page-shopping-cart .cart-product-info {              height: 50px;              line-height: 50px;              background: #f7f7f7;              padding-left: 20px; }          .page-shopping-cart .cart-product-info .delect-product {              color: #666; }          .page-shopping-cart .cart-product-info .delect-product span {              display: inline-block;              vertical-align: top;              margin: 18px 8px 0 0;              width: 13px;              height: 15px;              background: url("shopping_cart.png") no-repeat -60px 0; }          .page-shopping-cart .cart-product-info .product-total {              font-size: 14px;              color: #e94826; }          .page-shopping-cart .cart-product-info .product-total span {              font-size: 20px; }          .page-shopping-cart .cart-product-info .check-num {              color: #333; }          .page-shopping-cart .cart-product-info .check-num span {              color: #e94826; }          .page-shopping-cart .cart-product-info .keep-shopping {              color: #666;              margin-left: 40px; }          .page-shopping-cart .cart-product-info .keep-shopping span {              display: inline-block;              vertical-align: top;              margin: 18px 8px 0 0;              width: 15px;              height: 15px;              background: url("shopping_cart.png") no-repeat -40px 0; }          .page-shopping-cart .cart-product-info .btn-buy {              height: 50px;              color: #fff;              font-size: 20px;              display: block;              width: 110px;              background: #ff7700;              text-align: center;              margin-left: 30px; }          .page-shopping-cart .cart-worder {              padding: 20px; }          .page-shopping-cart .cart-worder .choose-worder {              color: #fff;              display: block;              background: #39e;              width: 140px;              height: 40px;              line-height: 40px;              border-radius: 4px;              text-align: center;              margin-right: 20px; }          .page-shopping-cart .cart-worder .choose-worder span {              display: inline-block;              vertical-align: top;              margin: 9px 10px 0 0;              width: 22px;              height: 22px;              background: url("shopping_cart.png") no-repeat -92px 0; }          .page-shopping-cart .cart-worder .worker-info {              color: #666; }          .page-shopping-cart .cart-worder .worker-info img {              border-radius: 100%;              margin-right: 10px; }          .page-shopping-cart .cart-worder .worker-info span {              color: #000; }            .choose-worker-box {              width: 620px;              background: #fff; }          .choose-worker-box .box-title {              height: 40px;              line-height: 40px;              background: #F7F7F7;              text-align: center;              position: relative;              font-size: 14px; }          .choose-worker-box .box-title a {              display: block;              position: absolute;              top: 15px;              right: 16px;              width: 10px;              height: 10px;              background: url("shopping_cart.png") no-repeat -80px 0; }          .choose-worker-box .box-title a:hover {              background: url("shopping_cart.png") no-repeat -80px -22px; }          .choose-worker-box .worker-list {              padding-top: 30px;              height: 134px;              overflow-y: auto; }          .choose-worker-box .worker-list li {              float: left;              width: 25%;              text-align: center;              margin-bottom: 30px; }          .choose-worker-box .worker-list li p {              margin-top: 8px; }          .choose-worker-box .worker-list li.cur a {              color: #f70; }          .choose-worker-box .worker-list li.cur a img {              border: 1px solid #f70; }          .choose-worker-box .worker-list li a:hover {              color: #f70; }          .choose-worker-box .worker-list li a:hover img {              border: 1px solid #f70; }          .choose-worker-box .worker-list li img {              border: 1px solid #fff;              border-radius: 100%; }      </style>  </head>  <body>  <div class="page-shopping-cart" id="shopping-cart">      <h4 class="cart-title">购物清单</h4>      <div class="cart-product-title clearfix">          <div class="td-check fl"><span class="check-span fl check-all"></span>全选</div>          <div class="td-product fl">商品</div>          <div class="td-num fl">数量</div>          <div class="td-price fl">单价(元)</div>          <div class="td-total fl">金额(元)</div>          <div class="td-do fl">操作</div>      </div>      <div class="cart-product clearfix">          <table>              <tbody><tr>                  <td class="td-check"><span class="check-span"></span></td>                  <td class="td-product"><img src="testimg.jpg" width="98" height="98">                      <div class="product-info">                          <h6>【斯文】甘油 | 丙三醇</h6>                          <p>品牌:韩国skc  产地:韩国</p>                          <p>规格/纯度:99.7%  起定量:215千克</p>                          <p>配送仓储:上海仓海仓储</p>                      </div>                      <div class="clearfix"></div>                  </td>                  <td class="td-num">                      <div class="product-num">                          <a href="javascript:;" class="num-reduce num-do fl"><span></span></a>                          <input type="text" class="num-input" value="3">                          <a href="javascript:;" class="num-add num-do fr"><span></span></a>                      </div>                  </td>                  <td class="td-price">                      <p class="red-text">¥<span class="price-text">800</span>.00</p>                  </td>                  <td class="td-total">                      <p class="red-text">¥<span class="total-text">800</span>.00</p>                  </td>                  <td class="td-do"><a href="javascript:;" class="product-delect">删除</a></td>              </tr>              <tr>                  <td class="td-check"><span class="check-span check-true"></span></td>                  <td class="td-product"><img src="testimg.jpg" width="98" height="98">                      <div class="product-info">                          <h6>【斯文】甘油 | 丙三醇</h6>                          <p>品牌:韩国skc  产地:韩国</p>                          <p>规格/纯度:99.7%  起定量:215千克</p>                          <p>配送仓储:上海仓海仓储</p>                      </div>                      <div class="clearfix"></div>                  </td>                  <td class="td-num">                      <div class="product-num">                          <a href="javascript:;" class="num-reduce num-do fl"><span></span></a>                          <input type="text" class="num-input" value="1">                          <a href="javascript:;" class="num-add num-do fr"><span></span></a>                      </div>                  </td>                  <td class="td-price">                      <p class="red-text">¥<span class="price-text">800</span>.00</p>                  </td>                  <td class="td-total">                      <p class="red-text">¥<span class="total-text">800</span>.00</p>                  </td>                  <td class="td-do"><a href="javascript:;" class="product-delect">删除</a></td>              </tr>              </tbody></table>      </div>      <div class="cart-product-info">          <a class="delect-product" href="javascript:;"><span></span>删除所选商品</a>          <a class="keep-shopping" href="#"><span></span>继续购物</a>          <a class="btn-buy fr" href="javascript:;">去结算</a>          <p class="fr product-total">¥<span>1600</span></p>          <p class="fr check-num"><span>2</span>件商品总计(不含运费):</p>      </div>      <div class="cart-worder clearfix">          <a href="javascript:;" class="choose-worder fl"><span></span>绑定跟单员</a>          <div class="worker-info fl">          </div>      </div>  </div>  </body>  <script src="vue.min.js"></script>  <script>      new Vue({          el:'#shopping-cart',          data:{            },          computed: {},          methods:{                        }      })  </script>  </html></code></pre>    <p>然后准备下列表数据,根据下面表格的箭头</p>    <p><img src="https://simg.open-open.com/show/72408e17d1684b84ac05bba5c99b1841.png"></p>    <p>所以大家就知道吗,下面的数据大概是涨这样</p>    <pre>  <code class="language-html">productList:[      {          'pro_name': '【斯文】甘油 | 丙三醇',//产品名称          'pro_brand': 'skc',//品牌名称          'pro_place': '韩国',//产地          'pro_purity': '99.7%',//规格          'pro_min': "215千克",//最小起订量          'pro_depot': '上海仓海仓储',//所在仓库          'pro_num': 3,//数量          'pro_img': '../../images/ucenter/testimg.jpg',//图片链接          'pro_price': 800//单价      }  ]</code></pre>    <p>准备了这么多,大家可能想到,还缺少一个,就是记录产品是否有选中,但是这个字段,虽然可以在上面那里加,但是意义不大,比如在平常项目那里!后台的数据不会这样返回,数据库也不会有这个字段,这个字段应该是自己添加的。代码如下</p>    <pre>  <code class="language-html">new Vue({      el:'#shopping-cart',      data:{          productList:[              {                  'pro_name': '【斯文】甘油 | 丙三醇',//产品名称                  'pro_brand': 'skc',//品牌名称                  'pro_place': '韩国',//产地                  'pro_purity': '99.7%',//规格                  'pro_min': "215千克",//最小起订量                  'pro_depot': '上海仓海仓储',//所在仓库                  'pro_num': 3,//数量                  'pro_img': '../../images/ucenter/testimg.jpg',//图片链接                  'pro_price': 800//单价              }          ]      },      computed: {},      methods:{        },      mounted:function () {          //为productList添加select(是否选中)字段,初始值为true          this.productList.map(function(item){item.select=true;console.log(item)})      }  })</code></pre>    <h3>步骤1</h3>    <p>为了着重表示我修改了什么地方,代码我现在只贴出修改的部分,大家对着上面的布局,就很容易知道我改的是什么地方了!下面也是这样操作!</p>    <p>点击增加和减少按钮(箭头指向地方),所属列的金额改变(红框地方)</p>    <p><img src="https://simg.open-open.com/show/ba9c475db9b72a89dcd05b9aef1dfeed.png"></p>    <p>执行步骤1之前,要先把列表的数据给铺出来。利用v-for指令。代码如下</p>    <pre>  <code class="language-html"><tr v-for="item in productList">      <td class="td-check"><span class="check-span"></span></td>      <td class="td-product"><img :src="item.pro_img" width="98" height="98">          <div class="product-info">              <h6>{{item.pro_name}}</h6>              <p>品牌:{{item.pro_brand}}  产地:{{item.pro_place}}</p>              <p>规格/纯度:{{item.pro_purity}}  起定量:{{item.pro_min}}</p>              <p>配送仓储:{{item.pro_depot}}</p>          </div>          <div class="clearfix"></div>      </td>      <td class="td-num">          <div class="product-num">              <a href="javascript:;" class="num-reduce num-do fl" @click="item.pro_num--"><span></span></a>              <input type="text" class="num-input" v-model="item.pro_num">              <a href="javascript:;" class="num-add num-do fr" @click="item.pro_num++"><span></span></a>          </div>      </td>      <td class="td-price">          <p class="red-text">¥<span class="price-text">{{item.pro_price.toFixed(2)}}</span></p>      </td>      <td class="td-total">          <p class="red-text">¥<span class="total-text">{{item.pro_price*item.pro_num}}</span>.00</p>      </td>      <td class="td-do"><a href="javascript:;" class="product-delect">删除</a></td>  </tr></code></pre>    <p>这样,列表的数据就有了!</p>    <p><img src="https://simg.open-open.com/show/a51d03efa3f062c2a59081355bf25f2b.gif"></p>    <p>也可以发现, <img src="https://simg.open-open.com/show/1179d9ca53a8fdca1d2d1a586200dfef.png"> 这两个按钮的功能已经实现了,后面的金额也会发生变化!是不是感到很惊喜!其实这里没什么特别的,就是因为输入框利用v-model绑定了数量( pro_num ),然后两个按钮分别添加了事件 @click="item.pro_num--" 和@ click="item.pro_num++" 。比如刚开始pro_num是3,点击 <img src="https://simg.open-open.com/show/962cb9858b1200e6b39b18262e4b72da.png"> , pro_num 就变成2,点击 <img src="https://simg.open-open.com/show/92de8e2e97d30cc6537e1a33c9587578.png"></p>    <p>, pro_num 就变成4,然后后面的金额会改改,是因为 {{item.pro_price*item.pro_num}} 。只要pro_price或者pro_num的值改变了,整一块也会改变,视图就会刷新,我们就能看到变化(这些事情是vue做的,这就是MVVM的魅力,数据驱动视图改变)。</p>    <h3>步骤2</h3>    <p>点击所属列选择按钮(箭头指向地方),总计的金额(红框地方)和已选产品的列数(蓝框地方)和全选(黄框地方)会改变(如果已经全选了,全选按钮自动变成全选,如果没有全选,全选按钮,自动取消全选)!</p>    <p><img src="https://simg.open-open.com/show/f955e1786363b755a352bde975cd00ec.png"></p>    <p>首先,选择与取消选择,在这里只有两个操作(其实只有一个:改变这条记录的 select 字段)。</p>    <p><img src="https://simg.open-open.com/show/96bb80df3b1ea0effac1bf2138751ea0.png"></p>    <p>然后改变 <img src="https://simg.open-open.com/show/442c0457cd8632af868ca1ca8bd83a35.png"> ,如果这条记录 select 为 false ,就显示 <img src="https://simg.open-open.com/show/345bc3eabf493ed1d6aa60bfaf8dec34.png" alt="vue快速入门的三个小实例" width="32" height="32"> ,否则就显示 <img src="https://simg.open-open.com/show/7e2ec1ca54429007174d77c86494a81b.png"> 。</p>    <p>代码如下</p>    <pre>  <code class="language-html"><td class="td-check"><span class="check-span" @click="item.select=!item.select" :class="{'check-true':item.select}"></span></td></code></pre>    <p>其实就是等于添加了 @click="item.select=!item.select" :class="{'check-true':item.select}" 这里。点击这个,这条数据的 select 字段就取反(true->false或者false->true)。然后 :class="{'check-true':item.select}" ,就会根据这条数据的 select 字段进行判断,是否添加 check-true 类名,如果 select 字段为true,就添加类名,显示 <img src="https://simg.open-open.com/show/d46377bd733da5e8c2236d64af25e68a.png"> 。否则不添加类名,显示</p>    <p><img src="https://simg.open-open.com/show/055adf62efc294fd5cc55d8bca11e172.png"></p>    <p>。</p>    <p>然后, <img src="https://simg.open-open.com/show/72086fbfdcb03b8b0e78ef9d50bed2c9.png"> 全选按钮,是否变成 <img src="https://simg.open-open.com/show/d46377bd733da5e8c2236d64af25e68a.png" alt="vue快速入门的三个小实例" width="34" height="30"> 。这里用一个computed(计算属性)就好。代码如下</p>    <p>html</p>    <pre>  <code class="language-html"><div class="td-check fl"><span class="check-span fl check-all" :class="{'check-true':isSelectAll}"></span>全选</div></code></pre>    <p>js</p>    <pre>  <code class="language-html">computed: {      isSelectAll:function(){          //如果productList中每一条数据的select都为true,返回true,否则返回false;          return this.productList.every(function (val) { return val.select});      }  }</code></pre>    <p>代码我解释下,就是计算属性中,定义的isSelectAll依赖productList。只要productList改变,isSelectAll的返回值就会改变,然后 :class="{'check-true':isSelectAll}" 根绝isSelectAll返回值是否添加 'check-true' 类名,显示对应的样式!</p>    <p>最后, <img src="https://simg.open-open.com/show/c38e4b764ddb46fe99418ac879934ce3.png"> ,这里的多少件产品和总价,也是使用计算属性,有了上一步的基础,给出代码,大家一看就明白了!</p>    <p>html</p>    <pre>  <code class="language-html"><p class="fr product-total">¥<span>{{getTotal.totalPrice}}</span></p>  <p class="fr check-num"><span>{{getTotal.totalNum}}</span>件商品总计(不含运费):</p></code></pre>    <p>js</p>    <pre>  <code class="language-html">computed: {      //检测是否全选      isSelectAll:function(){          //如果productList中每一条数据的select都为true,返回true,否则返回false;          return this.productList.every(function (val) { return val.select});      },      //获取总价和产品总件数      getTotal:function(){          //获取productList中select为true的数据。          var _proList=this.productList.filter(function (val) { return val.select}),totalPrice=0;          for(var i=0,len=_proList.length;i<len;i++){              //总价累加              totalPrice+=_proList[i].pro_num*_proList[i].pro_price;          }          //选择产品的件数就是_proList.length,总价就是totalPrice          return {totalNum:_proList.length,totalPrice:totalPrice}      }  },</code></pre>    <p>代码很简单,html根据getTotal返回值显示数据,getTotal依赖productList的数据,只要productList改变,返回值会改变,视图也会改变!</p>    <p><img src="https://simg.open-open.com/show/c3d7e2e7ca6f7e5b26c66d2ea1d64cd3.gif"></p>    <h3>步骤3</h3>    <p>点击全选按钮(箭头指向部分),会自动的对产品进行全选或者取消全选,下面的总计也会发生改变</p>    <p><img src="https://simg.open-open.com/show/93c421bc8c454beecf00b8593826fb32.png"></p>    <p>做到这一步,大家应该知道,全选或者取消全选,就是改变记录的 select 。但是怎么知道现在的列表有没有全选呢?这个很贱,不需要在操作函数(全选与取消全选函数)里面遍历,大家应该还记得第二步的计算属性 isSelectAll (为true就是全选,否则不是全选),把这个传进操作函数就好,然后操作函数,根据参数,决定执行全选,还是取消全选操作。代码如下!</p>    <p>html</p>    <pre>  <code class="language-html"><div class="td-check fl"><span class="check-span fl check-all" :class="{'check-true':isSelectAll}" @click="selectProduct(isSelectAll)"></span>全选</div></code></pre>    <p>js</p>    <pre>  <code class="language-html">methods: {      //全选与取消全选      selectProduct:function(_isSelect){          //遍历productList,全部取反          for (var i = 0, len = this.productList.length; i < len; i++) {              this.productList[i].select = !_isSelect;          }      }  },</code></pre>    <p><img src="https://simg.open-open.com/show/637b569b0fb31b51aedb4e458b155158.gif"></p>    <h3>步骤4</h3>    <p>点击删除产品,会删除已经选中的,全选按钮和下面的总计,都会变化!点击每条记录后面的删除,会删除当前的这条记录。全选按钮和下面的总计,也都会变化!</p>    <p><img src="https://simg.open-open.com/show/ed15dd5f0fd6d736258b6de5b2e51792.png"></p>    <p>首先,点击删除产品,删除已经选中。这个大家知道了怎么做了!就是遍历productList,如果哪条记录的select为true,就删除。</p>    <p>然后,点击每条记录后面的删除,删除当前的这条记录。这个在html遍历productList的时候。顺便带上索引,然后把索引当成参数,传进操作函数,然后根据索引参数,删除productList的哪一条记录。即可实现!代码如下!</p>    <p>html</p>    <pre>  <code class="language-html"><!--遍历的时候带上索引-->  <tr v-for="(item,index) in productList">      <td class="td-check"><span class="check-span" @click="item.select=!item.select" :class="{'check-true':item.select}"></span></td>      <td class="td-product"><img :src="item.pro_img" width="98" height="98">          <div class="product-info">              <h6>{{item.pro_name}}</h6>              <p>品牌:{{item.pro_brand}}  产地:{{item.pro_place}}</p>              <p>规格/纯度:{{item.pro_purity}}  起定量:{{item.pro_min}}</p>              <p>配送仓储:{{item.pro_depot}}</p>          </div>          <div class="clearfix"></div>      </td>      <td class="td-num">          <div class="product-num">              <a href="javascript:;" class="num-reduce num-do fl" @click="item.pro_num--"><span></span></a>              <input type="text" class="num-input" v-model="item.pro_num">              <a href="javascript:;" class="num-add num-do fr" @click="item.pro_num++"><span></span></a>          </div>      </td>      <td class="td-price">          <p class="red-text">¥<span class="price-text">{{item.pro_price.toFixed(2)}}</span></p>      </td>      <td class="td-total">          <p class="red-text">¥<span class="total-text">{{item.pro_price*item.pro_num}}</span>.00</p>      </td>      <td class="td-do"><a href="javascript:;" class="product-delect" @click="deleteOneProduct(index)">删除</a></td>  </tr>  ...  <a class="delect-product" href="javascript:;" @click="deleteProduct"><span></span>删除所选商品</a></code></pre>    <p>js</p>    <pre>  <code class="language-html">//删除已经选中(select=true)的产品  deleteProduct:function () {      this.productList=this.productList.filter(function (item) {return !item.select})  },  //删除单条产品  deleteOneProduct:function (index) {      //根据索引删除productList的记录      this.productList.splice(index,1);  },</code></pre>    <h3>完整代码</h3>    <p>样式图片</p>    <p><img src="https://simg.open-open.com/show/117d45a8157e49b31947f1e5b255a58e.png"></p>    <pre>  <code class="language-html"><!DOCTYPE html>      <html lang="en">      <head>          <meta charset="UTF-8">          <title>Title</title>          <style>              .fl {                  float: left;              }                     .fr {                  float: right;              }                    blockquote, body, dd, div, dl, dt, fieldset, form, h1, h2, h3, h4, h5, h6, img, input, li, ol, p, table, td, textarea, th, ul {                  margin: 0;                  padding: 0;              }                    .clearfix {                  zoom: 1;              }                    .clearfix:after {                  clear: both;              }                    .clearfix:after {                  content: '.';                  display: block;                  overflow: hidden;                  visibility: hidden;                  font-size: 0;                  line-height: 0;                  width: 0;                  height: 0;              }                    a {                  text-decoration: none;                  color: #333;              }                    img {                  vertical-align: middle;              }                    .page-shopping-cart {                  width: 1200px;                  margin: 50px auto;                  font-size: 14px;                  border: 1px solid #e3e3e3;                  border-top: 2px solid #317ee7;              }                    .page-shopping-cart .cart-title {                  color: #317ee7;                  font-size: 16px;                  text-align: left;                  padding-left: 20px;                  line-height: 68px;              }                    .page-shopping-cart .red-text {                  color: #e94826;              }                    .page-shopping-cart .check-span {                  display: block;                  width: 24px;                  height: 20px;                  background: url("shopping_cart.png") no-repeat 0 0;              }                    .page-shopping-cart .check-span.check-true {                  background: url("shopping_cart.png") no-repeat 0 -22px;              }                    .page-shopping-cart .td-check {                  width: 70px;              }                    .page-shopping-cart .td-product {                  width: 460px;              }                    .page-shopping-cart .td-num, .page-shopping-cart .td-price, .page-shopping-cart .td-total {                  width: 160px;              }                    .page-shopping-cart .td-do {                  width: 150px;              }                    .page-shopping-cart .cart-product-title {                  text-align: center;                  height: 38px;                  line-height: 38px;                  padding: 0 20px;                  background: #f7f7f7;                  border-top: 1px solid #e3e3e3;                  border-bottom: 1px solid #e3e3e3;              }                    .page-shopping-cart .cart-product-title .td-product {                  text-align: center;                  font-size: 14px;              }                    .page-shopping-cart .cart-product-title .td-check {                  text-align: left;              }                    .page-shopping-cart .cart-product-title .td-check .check-span {                  margin: 9px 6px 0 0;              }                    .page-shopping-cart .cart-product {                  padding: 0 20px;                  text-align: center;              }                    .page-shopping-cart .cart-product table {                  width: 100%;                  text-align: center;                  font-size: 14px;              }                    .page-shopping-cart .cart-product table td {                  padding: 20px 0;              }                    .page-shopping-cart .cart-product table tr {                  border-bottom: 1px dashed #e3e3e3;              }                    .page-shopping-cart .cart-product table tr:last-child {                  border-bottom: none;              }                    .page-shopping-cart .cart-product table .product-num {                  border: 1px solid #e3e3e3;                  display: inline-block;                  text-align: center;              }                    .page-shopping-cart .cart-product table .product-num .num-do {                  width: 24px;                  height: 28px;                  display: block;                  background: #f7f7f7;              }                    .page-shopping-cart .cart-product table .product-num .num-reduce span {                  background: url("shopping_cart.png") no-repeat -40px -22px;                  display: block;                  width: 6px;                  height: 2px;                  margin: 13px auto 0 auto;              }                    .page-shopping-cart .cart-product table .product-num .num-add span {                  background: url("shopping_cart.png") no-repeat -60px -22px;                  display: block;                  width: 8px;                  height: 8px;                  margin: 10px auto 0 auto;              }                    .page-shopping-cart .cart-product table .product-num .num-input {                  width: 42px;                  height: 28px;                  line-height: 28px;                  border: none;                  text-align: center;              }                    .page-shopping-cart .cart-product table .td-product {                  text-align: left;                  font-size: 12px;                  line-height: 20px;              }                    .page-shopping-cart .cart-product table .td-product img {                  border: 1px solid #e3e3e3;                  margin-right: 10px;              }                    .page-shopping-cart .cart-product table .td-product .product-info {                  display: inline-block;                  vertical-align: middle;              }                    .page-shopping-cart .cart-product table .td-do {                  font-size: 12px;              }                    .page-shopping-cart .cart-product-info {                  height: 50px;                  line-height: 50px;                  background: #f7f7f7;                  padding-left: 20px;              }                    .page-shopping-cart .cart-product-info .delect-product {                  color: #666;              }                    .page-shopping-cart .cart-product-info .delect-product span {                  display: inline-block;                  vertical-align: top;                  margin: 18px 8px 0 0;                  width: 13px;                  height: 15px;                  background: url("shopping_cart.png") no-repeat -60px 0;              }                    .page-shopping-cart .cart-product-info .product-total {                  font-size: 14px;                  color: #e94826;              }                    .page-shopping-cart .cart-product-info .product-total span {                  font-size: 20px;              }                    .page-shopping-cart .cart-product-info .check-num {                  color: #333;              }                    .page-shopping-cart .cart-product-info .check-num span {                  color: #e94826;              }                    .page-shopping-cart .cart-product-info .keep-shopping {                  color: #666;                  margin-left: 40px;              }                    .page-shopping-cart .cart-product-info .keep-shopping span {                  display: inline-block;                  vertical-align: top;                  margin: 18px 8px 0 0;                  width: 15px;                  height: 15px;                  background: url("shopping_cart.png") no-repeat -40px 0;              }                    .page-shopping-cart .cart-product-info .btn-buy {                  height: 50px;                  color: #fff;                  font-size: 20px;                  display: block;                  width: 110px;                  background: #ff7700;                  text-align: center;                  margin-left: 30px;              }                    .page-shopping-cart .cart-worder {                  padding: 20px;              }                    .page-shopping-cart .cart-worder .choose-worder {                  color: #fff;                  display: block;                  background: #39e;                  width: 140px;                  height: 40px;                  line-height: 40px;                  border-radius: 4px;                  text-align: center;                  margin-right: 20px;              }                    .page-shopping-cart .cart-worder .choose-worder span {                  display: inline-block;                  vertical-align: top;                  margin: 9px 10px 0 0;                  width: 22px;                  height: 22px;                  background: url("shopping_cart.png") no-repeat -92px 0;              }                    .page-shopping-cart .cart-worder .worker-info {                  color: #666;              }                    .page-shopping-cart .cart-worder .worker-info img {                  border-radius: 100%;                  margin-right: 10px;              }                    .page-shopping-cart .cart-worder .worker-info span {                  color: #000;              }                    .choose-worker-box {                  width: 620px;                  background: #fff;              }                    .choose-worker-box .box-title {                  height: 40px;                  line-height: 40px;                  background: #F7F7F7;                  text-align: center;                  position: relative;                  font-size: 14px;              }                    .choose-worker-box .box-title a {                  display: block;                  position: absolute;                  top: 15px;                  right: 16px;                  width: 10px;                  height: 10px;                  background: url("shopping_cart.png") no-repeat -80px 0;              }                    .choose-worker-box .box-title a:hover {                  background: url("shopping_cart.png") no-repeat -80px -22px;              }                    .choose-worker-box .worker-list {                  padding-top: 30px;                  height: 134px;                  overflow-y: auto;              }                    .choose-worker-box .worker-list li {                  float: left;                  width: 25%;                  text-align: center;                  margin-bottom: 30px;              }                    .choose-worker-box .worker-list li p {                  margin-top: 8px;              }                    .choose-worker-box .worker-list li.cur a {                  color: #f70;              }                    .choose-worker-box .worker-list li.cur a img {                  border: 1px solid #f70;              }                    .choose-worker-box .worker-list li a:hover {                  color: #f70;              }                    .choose-worker-box .worker-list li a:hover img {                  border: 1px solid #f70;              }                    .choose-worker-box .worker-list li img {                  border: 1px solid #fff;                  border-radius: 100%;              }          </style>      </head>      <body>      <div class="page-shopping-cart" id="shopping-cart">          <h4 class="cart-title">购物清单</h4>          <div class="cart-product-title clearfix">              <div class="td-check fl"><span class="check-span fl check-all" :class="{'check-true':isSelectAll}" @click="selectProduct(isSelectAll)"></span>全选</div>              <div class="td-product fl">商品</div>              <div class="td-num fl">数量</div>              <div class="td-price fl">单价(元)</div>              <div class="td-total fl">金额(元)</div>              <div class="td-do fl">操作</div>          </div>          <div class="cart-product clearfix">              <table>                  <tbody>                  <!--遍历的时候带上索引-->                  <tr v-for="(item,index) in productList">                      <td class="td-check"><span class="check-span" @click="item.select=!item.select" :class="{'check-true':item.select}"></span></td>                      <td class="td-product"><img :src="item.pro_img" width="98" height="98">                          <div class="product-info">                              <h6>{{item.pro_name}}</h6>                              <p>品牌:{{item.pro_brand}}  产地:{{item.pro_place}}</p>                              <p>规格/纯度:{{item.pro_purity}}  起定量:{{item.pro_min}}</p>                              <p>配送仓储:{{item.pro_depot}}</p>                          </div>                          <div class="clearfix"></div>                      </td>                      <td class="td-num">                          <div class="product-num">                              <a href="javascript:;" class="num-reduce num-do fl" @click="item.pro_num--"><span></span></a>                              <input type="text" class="num-input" v-model="item.pro_num">                              <a href="javascript:;" class="num-add num-do fr" @click="item.pro_num++"><span></span></a>                          </div>                      </td>                      <td class="td-price">                          <p class="red-text">¥<span class="price-text">{{item.pro_price.toFixed(2)}}</span></p>                      </td>                      <td class="td-total">                          <p class="red-text">¥<span class="total-text">{{item.pro_price*item.pro_num}}</span>.00</p>                      </td>                      <td class="td-do"><a href="javascript:;" class="product-delect" @click="deleteOneProduct(index)">删除</a></td>                  </tr>                  </tbody>              </table>          </div>          <div class="cart-product-info">              <a class="delect-product" href="javascript:;" @click="deleteProduct"><span></span>删除所选商品</a>              <a class="keep-shopping" href="#"><span></span>继续购物</a>              <a class="btn-buy fr" href="javascript:;">去结算</a>              <p class="fr product-total">¥<span>{{getTotal.totalPrice}}</span></p>              <p class="fr check-num"><span>{{getTotal.totalNum}}</span>件商品总计(不含运费):</p>          </div>      </div>      </body>      <script src="vue.min.js"></script>      <script>          new Vue({              el: '#shopping-cart',              data: {                  productList: [                      {                          'pro_name': '【斯文】甘油 | 丙三醇',//产品名称                          'pro_brand': 'skc',//品牌名称                          'pro_place': '韩国',//产地                          'pro_purity': '99.7%',//规格                          'pro_min': "215千克",//最小起订量                          'pro_depot': '上海仓海仓储',//所在仓库                          'pro_num': 3,//数量                          'pro_img': '../../images/ucenter/testimg.jpg',//图片链接                          'pro_price': 800//单价                      },                      {                          'pro_name': '【斯文】甘油 | 丙三醇',//产品名称                          'pro_brand': 'skc',//品牌名称                          'pro_place': '韩国',//产地                          'pro_purity': '99.7%',//规格                          'pro_min': "215千克",//最小起订量                          'pro_depot': '上海仓海仓储',//所在仓库                          'pro_num': 3,//数量                          'pro_img': '../../images/ucenter/testimg.jpg',//图片链接                          'pro_price': 800//单价                      },                      {                          'pro_name': '【斯文】甘油 | 丙三醇',//产品名称                          'pro_brand': 'skc',//品牌名称                          'pro_place': '韩国',//产地                          'pro_purity': '99.7%',//规格                          'pro_min': "215千克",//最小起订量                          'pro_depot': '上海仓海仓储',//所在仓库                          'pro_num': 3,//数量                          'pro_img': '../../images/ucenter/testimg.jpg',//图片链接                          'pro_price': 800//单价                      }                  ]              },              computed: {                  //检测是否全选                  isSelectAll:function(){                      //如果productList中每一条数据的select都为true,返回true,否则返回false;                      return this.productList.every(function (val) { return val.select});                  },                  //获取总价和产品总件数                  getTotal:function(){                      //获取productList中select为true的数据。                      var _proList=this.productList.filter(function (val) { return val.select}),totalPrice=0;                      for(var i=0,len=_proList.length;i<len;i++){                          //总价累加                          totalPrice+=_proList[i].pro_num*_proList[i].pro_price;                      }                      //选择产品的件数就是_proList.length,总价就是totalPrice                      return {totalNum:_proList.length,totalPrice:totalPrice}                  }              },              methods: {                  //全选与取消全选                  selectProduct:function(_isSelect){                      //遍历productList,全部取反                      for (var i = 0, len = this.productList.length; i < len; i++) {                          this.productList[i].select = !_isSelect;                      }                  },                  //删除已经选中(select=true)的产品                  deleteProduct:function () {                      this.productList=this.productList.filter(function (item) {return !item.select})                  },                  //删除单条产品                  deleteOneProduct:function (index) {                      //根据索引删除productList的记录                      this.productList.splice(index,1);                  },              },              mounted: function () {                  var _this=this;                  //为productList添加select(是否选中)字段,初始值为true                  this.productList.map(function (item) {                      _this.$set(item, 'select', true);                  })              }          })      </script>      </html></code></pre>    <h2>5.todoList</h2>    <h3>运行效果</h3>    <p><img src="https://simg.open-open.com/show/62a1d2a0c400421b7774f857f4a9008f.gif"></p>    <h3>原理分析和实现</h3>    <p>首先,还是先把布局写好,和引入vue,准备vue实例,这个不多说,代码如下</p>    <pre>  <code class="language-html"><!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="vue2.4.2.js"></script>      <script type="text/javascript">      new Vue({          el: "#app",          data: {          },          computed:{                        },          methods:{                        }      });      </script>  </html></code></pre>    <p>布局有了,相当于一个骨架就有了,下面实现功能,一个一个来</p>    <h3>步骤1</h3>    <p>输入并回车,多一条记录。下面的记录文字也会改变</p>    <p><img src="https://simg.open-open.com/show/48b254ed3c310f442fb4a083e1a8a690.png"></p>    <p>首先,大的输入框回车要添加纪录,那么输入框必须绑定一个值和一个添加纪录的方法。</p>    <p>代码如下:</p>    <p>然后,下面的记录也要改变,所以,下面的记录也要帮一个值,因为这个记录可能会有多个,这个值就是一个数组,也可以看到,记录除了名称,还有记录是否完成的状态,所以,绑定记录的这个值肯定是一个对象数组!代码如下</p>    <p>最后,记录文字</p>    <p><img src="https://simg.open-open.com/show/81ee74dca85e367e2f9c623664121c06.png"></p>    <p>要改变。这个只是一个当前记录的长度即可!</p>    <p>为了着重表示我修改了什么地方,代码我现在只贴出修改的部分,大家对着上面的布局,就很容易知道我改的是什么地方了!下面也是这样操作!</p>    <p>html代码</p>    <pre>  <code class="language-html"><!--利用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></code></pre>    <p>js代码</p>    <pre>  <code class="language-html">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="";          }      }  });</code></pre>    <p>测试一下,没问题</p>    <p><img src="https://simg.open-open.com/show/26dfdfab7995e774b6dac68a652d77a5.gif"></p>    <h3>步骤2</h3>    <p>点击切换,下面记录会改变</p>    <p><img src="https://simg.open-open.com/show/243050df2931fc44e0704c9f7e143294.png"></p>    <p>看到三个选项,也很简单,无非就是三个选择,一个是所有的目标,一个是所有已经完成的目标,一个是所有没完成的目标。</p>    <p>首先.新建一个新的变量(newList),储存prolist。遍历的时候不再遍历prolist,而是遍历newList。改变也是改变newList。</p>    <p>然后.选择所有目标的时候,显示全部prolist,把prolist赋值给newList。</p>    <p>然后.选择所有已经完成目标的时候,只显示prolist中,status为true的目标,把prolist中,status为true的项赋值给newList,</p>    <p>最后.选择所有未完成目标的时候,只显示status为false的目标,把prolist中,status为false的项赋值给newList。</p>    <p>代码如下</p>    <p>html</p>    <pre>  <code class="language-html"><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></code></pre>    <p>js</p>    <pre>  <code class="language-html">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;      }  });</code></pre>    <p>运行结果</p>    <p><img src="https://simg.open-open.com/show/f0b0e54657c62232f794f9503e7eb6a9.gif"></p>    <h3>步骤3</h3>    <p>红色关闭标识,点击会删除该记录。前面按钮点击会切换该记录完成状态,颜色也改变,记录文字也跟着改变</p>    <p><img src="https://simg.open-open.com/show/73fb5fcdaa2e51ac79bae5e3509db79f.png"></p>    <p>首先点击红色关闭标识,点击会删除该记录。这个应该没什么问题,就是删除prolist的一条记录!</p>    <p>然后前面按钮点击会切换该记录完成状态。这个也没什么,就是改变prolist的一条记录的status字段!</p>    <p>最后记录文字的改变,就是记录prolist中status为false的有多少条,prolist中status为true的有多少条而已</p>    <p>html代码</p>    <pre>  <code class="language-html"><!--如果noend等于0,就是全部完成了就显示‘全部完成了’,如果没有就是显示已完成多少条(prolist.length-noend)和未完成多少条(noend)-->  <p>共有{{prolist.length}}个目标,{{noend==0?"全部完成了":'已完成'+(prolist.length-noend)+',还有'+noend+'条未完成'}}</p></code></pre>    <pre>  <code class="language-html"><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></code></pre>    <p>js</p>    <pre>  <code class="language-html">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;      }  });</code></pre>    <p>运行结果</p>    <p><img src="https://simg.open-open.com/show/7046c3c9f40736bb8e118a6b359a8d7c.gif"></p>    <h3>步骤4</h3>    <p>文字双击会出现输入框,可输入文字,如果回车或者失去焦点,就改变文字,如果按下ESC就恢复原来的文字</p>    <p><img src="https://simg.open-open.com/show/3f29bc23f564012bf2d7bdd96b5dcd59.png"></p>    <p>首先.双击出现输入框,就是双击文字后,给当前的li设置一个类名(‘ eidting ’),然后写好样式。当li出现这个类名的时候,就出现输入框,并且隐藏其它内容。</p>    <p>然后.回车或者失去焦点,就改变文字这个只需要操作一个,就是把类名(‘ eidting ’)清除掉。然后输入框就会隐藏,其它内容显示!</p>    <p>最后.按下ESC就恢复原来的文字,就是出现输入框的时候,用一个变量(‘ beforeEditText ’)先保存当前的内容,然后按下了ESC,就把变量(‘ beforeEditText ’)赋值给当前操作的值!</p>    <p>代码如下:</p>    <p>html</p>    <pre>  <code class="language-html"><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></code></pre>    <p>css(加上)</p>    <pre>  <code class="language-html">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;}</code></pre>    <p>js</p>    <pre>  <code class="language-html">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="";          }   },</code></pre>    <p>运行结果</p>    <p><img src="https://simg.open-open.com/show/20c49be740e745c8d8182d453caaa6f7.gif"></p>    <p>还有一个小细节,大家可能注意到了,就是双击文字,出来输入框的时候,还要自己手动点击一下,才能获得焦点,我们想双击了,输入框出来的时候,自动获取焦点,怎么办?自定义指令就行了!</p>    <pre>  <code class="language-html">computed:{...},  methods:{...},  mounted(){...},  directives:{      "focus":{          update(el){              el.focus();          }      }  }</code></pre>    <p>然后html 调用指令</p>    <pre>  <code class="language-html"><input type="text" class="text2" v-model='list.name' @keyup.esc='cancelEdit(list)' @blur='edited' @focus='editBefore(list.name)' @keyup.enter='edited' v-focus/></code></pre>    <h3>完整代码</h3>    <pre>  <code class="language-html"><!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 .status-span{display: block;width: 10px;height: 10px;background: #ccc;margin: 14px 10px 0 0 ;float: left;}              li .status-span.status-end{                  background: #09f;              }              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 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;}              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="输入小目标后,按回车确认" @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="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' v-focus/>                  </li>              </ul>          </div>      </body>      <script src="vue2.4.2.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:""          },          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时,选择所有未完成目标                  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="";              }          },          mounted(){              //初始化,把prolist赋值给newList。默认显示所有目标              this.newList=this.prolist;          },          directives:{          "focus":{              update(el){                  el.focus();              }          }      }      });      </script>  </html></code></pre>    <h2>6.小结</h2>    <p>好了,三个小实例在这里就说完了!别看文章这么长,其实都是基础,可能是我比较啰嗦而已!如果大家能熟透这几个小实例,相信用vue做项目也是信手拈来。基础的语法在这里了,有了基础,高级的写法也不会很难学习!如果以后,我有什么要分享的,我会继续分享。最后一句老话,如果觉得我哪里写错了,写得不好,欢迎指点!</p>    <p> </p>    <p>来自:https://segmentfault.com/a/1190000010801357</p>    <p> </p>