Vue基础-day02

176 阅读7分钟

Vue基础-day02

复习昨天内容

  • Vue是一套渐进式JS框架

  • Vue基本使用

    • 准备一个容器
    • 导入vue
    • 实例化一个Vue,并且把这个容器通过 el 属性交给vue来管理
    • data是放数据的地方,methods是放方法的地方
  • 指令:

    • 以v-开头
    • 是vue提供的具备特殊功能的行内属性
  • v-text于v-html

    • 是用来设置双标签里的内容,v-text遇到标签不解析,v-html遇到标签会解析
  • v-on

    • 绑定事件的
    • 语法:
      • v-on:事件名="函数"
      • v-on:事件名="一句代码"
    • 简写:
      • @事件名="函数"
      • @事件名="一句代码"
    • 修饰符
      • .stop
        • 阻止冒泡
      • .prevent
        • 阻止默认行为
      • .self
        • 只能由自己触发,冒泡不能触发
      • .键名
        • 只能由某个键触发
        • 比如: .enter 只能由回车键触发
    • v-on绑定事件时函数加小括号和不加小括号有区别
      • 不加小括号默认有参数,参数就是事件对象(也就是$event)
      • 加小括号代表要自己传参,那你传什么就是什么,不传就是undefined,如果自己传参了还想拿到事件对象,就用 $event 代表事件对象
  • v-bind

    • 绑定行内属性,让行内属性不写死

    • 语法: v-bind:属性名="值"

    • 简写: :属性名="值"

    • 如果绑定的是class

      v-bind:class="{ 类名: 布尔值 }"
      
      • 如果布尔值为true有这个类,为false没有这个类
    • 如果绑定的是style

      v-bind:style="{样式名: 数据}"
      
  • v-for

    • 遍历渲染某个标签

    • 遍历数组

      <标签 v-for="(item, index) in 数组" ></标签>
      
    • 遍历对象

      <标签 v-for="(value, key) in 对象" ></标签>
      
    • 指定次数遍历(遍历数字)

      <标签 v-for="num in 数字" ></标签>
      
  • v-show与v-if

    • 都是用来控制显示和隐藏
    • v-show是通过css里的display属性来控制
    • v-if是通过添加或移除dom(相当于它会销毁和创建)
  • v-model

    • 双向数据绑定,给表单元素用的
    • 可以给表单元素赋值,也可以获取表单元素的值

v-for中key的作用

  • 问题代码演示:

        <div id="app">
            <!-- 相当于在下标1的位置加了一个赵六的对象 -->
            <button @click="list.splice( 1, 0, {id:4, name:'赵六'} )">添加</button>
            <ul>
                <li v-for="item in list">
                    <input type="checkbox">
                    <span>{{ item.name }}</span>
                </li>
            </ul>
        </div>
        
        <script src="./vue.js"></script>
        <script>
            new Vue({
                el: '#app',
                data: {
                    list: [
                        { id: 1, name: '张三' },
                        { id: 2, name: '李四' },
                        { id: 3, name: '王五' },
                    ]
                }
            })
        </script>
    
  • 当我勾了李四,然后在下标1的位置添加了赵六,结果发现勾给了赵六,李四自己没勾了

  • 原因:

    • Vue会在v-for尝试最大限度的复用当前元素
    • 所以可能会导致状态绑定错乱,它可能复用到别人的东西了
  • 解决办法:

    • 在v-for时加一个key属性,key绑定这个数据的唯一值(一般是id)
    • 有key后,就根据key来复用
  • 总结与建议:

    • 以后写v-for,一定要加key属性,且key的值是唯一的(唯一的数据只能是字符串和数字类型)
    • 给下标没效果
  • 小结

    • key一定要给字符串类型或者数字类型 唯一值
    • 可以起到复用更加精准,效率也更高

