Vue-Two-one

135 阅读7分钟

一 概念-为什么学习vue以及vue是什么?

  1. Angular 2. vue 3. React

Vue2 -> 稳定

  1. 最新长期稳定版 2.7.1 2016年9月 六年多 近140次版本更新
  2. 生态系统,文档系统完备
  3. 过往案例项目支撑

Vue3 -> 趋势

  1. 性能提升 => 1.2~2倍
  2. 内核体积更小=> 10kb
  3. TS支持度更高
  4. 组合式API,封装复用逻辑

Vue快速上手

Vue是什么

  • 概念:Vue是一个用于
  • 构建用户界面 1. 基于数据渲染出用户看到的页面
  • 的渐进式 2. 循序渐进
  • 框架 3. 一套完整的项目解决方案
  • 1-图片

image.png

  • 2-图片

image.png

  • 3-图片
  • 优点: 大大提升开发效率(70%)
  • 缺点: 需要理解记忆规则 - 官网

image.png

总结: Vue是一个用于 构建用户界面 的 渐进式 框架

  1. 构建用户界面: 基于 数据 动态 渲染 页面
  2. 渐进式: 循序渐进的学习
  3. 框架: 一套完整的项目的解决方案,提升开发效率(理解记忆规则)
  • 规则 - 官网

1 创建Vue实例,初始化渲染

image.png

V2: v2.cn.vuejs.org/

  • 学习-教程-安装-开发版本 在线链接:
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>

页面中显示:"你好"

<body>
  <!-- 
    目标: 使用 Vue 完成渲染
    创建Vue实例,初始化渲染
    1 准备容器(vue所管理的范围)
    2 引包(开发版本包 / 生产版本包)官网
    3 创建实例
    4 添加配置项 => 完成渲染
   -->
  <div>
    这里是非 vue 托管的区域: {{ msg }}
  </div>
  ------------------------------
  <div id="app">
    {{ msg }}
     <!-- 开发版本: 包含完整的警告和调试模式,学习阶段统一使用开发版本 -->
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    //  一旦引入了 vue 包,全局就会有一个 vue 构造函数
    // 3 创建实例
    // 4 添加配置项 => 完成渲染
    const app = new Vue({
      el:'#app',
      data:{
        msg:'你好!'
      }
    })
  </script>

总结: 创建 Vue实例,初始化渲染的核心步骤

  1. 准备容器
  2. 引包(官网) - 开发版本/生产版本
  3. 创建Vue实例 new Vue()
  4. 制定配置项 el data => 渲染数据
  • 4.1 el 指定挂载点,选择器指定控制的是哪个盒子
  • 4.2 data提供数据

2 插值表达式

  • 插值表达式{{}}
  • 插值表达式是一种vue的模板语法
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <!--
    目标: 使用插值表达式渲染数据到网页
    插值表达式:Vue的一种模板语法
    作用:利用表达式进行插值渲染
    语法:{{ 表达式 }}

    注意点:
      1. 使用的数据要存在
      2. 支持的是表达式,不是语句  if  for
      3. 不能在标签属性中使用 {{ }}
  -->
  <div id="app">
    <p>{{ nickname }}</p>
    <p>{{ nickname.substring(2) }}</p>
    <p>{{ age >=18 ? '成年' : '未成年'}}</p>
    <p>{{ fried.name }}{{ friend.desc }}</p>
    <!-- <p>{{ gender }}</p> -->
    <!-- 插值表示的类型没有,会报错 -->
    <!-- <p>{{if}}</p> -->
     <!-- <a href="{{ url}}">百度</a> -->
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        nickname: '紫阳道长',
        age: 18,
        friend: {
          name: '张三',
          desc: '热爱学习 Vue'
        }
      }
    })
  </script>
</body>

</html>
  1. 作用: 利用表达式进行插值,渲染到页面中
  • 表达式: 是可以被求职的代码,js引擎会将其计算出一个结果
  1. 语法: {{ 表达式 }}

