Vue2 Day1-Day2

204 阅读12分钟

定义

Vue是一个用来构建用户界面的渐进式框架

创建Vue实例 初始化渲染步骤:

  1. 准备容器(Vue管理的范围)
  2. 引包(官网)——开发版本/生产版本
  3. 创建实例
  4. 指定配置项——渲染数据
    • el指定挂裁点
    • data 提供数据
<div id="app">
//将来会编写一些用来渲染的代码逻辑
{{msg}}
</div>
//引入开发版本的包-包含完整的注释和警告
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
  //一旦引入VueJS核心包,在全局环境就有了Vue构造函数
  
  const app = new Vue({
  //通过el去配置选择器,指定Vue管理的是哪个盒子
  el'#app',
  //通过data提供数据
   data:{
              msg:'Hello 黑马'
          }
</script>

vue目录

image.png

nose_modules 是通过npm instal 来安装

文本插值

最基本的数据绑定形式就是文本插值,他使用的是"Mustache"语法(即大括号)

<template>
  <p>{{msg}}</p>
</template>

<script>
export default {
  data(){
     return{
       msg:"神奇的魔法"
     }
  }
}
</script>

使用JavaScript表达式

每个绑定仅支持 单一表达式 ,也就是一段能求值的javaScript代码。

简单判断方法:是否可以合法的写在return后面

插值表达式

  1. 作用:利用表达式进行插值,渲染到页面中
  2. 语法:{{表达式}}
<h3>{{title}}<h3>

<p>{{nickName.toUpperCase()}}</p>

<p>{{age >= 18 ? '成年':'未成年'}}</p>

<p>{{obj.name}}</p>

<p>{{fn()}}</p>

注意:

  1. 使用的数据要存在
  2. 支持的是表达式,不是语句 如if,for
  3. 不能在标签属性中使用{{}}
  4. 不具备解析标签的能力

Vue 核心特性:响应式

数据改变,视图自动更新

访问和修改数据:

访问数据: 实例.属性名

修改数据:实例.属性名="值"

Vue指令

指令:带有v-前缀的特殊标签属性

Vue 中的指令按照不同的用途可以分为如下 6 大类:

  • 内容渲染指令(v-html、v-text)
  • 条件渲染指令(v-show、v-if、v-else、v-else-if)
  • 事件绑定指令(v-on)
  • 属性绑定指令 (v-bind)
  • 双向绑定指令(v-model)
  • 列表渲染指令(v-for)

v-show VS v-if

v-show

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

v-if

  1. 作用:控制元素显示隐藏(条件渲染)
  2. 语法:v-if="表达式" 表达式值 true显示,false 隐藏
  3. 场景:要么显示,要么隐藏,不频繁切换的场景
  4. 原理:基于判断条件 控制元素的创建和移除
     <div id="app">
       <div class="box">我是v-show控制的盒子</div>
       <div class="box">我是v-if控制的盒子</div>
     </div>

     <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
     <script>
       const app = new Vue({
         el: '#app',
         data: {
           flag: false
         }
       })
     </script>

区别:

  • v-show 元素无论初始条件如何始终都会被渲染 底层原理:切换CSS中的display:none来控制隐藏(简单隐藏)

  • v-show有较高的初始渲染开销

  • v-if 有较高的切换开销

  • v-if 底层原理:根据判断条件 控制元素的创建和移除(条件渲染) 只有为true时才会渲染

v-else v-else-if

  1. 作用:辅助v-if进行判断渲染

  2. 语法:v-else v-else-if = "表达式"

  3. 注意:需要紧挨着v-if一起使用

  <div id="app">
    <p>性别:♂ 男</p>
    <p>性别:♀ 女</p>
    <hr>
    <p>成绩评定A:奖励电脑一台</p>
    <p>成绩评定B:奖励周末郊游</p>
    <p>成绩评定C:奖励零食礼包</p>
    <p>成绩评定D:惩罚一周不能玩手机</p>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>

    const app = new Vue({
      el: '#app',
      data: {
        gender: 2,
        score: 95
      }
    })
  </script>

v-on(内联事件处理器)

  1. 作用:注册事件 = 添加监听+提供处理逻辑
  2. 语法:
    • v-on:事件名 ="内联语句"
    • v-on:事件名= "methods中的函数名"
  <div id="app">
      <button @click="count--">-</button>
      <span>{{ count }}</span>
      <button v-on:click="count++">+</button>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          count: 100
        }
      })
    </script>