v-bind数组的写法绑定class

  • v-bind:class 也可以写数组形式,代表一次性绑定多个类

    <标签 v-bind:class="[变量1,变量2]"></标签>
    
    • 代表有2个类,2个类的分别是变量1和变量2对应的值
    <标签 v-bind:class="[变量1,'变量2']"></标签>
    
    • 代表有2个类,2个类,第一个是变量1的值,第二个类就叫 变量2
    <标签 v-bind:class="[变量1,{类名: 布尔值}]"></标签>
    
    • 可能一个类,可能2个类,第一个类一定是变量1的值,第二个类要看布尔值,是true有这个类,是false没有这个类
  • 演示代码

     <div id="app">
            <!-- 数组的形式就是:你变量的值是,它就有什么类 -->
            <div :class="[cls1, cls2]"></div>
    
            <!-- 两个类:一个是box,一个是cls2 -->
            <!-- 不加引号代表取出变量值,加引号代表就是这个值 -->
            <div :class="[cls1, 'cls2']"></div>
    
    
            <!-- box和bd  -->
            <div :class="[cls1, {bd: isBd}]"></div>
    
        </div>
        <script src="./vue.js"></script>
        <script>
            new Vue({
                el: '#app',
                data: {
    
                    cls1: 'box',
                    cls2: 'bd',
                    isBd: true
                }
            })
        </script>
    

记事本01-列表

分析

  • 因为列表要显示多条,所以我肯定要把多条数据存起来,既然要存多条数据,就意味着要用数组存起来
  • 然后再对着li进行v-for根据这个数组来渲染

步骤

  • 在data中声明一个数组,可以先放一些测试的数据

            data: {
              list: [
                { id: 1, title: '吃饭' },
                { id: 2, title: '睡觉' },
                { id: 3, title: '打人' }
              ]
            },
    
  • 然后来到 html部分,找到li那一块,用v-for生成li,要改掉显示的标题,以及序号

            <ul>
              <!-- 记录列表 -->
              <li v-for="(item, index) in list" :key="item.id">
                <div class="content"><span>{{ index + 1 }}.</span> {{ item.title }}</div>
                <button></button>
              </li>
            </ul>
    

记事本02-新增

接下来完成新增功能

分析

  • 新增要拿到输入框的内容,所以输入框肯定要加v-model
  • 因为要按回车才添加,就意味着输入框肯定要加事件 keyup,并且只能由enter键触发
  • 按回车不能直接加到数组里,因为有可能没有输入内容,所以要做一个非空判断
  • 如果不为空,就加到数组里
  • 加到数组后,要把输入框内容清空
  • 最后去完善一下 空空如也 的显示

步骤

  • 先声明变量叫 title,再跟输入框双向绑定

    data: {
        title: ''
    }
    
    <input type="text" v-model="title" />
    
  • 然后给 输入框键盘弹起 事件,绑定到方法叫add,所以记得要声明

    <input type="text" v-model="title" @keyup.enter="add"/>
    
    methods: {
       add () {
    
       }
    }
    
  • 事件里先做非空判断,然后加到数组里,然后清空输入框

              add () {
                // 如果输入为空就不往下执行,并且弹出提示框
                if (this.title == '') return alert('请输入点内容')
    
                // 能来到这证明有内容,有内容就加到数组里
                // 但是数组要加对象,加到最前面(unshift)
                // 时间戳是指从1970年1月1日0时0分0秒0毫秒 到现在的 毫秒数
                // 因为时间都是在向前的,所以每次的时间戳肯定是不一样的!
                this.list.unshift({
                  id: Date.now(),
                  title: this.title
                })
    
                // 加完后把输入框内容清空
                this.title = ''
              }
            }
    
  • 去优化空空如也的显示,如果数组长度为0,代表没数据,就显示空空如也

    <p v-show="list.length == 0" class="empty">空空如也...</p>
    

v-model的trim修饰符

  • 可以自动帮你去除首尾空格

  • 语法

    v-model.trim="数据"
    
  • 相当于取到输入框时的值就自动把首尾的空格去掉了

  • 所以,我们要做非空判断,其实只要把v-model加一个trim

    <input type="text" v-model.trim="title" @keyup.enter="add"/>
    

记事本03-删除

接下来完成删除功能

  • 就是给删除加点击事件,点谁就根据谁的下标来删除即可

    <button @click="list.splice(index, 1)"></button>
    

记事本04-清空