image.png

  1. 注意点: 3.1 使用的数据必须存在(data)
    <!-- <p>{{ gender }}</p> -->

3.2 支持的是表达式,而非语句,比如: if for ...

    <!-- <p>{{if}}</p> -->

3.3 不能在表情属性中使用 {{}} 插值

 <!-- <a href="{{ url}}">百度</a> -->

总结:

  1. 插值表达式的作用是什么? 利用表达式进行插值,将数据渲染页面中
  2. 语法格式? {{ 表达式 }}
  3. 插值表达式的注意点
  • 3.1 使用的数据要存在 (data)
  • 3.2 支持的是表达式,而非语句 if..for
  • 3.3 不能在标签属性里面使用

3 响应式特性:

  • Vue核心特性: 响应式
  • 我们已经掌握了基础的模版渲染,其实除了基本的模版渲染,Vue背后还有做了大量工作。
  • 如何访问 or 修改? data中的数据,最终会被添加到实例上
  • 1 访问数据: "实例.属性名"
  • 2 修改数据: "实例.属性名" = "值"
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    {{ msg }}
    {{ count }}
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标: 理解响应式数据的特性
     * 好处: 程序员以后不用再操心视图如何渲染了,把精力全部放在操作
     * 数据上面,只要数据变化,视频会自动更新
     */
    const app = new Vue({
      el: '#app',
      data: {
        // 响应式数据 → 数据变化了,视图自动更新
        msg: '你好,黑马',
        count: 100
      }
    })
  </script>
</body>

</html>

Vue核心特性: 响应式 数据改变,视图会自动更新

image.png

  • 聚焦于数据 -> 数据驱动视图
  • 使用 Vue开发,关注业务的核心逻辑,根据业务修改数据即可

总结:

  1. 什么是响应式呢?
  • 数据改变,视图自动更新
  • 使用Vue开发 - 专注于业务核心逻辑 即可
  1. 如何访问或修改数据呢?
  • data中的数据,最终会被添加到实例上
  • 【0】 访问数据:"实例.属性名"
  • 【1】修改数据: "实例.属性名" ="值"

4 开发者工具-安装vue-devtools插件

安装Vue开发者工具: 装插件调试Vue应用

  1. 通过谷歌应用商城安装(国外网站)
  2. 极简插件: 下载 - 开发者模式 - 拖拽安装 - 插件详情允许访问文件

image.png

Vue指令

Vue指令 v-html

  • Vue会根据不同的[指令],针对标签实现不同的[功能]
  • 指令: 带有 v-前缀 的特殊 标签属性
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <div>
      {{ msg }}
    </div>
    <!-- v-html 设置元素的 innerHTML 
         v-html="表达式"
        注意: 如果使用了 v-html 则标签内不能再写内容了,会被v-html的结果覆盖掉 -->
    <div v-html="msg"></div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标:
     *   将带有标签的 msg 数据解析标签并渲染到 div 中
     */
    const app = new Vue({
      el: '#app',
      data: {
        msg: '<h1>学前端~来黑马!</h1>'
      }
    })

  </script>

</body>

</html>

总结:

  1. 什么是Vue指令呢?
  • 指令计算带有 v-前缀的特殊属性,不同属性对应 不同的功能
  • 学习不同指令 - 解决不同业务场景需求
  1. 如果需要动态解析标签,可以用哪个指令?语法?
  • v-html = "表达式" - 动态设置元素 innerHTML

Vue指令 v-show vs v-if

v-show

  1. 作用 控制元素显示隐藏
  2. 语法: v-show="表达式" 表达式值 true显示,flash隐藏
  3. 原理: 切换 display:none 控制显示隐藏
  4. 场景: 频繁切换显示隐藏的场景