v-on:事件名 可替换为@事件名

注:data用来提供数据,methods用来提供方法

<div id="app">
       <button @click = "fn">切换显示隐藏</button>
       <h1 v-show ="isShow">黑马程序员</h1>
      
        </div>
       
        <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
        <script>
          
          
          const app = new Vue({
         
          el:'#app',
          data:{
             isShow:true

          },
          methods:{
            fn(){
                // 让提供的所有methods中的函数,this指向当前案例
                // console.log('执行力fn')
                // console.log(app3 === this)
                this.isShow = !this.isShow
            }

          }
          })
        </script>

注:

  • 内联语句可以直接访问到数据,函数不可直接拿数据

  • 可通过methods,methods函数内的this指向Vue实例

  • methods与datas 同级

v-on 调用传参

<button @click="fn(参数1,参数2)">按钮</button>

示例:小黑自动售货机

 .box {
      border: 3px solid black;
      border-radius: 10px;
      padding: 20px;
      margin: 20px;
      width: 200px;
    }
    h3 {
      margin: 10px 0 20px 0;
    }
    p {
      margin: 20px;
    }
<div id="app">
        <div class="box">
          <h3>小黑自动售货机</h3>
          <button @click="buy(5)">可乐5元</button>
          <button @click="buy(10)">咖啡10元</button>
          <button @click="buy(8)">牛奶8元</button>
        </div>
        <p>银行卡余额:{{ money }}元</p>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            money: 100
          },
          methods:{
            buy(price){
                console.log(price)
                this.money -= price
            }
          }
        })
      </script>

效果如下:

image.png

v-bind

  1. 作用:动态设置的html的标签属性 src url title
  2. 语法:v-bind:属性名= "表达式"
  • <img v-bind:src="url" />
  • <img :src="url" /> (v-bind可以省略)

v-bind 指令知识Vue将元素的id attribute 与组建的dynamicid 属性保持一致,如果绑定的的是 null 或者 undefined ,那么改attribute 将会从渲染的元素上移除

  <div id="app">
    <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/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        imgUrl: './imgs/10-02.png',
        msg: 'hello 波仔'
      }
    })
  </script>

示例:波仔的学习之旅

要求:默认展示数组中的第一张图片,点击上一页下一页来回切换数组中的图片

实现思路:

1.数组存储图片路径 ['url1','url2','url3',...]

2.可以准备个下标index 去数组中取图片地址。

3.通过v-bind给src绑定当前的图片地址

4.点击上一页下一页只需要修改下标的值即可

5.当展示第一张的时候,上一页按钮应该隐藏。展示最后一张的时候,下一页按钮应该隐藏

 <div id="app">
    <button v-show"index >0" @click="index--">上一页</button>
    <div>
      <img src ="list[index]"alt="">
    </div>
    <button v-show <list.length -1 @click="index++" >下一页</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    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',
          
        ]
      }
    })
  </script>

v-for

  1. 作用:基于数据循环,多次渲染整个元素

  2. 可遍历:数组,对象,数字……

  3. 语法:v-for="(item,index) in 数组"

    • item 每一项,index 下标

效果图如下:

image.png

示例:

<div id="app">
      <h3>小黑水果店</h3>
     <ul>
      <li v-for="item in list">
        {{item}}
      </li>
      
     </ul>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
         list:['西瓜','苹果','椰子']
         
        
      }
    })
  </script>

省略index : v-for="item in 数组"