最后咱们来完成空

  • 就是给清空加点击事件,点击事件让数组重新赋值为空数组,就全部清空

    <span @click="list = []">清空</span>
    
  • 统计合计:就是统计数组的长度

     <span>合计: {{ list.length }}</span>
    

侦听器

接下来咱们来学习侦听器,听名字好像是一个很厉害的东西哦

传送门:侦听器

传送门:侦听器-api

  • 作用:

    • 用来侦听数据有没有变化,一旦有变化就调用的函数
  • 语法

    • 在跟data、methods这些平级的位置写一个 watch
    watch: {
        // 参数1:改变后的值
        // 参数2:改变前的值
        要侦听的数据 (newVal, oldVal) {
            
            
        }
    }
    
  •             // 写侦听器的地方
                watch: {
                    // 基本数据类型,这两个参数有意义
                    msg(newVal, oldVal) {
                        console.log('改变了', newVal, oldVal)
                    },
    
                    // 复杂类型,这两个参数没有意义,因为地址没变
                    // 所以复杂类型一般不会写这两个,所以反正都一样,就算写也只是一个
                    // 因为vue2.x内部原理的原因,通过下标修改数据是不会被Vue侦听到的
                    list() {
    
                        console.log('数组改变了')
                    }
                }
    
  • 注意事项:

    • 如果侦听复杂类型,两个参数没有意义,都是一样的

    • 数组如果通过下标直接修改数据,不会侦听到

    • 但是数组调用如下方法造成修改,会侦听到

074b8d01-3869-4c82-86bc-148aed688c7e.png

  • 扩展:我非要让下标修改也能侦听到,而且也能是响应式的

    • 注意:vue3.x已经没有这个问题了,所以下面的方法可以作为了解
    • 就可以用$set来解决