v-if

  1. 作用: 控制元素显示隐藏(条件渲染)
  2. 语法: v-if="表达式" 表达式值 true显示,flase隐藏
  3. 原理: 基于条件判断,是否 创建 或 移除 元素节点
  4. 场景: 要么显示,要么隐藏,不频繁切换的场景

代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .box {
      width: 200px;
      height: 100px;
      line-height: 100px;
      margin: 10px;
      border: 3px solid #000;
      text-align: center;
      border-radius: 5px;
      box-shadow: 2px 2px 2px #ccc;
    }
  </style>
</head>

<body>
  <div id="app">
    <div v-show="isShow" class="box">我是v-show控制的盒子</div>
    <div v-if="isShow" class="box">我是v-if控制的盒子</div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标: 控制盒子显示隐藏
     *    v-show 底层原理: 通过设置 display:none 来改变合作的现实状态
     *    v-if   底层原理: 通过创建 / 删除 DOM 元素来实现合作的现实隐藏
     * 
     * 
     * v-show 比较适合频繁切换显示隐藏的场景
     * v-if 比较时候初始状态就决定了显示隐藏的场景
     * */
    const app = new Vue({
      el: '#app',
      data: {
        isShow:true
      }
    })
  </script>

</body>

</html>

Vue指令 v-else 和 v-else-if

1 作用: 辅助v-if 进行判断渲染 2 语法: v-else v-else-if="表达式"

image.png

v-else、v-else-if用法

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <div id="app">
    <!-- 
      v-if 和 v-else 注意事项
      v-else 必须紧贴着 v-if 来编写,中间不能有任何标签问题(注释除外)
     -->
    <p v-if="gender === 1">性别:♂ 男</p>
    <p v-else>性别:♀ 女</p>
    <hr>
    <p v-if="score >=90">成绩评定A:奖励电脑一台</p>
    <p v-else-if="score >= 70">成绩评定B:奖励周末郊游</p>
    <p v-else-if="score >= 60">成绩评定C:奖励零食礼包</p>
    <p v-else>成绩评定D:惩罚一周不能玩手机</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    // 目标:
    // 1. 根据条件渲染姓名
    // 2. 根据成绩来渲染奖励
    const app = new Vue({
      el: '#app',
      data: {
        gender: 1,
        score: 95
      }
    })
  </script>

</body>

</html>

Vue指令 v-on

1 作用: 注册事件 = 添加监听 + 提供处理逻辑 2 语法: 2.1 v-on:事件名="内联语句" 2.2 v-on:事件名="methods中的函数名" 3 简写: @事件名 4 注意: methods函数内的 this指向 Vue实例

<button v-on:click="count++">按钮</buttton>

1. v-on:事件名="内联语句"、用法

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <!-- 
      v-on 语法
      v-on:事件名="内联代码" 适合机器简单的场景,一行代码就搞定
      v-on:事件名="事件除了函数" 适合复杂的逻辑处理

      简写:
      v-on: => @
     -->
    <button v-on:click="count--">-</button>
    <span>{{ count }}</span>
    <button @click="count++">+</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    // 目标: 点击 - 让数字减一, 点击 + 让数字加一
    const app = new Vue({
      el: '#app',
      data: {
        count: 100
      }
    })
  </script>
</body>

</html>

2. v-on:事件名="methods中的函数名"、用法

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <button @click="change">切换显示隐藏</button>
    <h1 v-show="isshow">黑马程序员</h1>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标:
     *    点击切换 h1 标签显示隐藏
     * 思路:
     * 1 定义 isshow 变量,默认值为 true
     * 2 使用 v-show 控制 h1 标签的现实隐藏
     * 3 给 button 绑定点击事件, 对 isshow变量进行取反
     */
    const app = new Vue({
      el: '#app',
      data: {
        isshow:true
      },
      // methods 中存放函数
      // 只要定义在 methods 中的函数,最终都会放到实例对象上,所以内部的 this 指向实例对象
      
      methods:{
        change(){
          console.log('我被点了')
          this.isshow = !this.show
        }
      }
    })
  </script>