效果如下:

image.png

示例:小黑的书架

核心:列表渲染和删除功能

 <div id="app">
      <h3>小黑的书架</h3>
    <ul>
      <li v-for="(item,index) in booklist" :key="item.list">
       
        <span>{{item.name}}</span>
        <span>{{item.author}}</span>
        
        <button @click ="del(item.id)">删除</button>
      </li>
      <!-- 注册点击事件 通过id进行删除数组中的对应项 -->
    </ul>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
         booklist:[
          {id:1,name:'《红楼梦》',author:'曹雪芹'},
          {id:2,name:'《西游记》',author:'吴承恩'},
          {id:3,name:'《水浒传》',author:'施耐庵'},
          {id:4,name:'《三国演义》',author:'罗贯中'},
         ]
      },
      methods:{
        del(id){
          // console.log('删除',id)
          // 通过id 进行删除数组中的对应项——filter(不改变原数组)
          //filter:根据条件,保留满足条件的对应项,得到一个新数组
          
        //  console.log(this.booklist.filter (item => item.id!==id))
        this.booklist= this.booklist.filter (item => item.id!==id)
        }
      }
    })
  </script>

效果如下: 通过删除按钮可以将这一行内容删除

image.png

v-for中的key

  1. 作用:给列表项添加唯一的标识,便于Vue进行列表项的正确排序复用
  2. 语法:key属性 = "唯一的标识"

加key时:给元素添加了唯一标识,点击删除时 li中所有内容全部删除

未加key时:

  • v-for的默认行为会尝试 原地修改元素(就地复用)
  • 不加key则没有唯一标识,当删除时,会保留前三个而删除最后一个

key注意:

  • key的值只能是字符串数字类型
  • key的值必须具有 唯一性
  • key绑定的值期望是一个基础类型的值,如 字符串或number类型
  • 推荐使用 id 作为key(唯一),不推荐使用index 作为key(会变化,不对应)

v-model

  1. 作用: 给 表单元素(input、radio、select)使用,双向绑定数据,可以快速 获取设置 表单元素内容

  2. 语法:v-model="变量"

  3. v-model可以让数据和视图,形成双向数据绑定

  • 数据变化,视图自动更新
  • 视图变化,数据自动更新
  • 可以快速获取或设置表单元素的内容

示例:

需求:使用双向绑定实现以下需求

  • 点击登录按钮获取表单中的内容
  • 点击重置按钮清空表单中的内容
<div id="app">
    账户:<input type="text"> <br><br>
    密码:<input type="password"> <br><br>
    <button @click ="login">登录</button>
    <button @click ="reset">重置</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: '',
        password: ''
      },
      methods:{
        login(){
        console.log(this.username,this.password)
        },
        reset(){
        this.username = ''
        this.password = ''
        }
      }
    })
  </script>

效果如下:

image.png

指令修饰符

通过"." 指明后缀最,不同后缀封装了不同的处理操作——简化代码

1. 按键修饰符

  • @keyup.enter 键盘回车监听

2. v-model 修饰符

  • v-model.trim 去除首尾空格
  • v-model.number 转数字

3. 事件修饰符

  • @事件名.stop 阻止冒泡
  • @事件名.prevent 阻止默认行为
  • 在处理事件时调用event.prenventDfault()event.stopPropagation() 很常见

4.v-bind对于样式控制的增强

(1) 操作class

  • 语法: class="对象/数组"

对象:键就是类名,值是布尔值 如果为true 则有这个类 否则没有这个类

  • 适用场景:一个类名,来回切换
<div class="box":class="{类名1:布尔值,类名2:布尔值}">
</div>

数组:数组中所有的类都会添加到盒子上,本质就是一个class列表

  • 适用场景:批量添加或删除类

数组和对象嵌套过程中,只能是数组嵌套对象。不能相反,中括号里嵌套大括号

<div class="box":class="[类名1,类名2,类名3]">
</div>

示例:

