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 只能由回车键触发
- .stop
- 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一定要给
字符串类型或者数字类型唯一值 - 可以起到复用更加精准,效率也更高
- 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>
侦听器
接下来咱们来学习侦听器,听名字好像是一个很厉害的东西哦
-
作用:
- 用来侦听数据有没有变化,一旦有变化就调用的函数
-
语法
- 在跟data、methods这些平级的位置写一个
watch
watch: { // 参数1:改变后的值 // 参数2:改变前的值 要侦听的数据 (newVal, oldVal) { } } - 在跟data、methods这些平级的位置写一个
-
例
// 写侦听器的地方 watch: { // 基本数据类型,这两个参数有意义 msg(newVal, oldVal) { console.log('改变了', newVal, oldVal) }, // 复杂类型,这两个参数没有意义,因为地址没变 // 所以复杂类型一般不会写这两个,所以反正都一样,就算写也只是一个 // 因为vue2.x内部原理的原因,通过下标修改数据是不会被Vue侦听到的 list() { console.log('数组改变了') } } -
注意事项:
-
如果侦听复杂类型,两个参数没有意义,都是一样的
-
数组如果通过下标直接修改数据,
不会侦听到 -
但是数组调用如下方法造成修改,
会侦听到
-
-
扩展:我非要让下标修改也能侦听到,而且也能是响应式的
- 注意: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实例中,能不能进行拆分呢? 自信一些,可以哦,可以通过组件的方式进行拆分
-
组件化的概念
- 什么叫组件
- 组成网页的一部分,就叫组件
- 开发中多利用组件,可以方便复用以及维护
- 组件具备哪些要素?
- html结构、css样式、逻辑代码
- 因为组件是网页中的一小部分,那这一部分要想显示肯定要有
html结构,要想好看,要有css样式,要想有功能就要有逻辑代码
- 什么叫组件
-
小结:
- 什么叫组件?
- 为什么要用组件开发思想?
Vue组件-单文件组件
-
传统的html文件,方便复用吗?因为太庞大,一个html文件是一个大的页面
-
而组件可能只是界面中的一个小部分。所以如果我要把一个小部分抽取成组件,用.html文件不方便抽取
-
所以在Vue中,是以
.vue文件来抽取成组件的 -
.vue文件有三大部分- template部分
- 这里是写html结构的
- script部分
- 这里是写js代码(逻辑代码)
- style部分
- 这里是写css代码
- template部分
-
我们以后写vue代码肯定都是用这种
.vue文件
Vue-CLI-概念及安装
.vue文件浏览器能认识吗?不认识怎么办?可以用webpack,打包后浏览器就认识了,但是webpack配置起来麻烦,有没有一种帮我们准备好的webpack?有,那就是vue-cli
-
vue-cli俗称脚手架,它内部基于webpack,但是比webpack更方便,因为我们帮做了大量的配置,让我们不用配置或者只要少量配置就能实现对应功能,简单来说就是做到了
开箱即用,安装好了直接用- 例如webpack要识别css还得装loader,识别.vue文件也要装loader,还要写配置文件,比如要一边开发一边看效果还得装对应插件和配置,但是用了
vue-cli,这些你都不用做,它已经帮你做好了
- 例如webpack要识别css还得装loader,识别.vue文件也要装loader,还要写配置文件,比如要一边开发一边看效果还得装对应插件和配置,但是用了
-
为什么叫脚手架?
- 因为像现实工程一样,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创建项目了
目标:
- 能够通过
Vue-CLI创建默认配置的Vue项目
步骤:
-
在希望创建项目的位置,执行命令:
vue create 项目名- 非中文,不要大写字母,特殊符号,包名
-
选择Vue2默认设置的版本,回车
-
等待成功,并根据提示执行命令
- 根据自己的项目名,执行蓝色文字的命令
-
等待项目执行并显示如下提示,即可在网页中访问
- 地址1和地址2都可以访问
- 看到如下界面,说明启动成功
做了什么
执行vue create 项目名时他做了很多事情,比如:
- 创建文件夹
- 创建项目基础文件
- 调整好默认的项目配置
- 下载第三方包
- 初始化git仓库
- ...
小结:
vue create 项目名命令执行之后是否会多出一个目录?npm run serve中的serve配置在哪个文件中?
Vue-CLI项目结构
接下来咱们来看看项目的结构
- 项目好了后,可以自己试试改掉
App.vue里的代码看效果
脚手架Vue项目运行流程
- 我们执行
npm run serve他内部干了什么事呢?
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:
-
template里必须要有一个根标签(最外层的标签) -
装了
vetur插件后,可以输入<vue>来快速生成三大空白结构
组件化开发里data必须是函数
export default {
data () {
// 在return的对象里声明vue里的变量
return {
// 在这里面声明数据
msg: '马杀鸡'
}
},
// 其他的methods或者watch以前该怎么写,现在还怎么写
};
eslint介绍与关闭
在使用Vue-CLI创建的项目中,有些代码写完命名没有语法错误,但是却出现了错误提示,为啥呢?
-
代码有规则和规范两大类
- 规则是必须要遵守的,不遵守就报语法错误
- 规范是建议要遵守的,但是不遵守不会报错
- 就好比变量命名就有规则和规范
- 规则:不能用关键字,只能用字母、数字、下划线,且数字不能开头
- 规范:起名要有意义,最好用驼峰命名法
- 每个人写代码风格不一样,在同一个项目不利于分享,所以有些公司强制要程序员按照某种规范来写代码,但是老板不可能去检查每一句话,所以想要有一个工具,只要你写的代码不规范立即就报错,让程序无法执行
- 这种工具就叫
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
组件关系
当项目中的组件越来越多之后,组件之间可能出现彼此嵌套的情况,咱们如何去称呼这些组件呢
-
一个盒子包含另外一个盒子,包含别人的叫父盒子,被包含在里面的叫子盒子
-
一样的道理:
- 一个组件里包含了另外一个组件,包含别人的叫父组件,被包含的叫子组件
-
兄弟组件
- 同级别就叫兄弟组件
总结 和 作业
今天的重点内容
- v-for中的key推荐给什么值?
- v-for中的key如果省略可能有什么问题?
- 数据改变时希望执行一些代码,可以通过什么实现?
- Vue-CLI需要安装几次?
- 如何通过Vue-CLI创建项目?
.vue文件也叫做什么?.vue文件中,结构,逻辑,样式分别写在哪里?- template里必须满足什么要求?
- 组件里
data必须是什么? - 如何注册局部组件?
- 如何注册全局组件?
作业-1:
-
基于
02-其他资料/02.记事本模板中的模板,完成如下效果 -
整合步骤:
- 关闭项目
- 删除
src下的所有文件 - 使用把素材拷贝进去
- 重新运行
-
要求:
- 不需要实现逻辑
- 使用
components/目录下的提供的组件 - 完成截图类似效果,不需要实现逻辑
作业-2:
- 算是一个预习作业,可以自己看文档、或者笔记预习,如果实在搞不明白,没关系,等我后天讲
不需要测试代码,用自己的话描述
-
slot标签的作用?- 参考文档:
- 传送门:通过插槽分发内容
-
props属性的作用?- 参考文档
- 传送门:通过prop向子组件传递数据
-
$emit方法的作用? -
组件上使用
v-model等同于什么?- 参考文档:
- 传送门:在组件上使用v-model
- 传送门:表单输入绑定
今日单词
| 单词 | 解释 | 说明 |
|---|---|---|
| key | v-for中的key | key的值是唯一的(唯一的数据只能是字符串和数字类型) |
| trim | v-model中的trim | 去除两边的空白字符 |
| watch | 侦听器 | 侦听器的几种写法,都需要熟练 |
| deep | 深度侦听 | watch里的deep属性,默认false |
| immediate | 立即调用函数 | watch里的immediate属性,默认false,如果 |
| template | html结构 | vue里写html结构 |
| vue-cli | vue脚手架 | vue-cli俗称脚手架 |
| vue create 项目名 | 等待成功,并根据提示执行命令;如果卡住了按enter | |
| <vue + tab | 创建vue基本结构 | |
| vetur | vetur插件 | |
| lint | 线头;静态代码分析 | |
| eslint | 代码规范插件 | |
| lintOnSave | 在配置文件里关: vue.config.js,加如下一句话 lintOnSave: false | |
| components | 局部组件属性名 | components: { 组件名 } |
| component | 全局组件属性名 | Vue.component('组件名', 导入的组件) |