Vue基础知识(一)

64 阅读7分钟

vue基础

vue是什么

渐进式的JavaScript框架,拥有一套自己规则的语法

官网地址(作者:尤雨溪)

  1. 渐进式概念

    • 生活里的渐进式

      逐渐进步,想什么就用什么,不必全都使用

    • Vue渐进式

      Vue从基础开始, 会循序渐进向前学习, 如下知识点可能你现在不明白, 但是学完整个vue回过头来看, 会很有帮助

      渐进式-1613206784433.png

什么是库和框架

库:封装的属性和方法(例如jquery.js)

框架:拥有自己的规则元素,比库强大的多(例vue.js)

image-20210111215624065.png

@vue/cli脚手架

1. @vue/cli脚手架介绍

webpack自己配置环境很麻烦,下载@vue/cli包,用vue命令创建脚手架搭建项目

  • ​ @vue/cli是vue官方提供的一个全局模块包(得到vue命令),此包创建于脚手架

    脚手架是为了保证各施工过程顺利进行而搭建的工作平台

@vue/cli的好处

  • 开箱即用
  • 0配置webpack
  • babel支持
  • css,less支持
  • 开发服务器支持

2.@vue/cli安装

把@vue/cli模块包安装到全局,电脑拥有vue名利,才能创建脚手架工程

  • 全局安装命令

    npm install -g @vue/cli
    

    注意:如果半天没有动静(大多数都是网速问题),可以ctrl+c

    1. ​ 停止重来
    2. 换一个网络继续重来
  • 查看vue脚手架版本

    vue -V  //如果出现版本号说明已经安装成功了
    

3.@vue/cli创建项目启动服务器

使用vue命令,创建脚手架项目,启动服务器

注意:项目名不能带大写字母,中文和特殊符号

  1. 创建项目

    vue create 项目名
    
  2. 选择模板

    可以上下箭头选择vue的版本,弄错了ctrl+c重来

image-20210116230221236.png

  1. 回车等待生成项目文件夹+文件+下载必须的第三方包们

image-20210212174314768.png

  1. 进入脚手架项目下,启动内置的热更新本地服务器

    cd 项目名
    npm run serve
    

    image.png 打开浏览器输入以上地址

    image-20210116233035582.png

4.@vue/cli目录和代码分析

 vuecil-demo        # 项目目录
    ├── node_modules # 项目依赖的第三方包
    ├── public       # 静态文件目录
      ├── favicon.ico# 浏览器小图标
      └── index.html # 单页面的html文件(网页浏览的是它)
    ├── src          # 业务文件夹
      ├── assets     # 静态资源
        └── logo.png # vue的logo图片
      ├── components # 组件目录
        └── HelloWorld.vue # 欢迎页面vue代码文件 
      ├── App.vue    # 整个应用的根组件
      └── main.js    # 入口js文件
    ├── .gitignore   # git提交忽略配置
    ├── babel.config.js  # babel配置
    ├── package.json  # 依赖包列表
    ├── README.md    # 项目说明
	└── yarn.lock    # 项目包版本锁定和缓存地址

主要文件及含义

node——modules 下都是下载的第三方包
public/index.html -浏览器运行的网页
src/main.js -webpack打包入口文件
src/App.vue -vue项目入口页面
package.json -依赖包列表文件

5.@vue/cli项目架构了解

image-20210317201811310.png

6.@vue/cli只定义配置

src并列处新建vue.config.js

module.exports = {
    //自定义服务配置
    devServer:{
        open:false, //是否自动打开浏览器
        port:8080 //端口号
    }
}

7.eslint了解

eslint是一个代码检查工具

例子:现在main.js随便声明变量,但不使用

image-20210326165406694.png 终端和页面都报错了 注意:这种错误,证明代码不够严谨

image-20210326165544865.png

image-20210326165606191.png

解决办法:

  1. 手动解决错误
  2. 在代码上方添加以下代码注释
 /* eslint-disable */
  1. 暂时关闭eslint检查,在vue.config.js中配置后重启服务器

    module.exports = {
        //...其他配置
        lintOnSave:false //关闭eslint检查
    }
    

8.@vue/cli单vue文件讲解

单vue文件好处,独立作用域互不影响

Vue推荐采用.vue文件来开发项目

template里只能有一个根标签

vue文件-独立模块作用域互不影响

style配合scoped属性,保证样式只针对当前template内标签生效

vue文件配合webpack,把他们打包起来插入到index.html