.box{
    width:200px;
    height:200px;
    border:1px solid black;
    font-size: 30px;
    margin-top: 10px;
  }
  .pink{
    background-color: pink;
  }
  .big{
    width:300px;
    height: 300px;
  }
<div id="app">
    <div class="box":class="{pink:true,big:true}">黑马程序员</div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        
      }
      
    })
  </script>

效果如下:

此时pink与big都为true

image.png

案例:京东秒杀tab导航高亮

核心思路:

  1. 基于数据动态渲染tab v-for
  2. 准备下标记录高亮是哪一个tab activeindex
  3. 基于下标,动态控制class类名 v-bind;class
 * {
      margin: 0;
      padding: 0;
    }
    ul {
      display: flex;
      border-bottom: 2px solid #e01222;
      padding: 0 10px;
    }
    li {
      width: 100px;
      height: 50px;
      line-height: 50px;
      list-style: none;
      text-align: center;
    }
    li a {
      display: block;
      text-decoration: none;
      font-weight: bold;
      color: #333333;
    }
    li a.active {
      background-color: #e01222;
      color: #fff;
    }
  <div id="app">
  <ul>
    <li v-for="{item,index} in list":key="item.id"@click="activeindex">
      <a:class="{active:index === activeindex}"href="#">{{item.name}}</a>
    </li>
    
  </ul>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        activeindex:0,
        // 记录高亮
        list:[
           { id:1,name:'京东秒杀'},
           { id:2,name:'每日特价'},
           { id:3,name:'品类秒杀'}
        ]
      }
      
    })
  </script>

(2) 操作style

  • 语法::style="样式对象"
<div class="box" :style="{CSS属性名1:CSS属性值,CSS属性名2:CSS属性值}">
</div>

示例:

<style>
    .box {
      width: 200px;
      height: 200px;
      background-color: rgb(187, 150, 156);
    }
 </style>
 <div id="app">
    <div class="box"></div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {

      }
    })
  </script>

示例:进度条

 <style>
    .progress {
      height: 25px;
      width: 400px;
      border-radius: 15px;
      background-color: #272425;
      border: 3px solid #272425;
      box-sizing: border-box;
      margin-bottom: 30px;
    }
    .inner {
      width: 50%;
      height: 20px;
      border-radius: 10px;
      text-align: right;
      position: relative;
      background-color: #409eff;
      background-size: 20px 20px;
      box-sizing: border-box;
      transition: all 1s;
    }
    .inner span {
      position: absolute;
      right: -20px;
      bottom: -25px;
    }
  </style>

<div id="app">
    <!-- 外层盒子底色 (黑色) -->
    <div class="progress">
    <!-- 内层盒子 进度(蓝色) -->
      <div class="inner":style="{width:percent + '%'}">
        <span>{{percent}}%</span>
      </div>
    </div>
    <button @click="percent = 25">设置25%</button>
    <button @click="percent = 50>设置50%</button>
    <button @click="percent = 75>设置75%</button>
    <button @click="percent = 100>设置100%</button>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
         percent:30
      }
    })
  </script>

style绑定的权重很高 ,后期修改麻烦 建议使用class

v-model应用于其他表单元素

  1. 作用:快速获取或设置表单元素的值

  2. 会根据控件类型自动灭火选取正确的方法来更新元素

image.png

示例:


<style>
   *{
    margin:0;
    padding: 0;

   }
   ul{
    display: flex;
    background-color: red;

   }
   li{
    list-style: none;
    color: white;
    width: 100px;
    height:50px;
    line-height: 50px;
    text-align: center;

  }
 
</style>