</body>

</html>

3 v-on 调用传参

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .box {
      border: 3px solid #000000;
      border-radius: 10px;
      padding: 20px;
      margin: 20px;
      width: 200px;
    }

    h3 {
      margin: 10px 0 20px 0;
    }

    p {
      margin: 20px;
    }
  </style>
</head>

<body>

  <div id="app">
    <div class="box">
      <h3>小黑自动售货机</h3>
      <!-- 
        v-on 事件处理函数传参:
        @click="事件处理函数(实参)"

        注意: 即便加了 () 也不是调用函数,依然是绑定事件处理函数,函数依然在事件触发时
        才会执行,执行时会携带参数过去

       -->
      <button @click="buy(5)">可乐5元</button>
      <button @click="buy(10)">咖啡10元</button>
    </div>
    <p>银行卡余额:{{ money }}元</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标:
     *  点击不同按钮, 银行卡余额减少对应的金额
     */
    const app = new Vue({
      el: '#app',
      data: {
        money: 100
      },
      methods:{
         but(price){
          this.money -= price
         }
      }
    })
  </script>
</body>

</html>

Vue指令 v-bind

  1. 作用 动态的设置html的标签属性 src url title
  2. 语法 v-bind: 属性名="表达式"
  3. 注意: 简写形式 :属性名="表达式"
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <!-- 
      v-bind: 动态设置标签属性的
      v-bind: 属性名="表达式"

      支持简写:
      :属性名="表达式"
     -->
     <!-- <img v-bind:src="imgUrl"  v-bind:title="msg" alt=""> -->
    <img :src="imgUrl" :title="msg" alt="">
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标:
     *  使用 v-bind 指令动态绑定标签属性
     */
    const app = new Vue({
      el: '#app',
      data: {
        imgUrl: './imgs/10-02.png',
        msg: 'hello 波仔'
      }
    })

  </script>
</body>

</html>

案例-波仔的学习之旅

图片切换案例-波仔学习之旅 核心思路分析

  1. 数组 存储图片路径 - 【图片1,图片2,图片3】
  2. 准备下标 index,数组【下标】 - v-bind 设置 src展示图 - 修改下标切换图片

image.png

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <button v-show="index > 0" @click="index--" >上一页</button>
    <div>
      <img :src="list[index]" alt="">
    </div>
    <button v-show="index < list.length -1" @click="index++">下一页</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标: 点击按钮切换图片, 如果到第一张就不显示上一页按钮, 如果到最后一张就不显示下一页按钮
     * 思路:
     *  1. 定义一个变量当做数组索引
     *  2. 使用 v-bind 绑定 img 的 src 为 list[index]
     *  3. 点击按钮操作 index 值即可
     *  4. 使用 v-show 控制上一页和下一页按钮显示隐藏
     */
    const app = new Vue({
      el: '#app',
      data: {
        index:0,
        list: [
          './imgs/11-00.gif',
          './imgs/11-01.gif',
          './imgs/11-02.gif',
          './imgs/11-03.gif',
          './imgs/11-04.png',
          './imgs/11-05.png',
        ]
      },
      methods:{

      }
    })
  </script>
</body>

</html>

Vue 指令 v-for

1 作用: 基于数据循环,多次渲染整个元素 - 数组、对象、数字

<p v-for="">我是一个内容</p> 

2 遍历数组语法:

  • v-for="(item.index) in 数组"
  • item 每一项,index下标
  • 省略index: v-for="item in 数组"
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <div id="app">
    <h3>小黑水果店</h3>
    <ul>
      <!-- 
        v-for 写在 li 上就是重复渲染 li
        语法:
        v-for="(每一项,索引) in 数组"
       -->
      <li v-for="(item,index) in list">{{item}} --- {{index}}</li>
    </ul>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标: 使用 v-for 循环渲染 li
     */
    const app = new Vue({
      el: '#app',
      data: {
        list: ['西瓜', '苹果', '鸭梨', '榴莲']
      }
    })
  </script>