<!-- template必须, 只能有一个根标签, 影响渲染到页面的标签结构 -->
<template>
  <div>欢迎使用vue</div>
</template>

<!-- js相关 -->
<script>
export default {
  name: 'App'
}
</script>

<!-- 当前组件的样式, 设置scoped, 可以保证样式只对当前页面有效 -->
<style scoped>
</style>

vue指令

插值表达式

在dom标签中直接插入内容

又叫:声明式渲染/文本插值

语法:{{表达式}}

<template>
  <div>
    <h1>{{ msg }}</h1>
    <h2>{{ obj.name }}</h2>
    <h3>{{ obj.age > 18 ? '成年' : '未成年' }}</h3>
  </div>
</template>

<script>
export default {
  data() { // 格式固定, 定义vue数据之处
    return {  // key相当于变量名
      msg: "hello, vue",
      obj: {
        name: "小vue",
        age: 5
      }
    }
  }
}
</script>

<style>
</style>

注意:插值表达式不能写语句,函数

mvvm设计模式

用数据驱动视图改变, 操作dom的事, vue源码内干了

设计模式:是一套被反复使用,多人知晓,经过分类编目,代码设计经验分总结。

1.gif

  • mvvm,一种软件架构模式,决定了写代码的思想和层次
    • M:model数据模型 (data里定义)
    • V:view视图 (html页面)
    • VM:ViewModel视图模型(vue.js源码)
  • MVVM通过数据双向绑定让数据自动的双向同步 不需要操作DOM
    • V(修改视图)->M(数据自动同步)

    • M(修改数据)-> V(视图自动同步)

MVVM.png

在vue中,不推荐直手动操作DOM

在vue中,通过数据驱动视图,不要想着怎么操作DOM,而是想着如何操作数据

双向数据绑定.png

v-bind

给标签属性设置vue变量值

vue指令,实质就是特殊的HTML标签属性,特点:v-开头

  • 语法:v-bind:属性名='vue变量'

  • 简写::属性名='vue变量'

  • 代码示例

    <!-- vue指令 v-bind属性动态赋值-->
    <a v-bind:href='url'>我是a标签</a> // url是在data返回对象里的变量
    <img :src='imgSrc'>  //data里返回对象里的数据
    

v-on

给标签绑定事件

  • 语法
    • v-on:事件名="要执行的少量代码"
    • v-on:事件名='methods中的函数'
    • v-on:事件名='methods中的函数(实参)'
  • 简写:@事件名='methods中的函数'
<template>
  <div>
    <a @click="one" href="http://www.baidu.com">阻止百度</a>
    <hr>
    <a @click="two(10, $event)" href="http://www.baidu.com">阻止去百度</a>
  </div>
</template>

<script>
export default {
  methods: {
    one(e){
      e.preventDefault()
    },
    two(num, e){
      e.preventDefault()
    }
  }
}
</script>

v-on事件对象

vue事件处理函数中,拿到事件对象

  • 语法

    • 无传参,通过形参直接接收
    • 传参,通过$event指代事件对象传给事件处理函数
    <template>
      <div>
        <a @click="one" href="http://www.baidu.com">阻止百度</a>
        <hr>
        <a @click="two(10, $event)" href="http://www.baidu.com">阻止去百度</a>
      </div>
    </template>
    
    <script>
    export default {
      methods: {
        one(e){
          e.preventDefault()
        },
        two(num, e){
          e.preventDefault()
        }
      }
    }
    </script>
    

v-on修饰符

在事件后面,修饰符名-给事件带来更加强大的功能

  • 语法:

    • @事件名.修饰符='methods里函数'
      • .stop -阻止事件冒泡
      • .prevent -阻止默认行为
      • .once -程序运行期间,只触发一次事件处理函数
    <template>
      <div @click="fatherFn">
        <!-- vue对事件进行了修饰符设置, 在事件后面.修饰符名即可使用更多的功能 -->
        <button @click.stop="btn">.stop阻止事件冒泡</button>
        <a href="http://www.baidu.com" @click.prevent="btn">.prevent阻止默认行为</a>
        <button @click.once="btn">.once程序运行期间, 只触发一次事件处理函数</button>
      </div>
    </template>
    
    <script>
    export default {
      methods: {
        fatherFn(){
          console.log("father被触发");
        },
        btn(){
          console.log(1);
        }
      }
    }
    </script>
    

    总结:修饰符给事件扩展额外功能

v-on按键修饰符