<body>
    
  <div id="app">
     <h3>小黑学习网</h3>
     姓名:
    <input type="text" v-model="useername">
    <br><br>
    是否单身:
      <input type="checkbox" v-model="isSingle"> 
      <br><br>
       <!-- 前置理解:
        1. name:  给单选框加上 name 属性 可以分组 → 同一组互相会互斥
        2. value: 给单选框加上 value 属性,用于提交给后台的数据
      结合 Vue 使用 → v-model
    -->
      性别: 
      <input v-model="gender"type="radio"name="gender" value="1"><input v-model="gender"type="radio"name="gender" value="2"><br><br>
      <!-- 
      前置理解:
        1. option 需要设置 value 值,提交给后台
        2. select 的 value 值,关联了选中的 option 的 value 值
      结合 Vue 使用 → v-model
    -->
      所在城市:
      <select v-model="cityId">
        <option value="101">北京</option>
        <option value="102">上海</option>
        <option value="103">成都</option>
        <option value="104">南京</option>
      </select>
      <br><br>
    自我描述:
      <textarea v-model="desc"></textarea> 
    <button>立即注册</button>

  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
       username:'',
       isSingle:false,
       gender:"1",
       cityId:'102',
       desc:""
      }
      
    })
  </script>

效果如下:

image.png

数组变化侦测

1.变更方法

变更方法:会对调用他们的原数组进行变更 image.png

2.替换一个数组

有一些不可变的方法,如 filter() ,concat()slice(),这些都不会更改原数组而总是返回一个新数组。当遇到非变更方法时,我们需要将旧的数组替换为新的

计算属性

  1. 基于现有数据,计算出新属性,依赖的数据变化会自动重新计算
  2. 语法
  • 声明在computed配置项中,一个计算属性对应一个函数
  • 使用起来和普通属性一样使用{{计算属性名}}
<style>
 
    table {
      border: 1px solid #000;
      text-align: center;
      width: 240px;
    }
    th,td {
      border: 1px solid #000;
    }
    h3 {
      position: relative;
    }
  </style>
 
</style>

<body>
  <div id="app">
    <h3>小黑的礼物清单</h3>
    <table>
      <tr>
        <th>名字</th>
        <th>数量</th>
      </tr>
      <tr v-for="(item, index) in list" :key="item.id">
        <td>{{ item.name }}</td>
        <td>{{ item.num }}个</td>
      </tr>
    </table>

    <!-- 目标:统计求和,求得礼物总数 -->
    <p>礼物总数{{totalCount}}个</p>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        // 现有的数据
        list: [
          { id: 1, name: '篮球', num: 1 },
          { id: 2, name: '玩具', num: 2 },
          { id: 3, name: '铅笔', num: 5 },
        ]
      },
      computed:{
        totalCount(){
          let total = this.list.reduce((sum,item) => sum+item.num,0)
          return total
        }
      }
    })
  </script>
 
     

效果如下:

image.png

computed计算属性 VS methods方法

computed计算属性

作用:封装了一段对于 数据 的处理,求得一个结果

语法:

  1. 写在computed配置项中

  2. 作为属性,直接使用

    • js中使用计算属性: this.计算属性
    • 模板中使用计算属性:{{计算属性}}

计算属性有缓存,一旦计算出结果就会立刻缓存 下一次读取-直接读缓存-性能高

methods计算属性

作用:给Vue实例提供一个 方法,调用以处理业务逻辑

语法:

  1. 写在methods配置项中
  2. 作为方法调用
    • js中调用:this.方法名()
    • 模板中调用 {{方法名()}} 或者 @事件名=“方法名”

注意:

  1. computed配置项和data配置项是同级
  2. computed中的计算属性虽然是函数的写法,但他依然是个属性
  3. computed中的计算属性不能和data中的属性同名
  4. 使用computed中的计算属性和使用data中的属性是一样的用法
  5. computed中计算属性内部的this依然指向的是Vue实例

重点区别:

  • 计算属性值会基于其他响应式依赖被缓存,一个计算属性仅会在其响应式以来更新时才重新计算 多次调用的值是一次计算的

  • 方法调用总是会在重渲染发生时再次执行函数 调用四次,计算属性也计算四次

  • 复杂的逻辑使用计算属性更好

计算属性完整写法

image.png