</body>

</html>

显示效果:

image.png

图书管理案例-小黑的书架

明确需求

  1. 基本渲染 - v-for
  2. 删除功能 - 用 filter 根据 id从数组中删除对应项
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <div id="app">
    <h3>小黑的书架</h3>
    <ul>
      <li v-for="item in booksList" >
        <span>{{item.name}}</span>
        <span>{{item.author}}</span>
        <button @click="del(item.id)">删除</button>
      </li>
    </ul>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标:
     *  1. 渲染书籍信息
     *  2. 实现删除功能
     * 
     * 思路:
     *  1. 使用 v-for 循环渲染 li
     *  2. 使用 v-on 给删除按钮绑定点击事件
     *  3. 点击后传入 id
     *  4. 根据 id 删除数据
     */
    const app = new Vue({
      el: '#app',
      data: {
        booksList: [
          { id: 1, name: '《红楼梦》', author: '曹雪芹' },
          { id: 2, name: '《西游记》', author: '吴承恩' },
          { id: 3, name: '《水浒传》', author: '施耐庵' },
          { id: 4, name: '《三国演义》', author: '罗贯中' }
        ]
      },
      methods:{
        del(id){
          // 根据 id 找到索引,根据索引删除元素
          // forEach map reduce find findIndex
          // const index = this.booksList.findIndex(item => item.id === id)
          // this.booksList.splice(index,1)

          // 2 filter 筛选不符合 id 的元素,把新数组覆盖回老数组
          this.booksList = this.booksList.filter(item => item.id !== id)
        }
      }
    })
  </script>
</body>

</html>

v-for中的key

key的作用:

给元素添加唯一标识,便于Vue进行列表项的正确排序复用

注意点:

  1. key的值只能是 字符串 或 数字类型
  2. key 的值必须具有 唯一性
  3. 推荐使用 id 作为key(唯一),不推荐使用 index 作为 key (会变化,不对应)
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <div id="app">
    <h3>小黑的书架</h3>
    <ul>
      <!-- 
        复用: vue不好轻易删除 DOM 并重新创建 DOM,因为这样很消耗性能,它会想尽
        一切办法去的销毁 DOM
        v-for 的默认复用策略: 就地更新,当前删除一个元素后,还剩3个 li,那么 vue
        就会把最后一个 li 删除,里面的内容平移,以复用所以现存的li
        
        v-for时建议加上 key属性,一般用唯一标识: id
        key的设置要求:
        1 一定要在当前v-for 中唯一
        2 必须是 string 或 number
       -->
      <li v-for="(item, index) in booksList" :key="item.id">
        <span>{{ item.name }}</span>
        <span>{{ item.author }}</span>
        <button @click="del(item.id)">删除</button>
      </li>
    </ul>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标: 理解 v-for 中 :key 的作用
     */
    const app = new Vue({
      el: '#app',
      data: {
        booksList: [
          { id: 1, name: '《红楼梦》', author: '曹雪芹' },
          { id: 2, name: '《西游记》', author: '吴承恩' },
          { id: 3, name: '《水浒传》', author: '施耐庵' },
          { id: 4, name: '《三国演义》', author: '罗贯中' }
        ]
      },
      methods: {
        del(id) {
          this.booksList = this.booksList.filter(item => item.id !== id)
        }
      }
    })
  </script>
</body>

</html>

Vue指令 v-model