给键盘事件,添加修饰符,增强能力

  • 语法:

    • @keyup.enter -监听回车按键
    • @keyup.esc -监听返回按键
    • 更多修饰符
    <template>
      <div>
        <input type="text" @keydown.enter="enterFn">
        <hr>
        <input type="text" @keydown.esc="escFn">
      </div>
    </template>
    
    <script>
    export default {
     methods: {
       enterFn(){
         console.log("enter回车按键了");
       },
       escFn(){
         console.log("esc按键了");
       }
     }
    }
    </script>
    

    总结:多使用事件修饰符,可以提高开发效率,少去判断过程

v-model

把value属性和vue数据变量,双向绑定到一起

  • 语法:v-model='vue数据变量'
  • 双向数据绑定
    • 数据变化->视图自动同步
    • 视图变化->数据自动同步
  • 注意:遇到复选框, v-model的变量值,非数组 - 关联的是复选框的checked属性,数组 - 关联的是复选框的value属性
<template>
  <div>
    <!-- 
    	v-model:是实现vuejs变量和表单标签value属性, 双向绑定的指令
    -->
    <div>
      <span>用户名:</span>
      <input type="text" v-model="username" />
    </div>
    <div>
      <span>密码:</span>
      <input type="password" v-model="pass" />
    </div>
    <div>
      <span>来自于: </span>
      <!-- 下拉菜单要绑定在select上 -->
      <select v-model="from">
        <option value="北京市">北京</option>
        <option value="南京市">南京</option>
        <option value="天津市">天津</option>
      </select>
    </div>
    <div>
      <!-- (重要)
      遇到复选框, v-model的变量值
      非数组 - 关联的是复选框的checked属性
      数组   - 关联的是复选框的value属性
       -->
      <span>爱好: </span>
      <input type="checkbox" v-model="hobby" value="抽烟">抽烟
      <input type="checkbox" v-model="hobby" value="喝酒">喝酒
      <input type="checkbox" v-model="hobby" value="写代码">写代码
    </div>
    <div>
      <span>性别: </span>
      <input type="radio" value="男" name="sex" v-model="gender">男
      <input type="radio" value="女" name="sex" v-model="gender">女
    </div>
    <div>
      <span>自我介绍</span>
      <textarea v-model="intro"></textarea>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: "",
      pass: "",
      from: "",
      hobby: [], 
      sex: "",
      intro: "",
    };
    // 总结:
    // 特别注意: v-model, 在input[checkbox]的多选框状态
    // 变量为非数组, 则绑定的是checked的属性(true/false) - 常用于: 单个绑定使用
    // 变量为数组, 则绑定的是他们的value属性里的值 - 常用于: 收集勾选了哪些值
  }
};
</script>

v-model修饰符

让v-model拥有更加强大的功能

  • 语法:

    • v-model.修饰符='vue数据变量'
      • .number 以parseFloat转成数字类型
      • .trim 去除首尾空白字符
      • .lazy在change触发而非input时
    <template>
      <div>
        <div>
          <span>年龄:</span>
          <input type="text" v-model.number="age">
        </div>
        <div>
          <span>人生格言:</span>
          <input type="text" v-model.trim="motto">
        </div>
        <div>
          <span>自我介绍:</span>
          <textarea v-model.lazy="intro"></textarea>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          age: "",
          motto: "",
          intro: ""
        }
      }
    }
    </script>
    

    v-model修饰符,可以对值进行预处理

v-text和v-html

更新DOM对象的innerText/innerHTML

  • 语法:

    • v-text='vue数据变量'
    • v-html='vue数据变量'

    注意:会覆盖插值表达式

    <template>
      <div>
        <p v-text="str"></p>
        <p v-html="str"></p>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          str: "<span>我是一个span标签</span>"
        }
      }
    }
    </script>
    

    v-text会把值当成普通字符串显示,v-html把值当做html解析

v-show和v-if

控制标签的显示或隐藏

  • 语法:

    • v-show='vue变量'
    • v-if='vue变量'
  • 原理:

    • v-show用的是标签的样式属性display:none隐藏(频繁切换使用)
    • v-if直接从DOM树上移除
  • 高级

    • v-else='vue数据变量'必须配合v-if使用
    • v-else-if='vue变量'必须配合v-if使用,有需要是可以以v-else结尾
    <template>
      <div>
        <h1 v-show="isOk">v-show的盒子</h1>
        <h1 v-if="isOk">v-if的盒子</h1>
    
        <div>
          <p v-if="age < 18">还得多吃饭</p>
          <p v-else-if='age>18 && age<60'>坚持锻炼</p>
          <p v-else='age>60'>送你脑白金</p>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          isOk: true,
          age: 15
        }
      }
    }
    </script>
    