完整侦听器写法

  • 默认情况下,你写上面的侦听器,是不能侦听到对象里属性的变化

  • 如果想侦听对象的属性变化,可以单独侦听这个属性

    watch: {
        // 只是侦听name属性
        "obj.name" () {
            
        }
    }
    
  • 如果希望这个对象里所有属性的变化都能被侦听到,就开启深度侦听

  • 语法

    watch: {
        对象名: {
            // 开启深度侦听
            deep: true,
            // 当有变化时调用的函数
            handler(){
                
            },
            // 如果为true,代表当前页面打开时会立即调用一次handler
            // 默认是false
            immediate: true
        }
    }
    
  •           watch: {
    
                    // 如果希望侦听到所有属性的变化,就要开启深度侦听
                    obj: {
                        // 当有变化会调用的函数
                        handler () {
                            console.log('obj的属性变化了')
                        },
                        // 开启深度侦听
                        deep: true,
                        // 要不要当前页面一打开就立即调用依次handler函数
                        // 给true要立即调用,默认是false(代表只有改动了才调用)
                        immediate: true
                    }
    

记事本05-缓存数据

结合上一节学习的侦听器,咱们来把记事本中数据缓存起来

  • 我们目前学过的存储数据技术有:localStorage、sessionStorage

  • 所以如果我们希望把记事本的数据长久保存起来,就应该用 localStorage

  • 因为只要数据发生改变就要保存起来,因此需要写一个侦听器,来侦听数组是否有变化,一旦变化就存到本地存储

  • 步骤

    • 写一个侦听器,侦听数组的变化,一旦有变化就存到本地存储

              // 写侦听器的地方
              watch: {
      
                // 侦听list的改变
                list () {
      
                  // 把数组给存到本地存储
                  // 本地存储只能存字符串,复杂类型要转成JSON字符串才能存储
                  window.localStorage.setItem('note83', JSON.stringify(this.list))
                }
              }
      
    • 页面一打开给数组的默认值就得取出来,但是有可能缓存已经被删了(或者压根就没有),那会得到null,那样就会报错,所以应该做判断,本地存储有值就取本地存储的值,没值就给一个空数组

      // 左边有值,就用左边的值,左边没值就用右边值
      // 在这里就是本地存储有值就取本地存储的值,没值就取空数组 
      list: JSON.parse(localStorage.getItem('note83')) || []
      

Vue组件-基本概念

目前为止,咱们的逻辑都写在一个Vue实例中,能不能进行拆分呢? 自信一些,可以哦,可以通过组件的方式进行拆分

传送门:Vue组件基础

ba267fe3-df6c-4f19-9011-c80a0d83bfab.png

  • 组件化的概念

    • 什么叫组件
      • 组成网页的一部分,就叫组件
    • 开发中多利用组件,可以方便复用以及维护
    • 组件具备哪些要素?
      • html结构、css样式、逻辑代码
      • 因为组件是网页中的一小部分,那这一部分要想显示肯定要有html结构,要想好看,要有css样式,要想有功能就要有逻辑代码
  • 小结:

    • 什么叫组件?
    • 为什么要用组件开发思想?

Vue组件-单文件组件

传送门:单文件组件

传送门:风格指南-组件文件

  • 传统的html文件,方便复用吗?因为太庞大,一个html文件是一个大的页面

  • 而组件可能只是界面中的一个小部分。所以如果我要把一个小部分抽取成组件,用.html文件不方便抽取

  • 所以在Vue中,是以.vue文件来抽取成组件的

  • .vue文件有三大部分

    • template部分
      • 这里是写html结构的
    • script部分
      • 这里是写js代码(逻辑代码)
    • style部分
      • 这里是写css代码
  • 我们以后写vue代码肯定都是用这种 .vue文件

Vue-CLI-概念及安装

.vue文件浏览器能认识吗?不认识怎么办?可以用webpack,打包后浏览器就认识了,但是webpack配置起来麻烦,有没有一种帮我们准备好的webpack?有,那就是vue-cli

传送门:Vue-CLI官网

3560fb20-d155-4e44-9b63-54d6b6b3cf12.png

  • vue-cli俗称脚手架,它内部基于webpack,但是比webpack更方便,因为我们帮做了大量的配置,让我们不用配置或者只要少量配置就能实现对应功能,简单来说就是做到了 开箱即用,安装好了直接用

    • 例如webpack要识别css还得装loader,识别.vue文件也要装loader,还要写配置文件,比如要一边开发一边看效果还得装对应插件和配置,但是用了 vue-cli,这些你都不用做,它已经帮你做好了
  • 为什么叫脚手架?

    • 因为像现实工程一样,vue-cli可以帮我们搭好大概的项目架子,然后我从这个架子上去丰富项目代码,所以称之为代码中的脚手架
  • 安装

    npm i -g @vue/cli
    
    • 目前版本是5.x版本,所以目前用这条命令下载到的就是5.x版
    • 5.x版本的脚手架最低依赖node14版本,而node14,win7不支持,win7最高支持12
    • 所以win7不能下载最新版脚手架,下4.x版本脚手架
    npm i -g @vue/cli@4.x
    
  • 如何检查安装成功?

    vue -V
    
    • 如果出现版本号代表安装成功
    • 注意:如果你当前小黑窗的目录有vue.js,敲命令时会异常
  • 5.x版本和4.x的版本区别

    • 大部分都是一样,小部分区别,到时候见一个讲一个

Vue-CLI项目创建

确保上一步搞定之后,就可以通过Vue-CLI创建项目了

目标:

  1. 能够通过Vue-CLI创建默认配置的Vue项目

步骤:

  1. 在希望创建项目的位置,执行命令:vue create 项目名

    1. 非中文,不要大写字母,特殊符号,包名
  2. 选择Vue2默认设置的版本,回车

867878cc-6696-435e-94fc-da06f37440b8.png

  1. 等待成功,并根据提示执行命令

    1. 根据自己的项目名,执行蓝色文字的命令

54ba46fc-cd59-4473-b5bf-22483166ff1e.png

  1. 等待项目执行并显示如下提示,即可在网页中访问

    1. 地址1和地址2都可以访问

2e93bb75-f5ce-4b7e-8455-90dacbaa4315.png

  1. 看到如下界面,说明启动成功

ee6a0847-ce97-4655-8572-2ade1c12d586.png

做了什么

执行vue create 项目名时他做了很多事情,比如:

  1. 创建文件夹
  2. 创建项目基础文件
  3. 调整好默认的项目配置
  4. 下载第三方包
  5. 初始化git仓库
  6. ...

小结:

  1. vue create 项目名命令执行之后是否会多出一个目录?
  2. npm run serve中的serve配置在哪个文件中?

Vue-CLI项目结构

接下来咱们来看看项目的结构

8755539c-c6f1-4164-a6e4-610446f52dde.png

  • 项目好了后,可以自己试试改掉App.vue里的代码看效果

脚手架Vue项目运行流程

  1. 我们执行npm run serve他内部干了什么事呢?

894900b4-1bdc-4ad7-8a72-b98e4f9d6a3d.png

Vue-CLI main.js

main.js以后在开发中什么作用呢?

  • main.js是入口,打包时的特点是:从入口开始,分析里面的依赖,再一起打包
  • 所以就意味着,如果以后我们要导入一些全局的插件全局的样式,应该写在 main.js
  • 简而言之:全局的东西放到main.js里

Vue-CLI App.vue

接下来是App.vue

  • 它叫主组件,我们默认打开项目,显示的就是 App.vue

  • 所以以后我们组件代码都是从 App.vue开始

  • 组件一定有三大部分

    • template:
      • 写html结构的地方
    • script
      • 写js代码的地方
    • style
      • 写样式的地方
  • template里必须要有一个根标签(最外层的标签)

  • 装了vetur插件后,可以输入 <vue>来快速生成三大空白结构

组件化开发里data必须是函数

export default {
  
  data () {
    // 在return的对象里声明vue里的变量
    return {
      // 在这里面声明数据
      msg: '马杀鸡'
    }
  },
  // 其他的methods或者watch以前该怎么写,现在还怎么写
};

eslint介绍与关闭

在使用Vue-CLI创建的项目中,有些代码写完命名没有语法错误,但是却出现了错误提示,为啥呢?

传送门:eslint文档

传送门:lintOnSave

  • 代码有规则和规范两大类

    • 规则是必须要遵守的,不遵守就报语法错误
    • 规范是建议要遵守的,但是不遵守不会报错
    • 就好比变量命名就有规则和规范
      • 规则:不能用关键字,只能用字母、数字、下划线,且数字不能开头
      • 规范:起名要有意义,最好用驼峰命名法
    • 每个人写代码风格不一样,在同一个项目不利于分享,所以有些公司强制要程序员按照某种规范来写代码,但是老板不可能去检查每一句话,所以想要有一个工具,只要你写的代码不规范立即就报错,让程序无法执行
    • 这种工具就叫 ESLint
  • 我们创建项目时如果选择的是默认配置,那么就携带了ESLint

    • 例:声明变量,但是我后面不用

    • 还有个规范:在vue中写v-for必须要加key

  • 现在我们主要是为了学习Vue的语法,所以为了避免你写的代码因为不规范报错,我们就把ESLint给关了

  • 在配置文件里关: vue.config.js,加如下一句话

    lintOnSave: false
    
    • 脚手架5有默认代码,我们不用动,自己加上面那一句就可以了
    const { defineConfig } = require('@vue/cli-service')
    module.exports = defineConfig({
      transpileDependencies: true,
      // 关掉ESLint
      lintOnSave: false // 加这句即可,其他不要动
    })
    
  • vue/cli 4的版本,默认没有 vue.config.js,所以需要自己添加。然后里面写这样的形式

    module.exports = {
        lintOnSave: false
    }
    

注意:如果改了配置文件一定要重新启动才能生效

组件局部注册及使用

  • 如果哪个组件里要用这个组件,就要先导入

    import 组件名 from '路径'
    // 例
    import HmHeader from './components/HmHeader'
    
  • 导入完要注册

    export default {
        
        components: {
            组件名
        }
    }
    
    // 例
    export default {
        
        components: {
            HmHeader
        }
    }
    
  • 选一个你想显示它的位置,写一个以组件名的标签,就能把这个组件显示到这个位置

    <组件名 />
    <HmHeader />
    
    • 大驼峰可以拆成带-的小写,单词之间加-
    <hm-header />
    
  • 目前而言组件写单标签双标签效果一样

全局组件注册与使用

上面的组件叫局部组件,就是在哪里导入,就只能在哪里使用,全局组件的含义就是:导入一次,其他地方都能用

  • 写到 main.js

  • 要先导入组件

    import 组件名 from '路径'
    
  • 然后注册全局组件

    Vue.component('组件名', 导入的组件)
    // 一般情况下组件名跟导入的组件文件名是一样的,但是可以改,没必要
    

组件名

现在可以随意添加组件了,组件的名字有要求吗?

传送门:组件名

传送门:风格指南

传送门:自闭合组件

  • 规范1:
    • 纯小写名字,多个单词之间用 - 连接
      • 例如: my-heima-header
      • 使用时也是 <my-heima-header />
  • 规范2:
    • 小驼峰命名
      • 第一个单词首字母小写,后面每个单词首字母大写
      • 不太推荐
    • 例:
      • myHeimaHeader
      • 用的时候就 <myHeimaHeader /> 也可以拆 <my-heima-header />
  • 规范3:
    • 大驼峰命名
      • 全部单词首字母大写
      • MyHeimaHeader
      • 用的时候就 <MyHeimaHeader /> 也可以拆 <my-heima-header />
  • 组件名官方建议至少由2个单词组成
  • 这只是规范、不遵守默认不会报错,除非有ESLint

组件关系

当项目中的组件越来越多之后,组件之间可能出现彼此嵌套的情况,咱们如何去称呼这些组件呢

  • 一个盒子包含另外一个盒子,包含别人的叫父盒子,被包含在里面的叫子盒子

  • 一样的道理:

    • 一个组件里包含了另外一个组件,包含别人的叫父组件,被包含的叫子组件
  • 兄弟组件

    • 同级别就叫兄弟组件

总结 和 作业

今天的重点内容

  1. v-for中的key推荐给什么值?
  2. v-for中的key如果省略可能有什么问题?
  3. 数据改变时希望执行一些代码,可以通过什么实现?
  4. Vue-CLI需要安装几次?
  5. 如何通过Vue-CLI创建项目?
  6. .vue文件也叫做什么?
  7. .vue文件中,结构,逻辑,样式分别写在哪里?
  8. template里必须满足什么要求?
  9. 组件里data必须是什么?
  10. 如何注册局部组件?
  11. 如何注册全局组件?

作业-1:

  1. 基于02-其他资料/02.记事本模板中的模板,完成如下效果

  2. 整合步骤:

    1. 关闭项目
    2. 删除src下的所有文件
    3. 使用把素材拷贝进去
    4. 重新运行
  3. 要求:

    1. 不需要实现逻辑
    2. 使用components/目录下的提供的组件
    3. 完成截图类似效果,不需要实现逻辑

4f5a3bea-2a1c-4420-9f94-5bf720f801b7.png

作业-2:

  • 算是一个预习作业,可以自己看文档、或者笔记预习,如果实在搞不明白,没关系,等我后天讲

不需要测试代码,用自己的话描述

  1. slot标签的作用?

    1. 参考文档:
    2. 传送门:通过插槽分发内容
  2. props属性的作用?

    1. 参考文档
    2. 传送门:通过prop向子组件传递数据
  3. $emit方法的作用?

    1. 参考文档
    2. 传送门:监听子组件的事件
    3. 传送门:使用只组件抛出一个值
  4. 组件上使用v-model等同于什么?

    1. 参考文档:
    2. 传送门:在组件上使用v-model
    3. 传送门:表单输入绑定

今日单词

单词解释说明
keyv-for中的keykey的值是唯一的(唯一的数据只能是字符串和数字类型)
trimv-model中的trim去除两边的空白字符
watch侦听器侦听器的几种写法,都需要熟练
deep深度侦听watch里的deep属性,默认false
immediate立即调用函数watch里的immediate属性,默认false,如果
templatehtml结构vue里写html结构
vue-clivue脚手架vue-cli俗称脚手架
vue create 项目名等待成功,并根据提示执行命令;如果卡住了按enter
<vue + tab创建vue基本结构
veturvetur插件
lint线头;静态代码分析
eslint代码规范插件
lintOnSave在配置文件里关: vue.config.js,加如下一句话 lintOnSave: false
components局部组件属性名components: {
组件名
}
component全局组件属性名Vue.component('组件名', 导入的组件)