1 作用: 给表单元素 使用。双向数据绑定-可以快速 获取 或 设置 表单元素内容

  • 1.1 数据变化 - 视频自动更新
  • 1.2 视图变化 - 数据自动更新
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <div id="app">
    <!-- 
      v-model 可以让数据和视图,形成双向数据绑定
        1. 数据变化,视图自动更新
        2. 视图变化,数据自动更新
      可以快速获取或设置表单元素的内容
     -->
    账户:<input type="text" v-model="username"> <br><br>
    密码:<input type="password" v-model="password"><br><br>
    <button @click="login">登录</button>
    <button @click="reset">重置</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标: 理解 v-model 的使用
     *  1. 使用 v-model 双向绑定用户名和密码
     *  2. 点击登录时直接获取用户名密码数据
     *  3. 点击重置时直接重置用户名和密码
     */
    const app = new Vue({
      el: '#app',
      data: {
        username:'zhangsan',
        password:'123456'
      },
      methods: {
        login(){
          console.log(this.username,this.password);
        },
        reset(){
          this.password=""
          this.username=""
        }

      }
    })
  </script>
</body>

</html>

综合案例-小黑记事本

功能需求:

  • ① 列表渲染
  • ② 删除功能
  • ③ 添加功能
  • ④ 底部统计 和 清空

第一步、删除and渲染功能

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="stylesheet" href="./css/index.css" />
  <title>记事本</title>
</head>

<body>

  <!-- 主体区域 -->
  <section id="app">
    <!-- 输入框 -->
    <header class="header">
      <h1>小黑记事本</h1>
      <input placeholder="请输入任务" class="new-todo" />
      <button class="add">添加任务</button>
    </header>
    <!-- 列表区域 -->
    <section class="main">
      <ul class="todo-list">
        <li class="todo" v-for="(item,index) in list" :key="item.id ">
          <div class="view">
            <span class="index">{{index+1}}</span> <label>{{item.name}}</label>
            <button class="destroy" @click="del(item.id)"></button>
          </div>
        </li>
      </ul>
    </section>
    <!-- 统计和清空 -->
    <footer class="footer">
      <!-- 统计 -->
      <span class="todo-count">合 计:<strong> 1 </strong></span>
      <!-- 清空 -->
      <button class="clear-completed">
        清空任务
      </button>
    </footer>
  </section>

  <!-- 底部 -->
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标1  列表渲染
     * 1.1 使用 v-for 循环渲染 list
     * 1.2 设置 :key
     * 1.3 使用索引作为序号
     * 
     * 
     * 目标2 删除功能
     * 2.1 给小叉叉绑定点击事件
     * 2.2 传入id
     * 2.3 使用 filter 筛选删除
     */

    const app = new Vue({
      el: '#app',
      data: {
        list: [
          { id: 1, name: '跑步一公里' },
          { id: 2, name: '打球一小时' },
          { id: 3, name: '游泳100米' },
        ]
      },
      // 删除 按钮
      methods:{
        del(id){
      this.list = this.list.filter(item => item.id !== id)
      }
      }
    
    })

  </script>
</body>

</html>

第二步-添加功能

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="stylesheet" href="./css/index.css" />
  <title>记事本</title>
</head>

<body>

  <!-- 主体区域 -->
  <section id="app">
    <!-- 输入框 -->
    <header class="header">
      <h1>小黑记事本</h1>
      <input placeholder="请输入任务" class="new-todo" v-model="taskname"/>
      <button class="add" @click="add">添加任务</button>
    </header>
    <!-- 列表区域 -->
    <section class="main">
      <ul class="todo-list">
        <li class="todo" v-for="(item,index) in list" :key="item.id ">
          <div class="view">
            <span class="index">{{index+1}}</span> <label>{{item.name}}</label>
            <button @click="del(item.id)" class="destroy"></button>
          </div>
        </li>
      </ul>
    </section>
    <!-- 统计和清空 -->
    <footer class="footer">
      <!-- 统计 -->
      <span class="todo-count">合 计:<strong> 1 </strong></span>
      <!-- 清空 -->
      <button class="clear-completed">
        清空任务
      </button>
    </footer>
  </section>

  <!-- 底部 -->
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标1  列表渲染
     * 1.1 使用 v-for 循环渲染 list
     * 1.2 设置 :key
     * 1.3 使用索引作为序号
     * 
     * 
     * 目标2 删除功能
     * 2.1 给小叉叉绑定点击事件
     * 2.2 传入id
     * 2.3 使用 filter 筛选删除
     * 
     * 目标3
     * 3.1 定义 taskname数据,使用 v-model双向数据绑定
     * 3.2 给添加任务按钮绑定点击事件
     * 3.3 匪口校验
     * 3.4 将数据组装后添加到数组的第一个元素
     * 3.5 清空文本框(给 taskname 赋值 空)
     */

    const app = new Vue({
      el: '#app',
      data: {
        list: [
          { id: 1, name: '跑步一公里' },
          { id: 2, name: '打球一小时' },
          { id: 3, name: '游泳100米' },
        ],
        taskname:''
      },
      // 删除 按钮
      methods:{
        del(id){
      this.list = this.list.filter(item => item.id !== id)
      },
      add(){
        if(this.taskname.trim() === '')return alert('请输入任务名称')
        // console.log(this.taskname);
        this.list.unshift({
          id: +new Date(),
          name:this.taskname
        })
        this.taskname = ""
      }
      }
    
    })

  </script>