v-for

列表渲染,所在标签结构,按照数据数量,循环生成

  • 语法

    • v-for='(值,索引) in 目标结构'
    • v-for='值 in 目标结构'
  • 目标结构:

    • 可以遍历数组、对象、数字、字符串(可遍历结构)
  • 注意:

    v-for的临时变量名不能用到v-for范围外

    <template>
      <div id="app">
        <div id="app">
          <!-- v-for 把一组数据, 渲染成一组DOM -->
          <!-- 口诀: 让谁循环生成, v-for就写谁身上 -->
          <p>学生姓名</p>
          <ul>
            <li v-for="(item, index) in arr" :key="item">
              {{ index }} - {{ item }}
            </li>
          </ul>
    
          <p>学生详细信息</p>
          <ul>
            <li v-for="obj in stuArr" :key="obj.id">
              <span>{{ obj.name }}</span>
              <span>{{ obj.sex }}</span>
              <span>{{ obj.hobby }}</span>
            </li>
          </ul>
    
          <!-- v-for遍历对象(了解) -->
          <p>老师信息</p>
          <div v-for="(value, key) in tObj" :key="value">
            {{ key }} -- {{ value }}
          </div>
    
          <!-- v-for遍历整数(了解) - 从1开始 -->
          <p>序号</p>
          <div v-for="i in count" :key="i">{{ i }}</div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          arr: ["小明", "小欢欢", "大黄"],
          stuArr: [
            {
              id: 1001,
              name: "孙悟空",
              sex: "男",
              hobby: "吃桃子",
            },
            {
              id: 1002,
              name: "猪八戒",
              sex: "男",
              hobby: "背媳妇",
            },
          ],
          tObj: {
            name: "小黑",
            age: 18,
            class: "1期",
          },
          count: 10,
        };
      },
    };
    </script>
    

v-for更新检测

当v-for遍历的目标结构改变,vue触发v-for更新

情况一:数组翻转

<template>
  <div>
    <ul>
      <li v-for="(val, index) in arr" :key="index">
        {{ val }}
      </li>
    </ul>
    <button @click="revBtn">数组翻转</button>
  </div>
</template>
<script>
export default {
  data(){
    return {
      arr: [5, 3, 9, 2, 1]
    }
  },
  methods: {
    revBtn(){
      // 1. 数组翻转可以让v-for更新
      this.arr.reverse()
    },
    
  }
}
</script>

<style>

</style>

情况二:数组截取

<template>
  <div>
    <ul>
      <li v-for="(val, index) in arr" :key="index">
        {{ val }}
      </li>
    </ul>
    <button @click="sliceBtn">截取数组</button>
  </div>
</template>
<script>
export default {
  data(){
    return {
      arr: [5, 3, 9, 2, 1]
    }
  },
  methods: {
     sliceBtn(){
      // 2. 数组slice方法不会造成v-for更新
      // slice不会改变原始数组
      // this.arr.slice(0, 3)

      // 解决v-for更新 - 覆盖原始数组
      let newArr = this.arr.slice(0, 3)
      this.arr = newArr
    },
    
  }
}
</script>

<style>

</style>

情况三:更新值

<template>
  <div>
    <ul>
      <li v-for="(val, index) in arr" :key="index">
        {{ val }}
      </li>
    </ul>
    <button @click="updateBtn">截取数组</button>
  </div>
</template>
<script>
export default {
  data(){
    return {
      arr: [5, 3, 9, 2, 1]
    }
  },
  methods: {
     updateBtn(){
         //更新某个值得时候,v-for是检测不到的
         //this.arr[0] = 10
         
         //解决 --this.$set()
         //参数1:更新目标结构
         //参数2:更新位置
         //参数3:更新值
         this.$set(this.arr,0,10)
     }
    
  }
}
</script>

<style>

</style>

口诀:

数组变更方法,就会导致v-for更新,页面更新

数值非变更方法,返回新数组,就不会导致v-for更新可以采用覆盖数组或者this.$set()

常见的会触发数组改变,v-for会检测到并更新页面的数组方法有:

  • push()添加数组
  • pop()删除数组中最后一个元素
  • shift()删除数组第一个元素,并返回这个元素的值
  • unshift添加一个或者多个元素到数组开头,并返回该数组的新长度
  • splice()删除指定位置的数组或者添加新元素到指定位置
  • sort()方法用原地算法对数组的元素进行排序
  • revese()倒转数组