</body>

</html>

第三步 底部统计、清空功能

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="stylesheet" href="./css/index.css" />
  <title>记事本</title>
</head>

<body>

  <!-- 主体区域 -->
  <section id="app">
    <!-- 输入框 -->
    <header class="header">
      <h1>小黑记事本</h1>
      <input placeholder="请输入任务" class="new-todo" v-model="taskname"/>
      <button class="add" @click="add">添加任务</button>
    </header>
    <!-- 列表区域 -->
    <section class="main">
      <ul class="todo-list" >
        <li class="todo" v-for="(item,index) in list" :key="item.id ">
          <div class="view">
            <span class="index">{{index+1}}</span> <label>{{item.name}}</label>
            <button @click="del(item.id)" class="destroy"></button>
          </div>
        </li>
      </ul>
    </section>
    <!-- 统计和清空  内容全部清空后 清空内容和内容多少隐藏-->
    <footer class="footer" v-show="list.length>0">
      <!-- 统计 -->
      <span class="todo-count">合 计:<strong> {{list.length}} </strong></span>
      <!-- 清空 -->
      <button class="clear-completed" @click="clear">
        清空任务
      </button>
    </footer>
  </section>

  <!-- 底部 -->
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标1  列表渲染
     * 1.1 使用 v-for 循环渲染 list
     * 1.2 设置 :key
     * 1.3 使用索引作为序号
     * 
     * 
     * 目标2 删除功能
     * 2.1 给小叉叉绑定点击事件
     * 2.2 传入id
     * 2.3 使用 filter 筛选删除
     * 
     * 目标3
     * 3.1 定义 taskname数据,使用 v-model双向数据绑定
     * 3.2 给添加任务按钮绑定点击事件
     * 3.3 匪口校验
     * 3.4 将数据组装后添加到数组的第一个元素
     * 3.5 清空文本框(给 taskname 赋值 空)
     * 
     * 
     * 目标4 清空任务和底部统计
     * 4.1 底部统计计算 list.length
     * 4.2 清空任务计算给list 赋值为空数组
     * 4.3 使用 v-show 控制底部的显示隐藏
     */

    const app = new Vue({
      el: '#app',
      data: {
        list: [
          { id: 1, name: '跑步一公里' },
          { id: 2, name: '打球一小时' },
          { id: 3, name: '游泳100米' },
        ],
        taskname:''
      },
      // 删除 按钮
      methods:{
        del(id){
      this.list = this.list.filter(item => item.id !== id)
      },
      add(){
        if(this.taskname.trim() === '')return alert('请输入任务名称')
        // console.log(this.taskname);
        this.list.unshift({
          id: +new Date(),
          name:this.taskname
        })
        this.taskname = ""
      },
      clear(){
        this.list = []
      }
      }
    
    })

  </script>
</body>

</html>