不会触发v-for更新

  • slice()截取数组
  • filter()过滤数组
  • concat()合并两个数组或者多个数组

注意:vue不能检测到数组里赋值的动作而更新,如果需要就使用Vue.set()或者this.$set(),或者覆盖整个数组

v-for就地更新

v-for的默认行为会尝试原地修改元素而不是移动他们

image-20210414215302318.png 这种虚拟DOM对比方式,可以提升性能-但是还不够高

虚拟dom

.vue文件中的template里面写标签,模板都要被vue处理成虚拟DOM对象,才能被渲染到真实的DOM页面上

  1. 内存中生成一样的虚拟DOM结构(本质是一个JS对象)

    真实的DOM属性好几百个,没办法快速的知道哪个属性改变了

    比如template里面的标签结构

    <template>
        <div id="box">
            <p class="my_p">123</p>
        </div>
    </template>
    

    对应的虚拟DOM结构

    const dom = {
        type:'div',
        attributes:[{id:'box'}],
        children:{
            type:'p',
            attributes:[{class:'my_p'}],
            text:'123'
        }
    }
    
  2. 以后vue数据更新

    • 生成新的虚拟DOM结构
    • 和旧的虚拟DOM结构对比
    • 找不同,只更新变化部分(重绘、回流)到页面 - 也叫补丁

    好处1:提高了更新DOM的性能(不用把页面全删除重新渲染)

    好处2:虚拟DOM只包含必要属性(没有真实的DOM上百个属性)

    虚拟DOM保存在内存中,只记录dom关键信息,提高DOM更新的性能

    在内存中比较差异,如然后给真实的DOM打补丁更新上

key的作用

  1. 没有key-就地更新

    v-for不会移动DOM,而是尝试复用,就地更新,如果需要v-for移动DOM,你需要特殊attributekey来提供一个排序提示

    <ul id="myUL">
        <li v-for="str in arr">
            {{ str }} 
            <input type="text">
        </li>
    </ul>
    <button @click="addFn">下标为1的位置新增一个</button>
    <script>
    export default {
        data(){
            return {
                arr: ["老大", "新来的", "老二", "老三"]
            }
        },
        methods: {
            addFn(){
                this.arr.splice(1, 0, '新来的')
            	}
        	}
    	};
    </script>
    

    新旧DOM的对比过程

    新_vfor更细_无key_就地更新.gif

    image-20210414215502653.png

  2. 有key - 值为索引

    因为新旧虚拟DOM对比,key存在就复用此标签更新内容,如果不存在就直接建立在一个新的

    <ul id="myUL">
       <li v-for="(str, index) in arr" :key="index">
           {{ str }} 
           <input type="text">
       </li>
    </ul>
    <button @click="addFn">下标为1的位置新增一个</button>
    <script>
    export default {
       data(){
           return {
               arr: ["老大", "新来的", "老二", "老三"]
           }
       },
       methods: {
           addFn(){
               this.arr.splice(1, 0, '新来的')
           }
       }
    };
    </script>
    

    图解过程:

    新_vfor更细_无key_就地更新.gif

    image-20210414215525492.png

  3. v-for先循环产生新的DOM结构,key是连续的和数据对应

  4. 然后比较新旧DOM结构,找到区别,打补丁到页面上,最后一个补li然后从第二个开始往后,都要更新内容

  5. 有key - 值为id

    key的值只能是唯一不重复,字符串或数值

    v-for不会移动DOM,而是尝试复用,就地更新,如果需要v-for移动DOM,你需要用特殊attributekey来提供一个排序提示

    新的DOM里的数据key存在,去就得虚拟DOM里找到key标记的标签,复用标签

    新的DOM里的数据的key存在,去旧的虚拟DOM结构里没有找到key标签,创建旧的DOM的结构key,在新的DOM结构没有了,则==移除key所在标签

    <template>
      <div>
        <ul>
          <li v-for="obj in arr" :key="obj.id">
            {{ obj.name }}
            <input type="text">
          </li>
        </ul>
        <button @click="btn">下标1位置插入新来的</button>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          arr: [
            {
              name: '老大',
              id: 50
            },
            {
              name: '老二',
              id: 31
            },
            {
              name: '老三',
              id: 10
            }
          ],
        };
      },
      methods: {
        btn(){
          this.arr.splice(1, 0, {
            id: 19, 
            name: '新来的'
          })
        }
      }
    };
    </script>
    
    <style>
    </style>
    

    图文详解:

    新_vfor更细_有key值为id_提高性能更新.gif

    image-20210414215546869.png