视频:【尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通】https://www.bilibili.com/video/BV1Zy4y1K7SH?vd_source=10e3dfac95ac3a6883b1f8a6c3bc65d5

看了很多市面上以后的笔记,大多都是复制粘贴代码,让我看的知其然而不知其所以然,于是打算自己写一下这个课程的笔记,把一些老师的讲解结合自己的理解也写下来

教程内容:

1.vue基础
2.vue-cli
3.vue-router
4.vuex
5.element-ui
6.vue3

注:因为笔者学习过程中需要参与一个小项目,该项目需要使用到vue,但是记详细的讲解比较较为耗时,所以在1.10之后的笔记是只记录使用方法和案例,不添加详细讲解。实际上,您可以直接访问官网的文档教程,如果您看了我的笔记的1.10之前的内容,理解官网的教程应该就比较简单了,如果有不理解的,再去看老师的讲解视频,个人觉得这是较快的学习方法(当然 ,时间充裕的,最好去听老师讲的课)

第1章 vue核心

1.1 vue简介

1.1.1vue是什么

一套用于构建用户界面的渐进式js框架

  • 构建用户界面:我只关注,你把数据给我,我怎么把数据变成界面

  • 渐进式:可以自底向上逐层应用:

    • 简单应用:只需要一个小巧的核心库
    • 复杂应用:可以引入各式各样的vue插件

1.1.2 谁开发的

1.1.3 vue的特点

  1. 采用组件化模式,提高代码复用率、且让代码更好维护。

组件化:

以后其他人想用这个activity功能,直接应用我的这个文件就行

更好维护:哪个部分出了问题,就到哪个组件维护

  1. 声明式编码,让编码人员无需直接操作DOM,提高开发效率。

js:用代码拼接html 这是命令式编码

命令式:同学,我渴了,你往前走两步,到饮水机面前,拿出杯子,倒点水,回头走到我旁边,往我嘴里倒水

声明式:同学,我渴了。然后同学就把水装给我了

  1. 使用虚拟DOM+优秀的Dif算法,尽量复用DOM节点。

咱们还是用js举例

原来你声明了变量,赋值以后写到html页面上,之后,如果你的数据变了,刷新页面的时候,相当于把原来的删除了,又从头添加了数据。

而vue呢,先把三个数据转换成虚拟dom,然后再转换成页面中的真实dom

数据变化之后,又生成了新的虚拟dom,他会把新的虚拟dom和原来的dom进行比较,然后会把原本的数据复用,再添加上多出来的dom(这里的赵六)

  1. 学习Vue之前要掌握的javaScript基础知识:
    ES6语法规范 结构函数,模板字符串,箭头函数
    ES6模块化 默认暴露,同意暴露,分别暴露
    包管理器 npm yarn cnpm
    原型、原型链
    数组常用方法 过滤一个数组,
    axios
    promise

当然,如果哪个不会,老师也会简单回顾一下

1.1.4 vue网站简单了解(vue2文档)

Vue.js (vuejs.org)

  1. 教程

按照教程说的一步一步来

  1. API

不会的就找字典

  1. 风格指南

会教你怎么写出优雅的vue代码

  1. 示例

看示例的时候,往右划一划,就能看到代码

  1. cookbook

编码技巧: 1 js基本功 2 vue代码一些小技巧

指南和cookbook的不同:指南教你什么好,什么不好;cookbook教你实用的技巧

  1. 工具 核心插件

公司开发时用到的 ,很重要

  1. Awssome vue/浏览和vue相关的包

很多vue的周边库(steam的创意工坊)

1.1.5 搭建vue开发环境

根据文档,安装

我们可以看到,一个是直接scipt引入vue,另外一个是使用npm安装

咱们先直接用引用

开发时,最好使用开发版本

点击后,自动下载,上面的是开发版,下面的是生产版,过会会进行对比

ok,我们在桌面新建一个文件夹,叫vue_basic

用vs code打开(不会有人前端已经学到vue了还不知道什么是vscode吧,不会吧不会吧)

把两个文件放在js文件夹中,新建html文件,新建完,!+回车;html结构就出来了

文件夹结构:

引入vue

<script type="text/javascript" src="../js/vue.js"></script>

如何证明我们引入了vue呢?

右键,在浏览器中打开(记得CTRL+s保存)

f12查看控制台,可以看到两个提示,一个说建议用开发工具开发vue,另一个说引入的vue有点大,不建议在生产环境中使用

输入vue,敲回车,发现有了构造方法,说明引用成功了

说回刚刚的问题,如何下载浏览器vue的开发工具,edge下载扩展

还要点上允许文件访问

另外一个提示我们如何隐藏呢,这是vue的全局配置中的一个属性,我们可以在文件中修改默认值

1.2 初识vue

1.2.1 vue小案例

首先,我们要添加一个存放页面的容器

容器,一般在11行,是一切的开始

输入 div#root 回车 得到:

创建一个Vue对象 在19行

然后我们需要

配置对象

什么叫配置对象:对象中有需要配置的属性:如anxios中要配置url,这个url你不能写成ura,因为不存在这个属性,url对应的值写在’’中,这是有规范的

好,我们开始写vue的配置对象

第一个属性 el

el是element的简称,里面的#root类似于css中的id选择器,没有第二十行的这个配置的时候,vue对象和id为root的容器是互相看不到的,加上之后,他们就互相匹配了

el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。

第二个属性 data

我们之前在容器中写的是hhh,那我们想在我们的实例中动态的存放那个位置填写的文字,怎么办呢

很自然的,第二个属性:data

data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象(以后可能写成一个函数)

这里用到了双大括号(插值语法,后面会讲到),这个实际上就是分隔符区分data的数据

写到这我们发现,const x一点用也没有,我们可以去掉,完全不受影响

总结

  1. 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象:

  2. root容器里的代码依然符html规范只不过混入了一些特殊的vue语法:

  3. root容器里的代码被称为【Vue模板】

1.2.2 分析小案例

  1. 容器和实例之间的关系是一对一的,一一对应
  2. 以后如果数据多了,会有组件功能来分担数据
  3. =={{}}==中必须写成js表达式

区分js表达式和js代码

  • js表达式:可以生成一个值,可以放在任何一个需要值的地方
    • a
    • a+b
    • Data.now() 生成当前时间戳
    • demo(1) 函数调用表达式
    • x==y ” />
    • vue开发者工具
    • 可以直接在这里修改数据

      1. 一旦data中的数据发生改变,那么模板中用到该数据的地方也会自动更新

      1.3 模板语法

      1.3.1 效果

      实际上,模板语法有两大类,一类就是{{}},插值语法

      还有一类叫指令语法

      比如,我们想在一个标签里,动态存入href的值,该怎么做呢,第一反应肯定是加一个{{}},我们试试看:

      我们发现,并没有帮我转换,看一下控制台的报错:

      说以前这样子写是可以的,但是现在不行了,建议我们用v-bind或者来写

      1.3.2 指令语法

      引入 v-bind

      我们在href前添加v-bind:

      <a v-bind:href="url">点我跳转</a>

      发现url动态的显示在href中了:

      v-bind:后的属性值后的双引号中的也是js表达式,且可以简写为

      简写:

       <a :href="url">点我跳转</a>

      插值模板主要用在标签体中

      指令语法主要用来管理标签属性

      总结:

      Vue模板语法有2大类:
      1.插值语法:
      功能:用于解析标签体内容。
      写法:{{xxx}}:xx是的s表达式。且可以直接读取到data中的所有属性。
      2.指令语法:
      功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)。
      举例:v-bind:href="xxx"域筒写为::href="xxx",xxx同样要列js表达式,且以直接读取到data中的所有属性.
      备注:Vue中有根多的指令,且形式都是:v-” />

      使用这样的方法区分不同的变量

      1.4 数据绑定

      1.4.1 单向数据绑定

      v-bind是单向数据绑定

      在这个input框中填写数据,data中name的值不会变,因为数据只能从data中到v-bind中

      实例1:

      容器:

      <div id="root"><input v-bind:value="name" /><hr/>{{name}}</div>

      一开始:

      input中输入数据后:

      1.4.2 双向数据绑定

      引出新的指令模板 v-model

       <input v-model:value="name" />

      v-model可以双向绑定,即在value中的数据也可以同步到data中:

      总结:

      v-model只能用在表单类元素中(输入类元素)

      也就是说,有一个属性是value的元素

      v-model:value=可以简写成v-model=

      番外 el和data的两种写法

      正常说讲到组件才要讲这个,但是组件内容太多了,所以拆到这里说一下

      el

      之前我们是在data中,通过el属性来绑定vue实例和容器的。

      除此之外,我们可以通过挂载的方式绑定

      <script> //创建Vue实例const v = new Vue({data: {name: "五六七",},});v.$mount("#root");</script> 

      v.$mount的这个操作叫挂载

      这两种方式都可以,第二种比较灵活一点

      data

      原来的方法:

      data:{name:''}<script> const v = new Vue({data:{name:''}});v.$mount("#root");</script>

      这是对象式写法,还有一种写法,叫函数式

      函数式:

      <script> const v = new Vue({data: function(){return{name:'尚硅谷'}}});v.$mount("#root");</script>

      el 两种方法都可以

      但是data,以后用到组件的时候,只可以用函数式,不然会报错,我们到时候会讲到

      由vue管理的函数,不可以用箭头函数(es6中的东西),写了箭头函数后,this就不再是vue实例了

      1.5 MVVM模型

      Vue的设计受到了MVVM模型的启发,设计时参考了这个模型

      1. M 模型(model) 对应data中的数据
      2. V 视图(View) 模板(页面结构)
      3. VM 视图模型(ViewModel) Vue实例对象

      其实主流的前端框架都是这样

      所以我们经常使用vm这个变量名表示Vue实例

      观察发现:
      1.data中所有的属性,最后都出现在了vm身上.
      2.vm身上所有的属性及Vue原型上所有属性,在Vue模版中都可以直接使用.

      console.log一下vue实例

      下面这些v的属性数据都可以写在模板中

      原型中的也可以写在里面(当然,写也没什么意义,这些是用来调用的方法)

      1.6 数据代理

      1.6.1 回顾 Object.defineProperty方法

      用于给对象添加属性

      需要三个参数

      第一个是对象 第二个是属性名 第三个是配置项

      <script type="text/javascript">let person={age:'18',name:'桃桃'}Object.defineProperty(person,'sex',{value:'女'})console.log(person)</script>

      用这种方法添加的属性,在遍历时不会参与遍历

      如果想要这个属性也可以参与遍历,在用方法添加时,在配置项中添加一个叫enumerable的属性

      <script>Object.defineProperty(person,'sex',{value:'女',enumerable:true})</script>

      用这种方法添加的属性,值也是不可以修改的:

      要是想修改,添加属性writable

      同理,也无法删除,想要删除,添加属性configurable

      这些是基本的配置项,除此之外,我们可以添加一些高级的配置项 get set

      比如我们不想要age的值是固定的,我们想要age的值是取决于一个叫做number的变量,然后number的值变了,age的值就会变,我们怎么写呢

      我们现在想要number值变了,我们的值也变,怎么办呢,使用Object.defineProperty方法配置项中的get属性

      <script type="text/javascript">let number = "女";let person = {age: "18",name: "桃桃",};Object.defineProperty(person, "sex", {// enumerable:true,// writable:true,// configurable:trueget:function(){return number}});console.log(person);</script>

      每一次访问sex,都会触发get方法的调用

      set方法:

      <script type="text/javascript">let number = "女";let person = {age: "18",name: "桃桃",};Object.defineProperty(person, "sex", {// enumerable:true,// writable:true,// configurable:trueget:function(){return number},set:function(value){number=value}});console.log(person);</script>

      每次有人修改sex的值,都会调用set方法

      1.6.2 何为数据代理

      通过一个对象代理对另一个对象中属性的操作

      比如有一个obj1对象,其中一个属性是x,我们想通过另一个obj2对象来获取和修改obj1中x属性的值,应该怎么做呢,这就可以用到上面学的东西

      <script type="text/javascript"> let obj1={x:100} let obj2={y:200} Object.defineProperty(obj2,'x',{get(){return obj1.x;},set(value){obj1.x=value;} })</script>

      模板语法中数据的值(data属性中数据的值)就是通过数据代理存放到vm(vue实例)中的

      1.6.3 数据代理在vue中的使用

      1.Vue中的数据代理:
      通过VM对象代理data对像中属性的操作(读/写)
      2.Vue中数据代理的好处:
      更加方便的操作data中的数据
      3.基本原理:
      通过Object,defineProperty()把data对象中所有属性添加到外vm上,
      为每一个添加到vm上的属性,都指定一个getter/setter.
      在getter/setter内部去操作(读/写)data中对应的属性.

      options是Vue的配置对象的意思

      vm._data实际上就是我们传给它的data

      所以以下这两种表达方式都是可 以的

      vm.data是用的数据代理

      数据代理图示:

      1.7 事件处理

      1.7.1 事件的基本使用:

      1. 使用v-on:xxx或@xxx绑定事件,其中xxx是事件名:
      2. 事件的回调需要配置在methods对象中,最终会在vm上:
      3. methods中配置的函数,不要用箭头函数!否则this就不是vm了:
      4. methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象:
      5. @click=”demo”和@click=”demo($event)”效果一到,但后者可以传参

      在button中,绑定一个v-on指令,在vue实例中添加一个新属性,methods,在里面添加方法,:

      <body><div id="root"><h1>{{name}}</h1><button v-on:click="clickme">别点我</button></div></body><script type="text/javascript">new Vue({el: '#root',data: {name: '桃桃'},methods:{clickme(){alert('让你别点,你个小坏蛋')}}})</script>

      此时在页面中点击按钮,就会弹出弹框

      如果我们在方法中添加一个参数,

      click(a){console.log(a);}

      在页面中点击时,发现打印在控制台的是点击事件

      这是老师以前讲的事件event(建议这部分去视频里听一下,因为我以前没学过,肯定讲不明白这个是什么东西,这个在视频的p14 事件处理中)

      我们把参数改为event,打印event.target这个是打印出事件触发的元素,也就是我们的button标签

      注意,所有被vue管理的函数不可以用箭头函数

      简写 v-on简写成@ v-on:click @click

      如果想要传参的话,就在click后双引号里方法名后加括号,里面写参数,不传参可以 不加括号

       <button v-on:click="clickme('hello')">别点我</button>

      当然,也可以直接传已定义的变量

      <button v-on:click="clickme(name)">别点我</button>

      这样的话,就把之前的event搞丢了,可以在括号中添加$event来接受事件

      1.7.2 事件修饰符

      Vue中的事件修饰符:

      1. prevent:阻止默认事件(常用)
      <a href="www.baidu.com" @click="sum">点我</a>

      正常点击这个按钮的时候,会先触发sum方法,然后跳转页面,如果我们不想a标签触发其默认事件(访问链接),我们可以在click后添加prevent,就不会访问了

      <a href="www.baidu.com" @click.prevent="sum">点我</a>

      2.stop:阻止事件冒泡(常用):

      当存在标签嵌套,且内外的标签都有调用的事件时,点击里面的标签,会像冒泡一样,触发外面标签的事件:

      <div @click="sum2"><button@click="sum">点我</button></div>

      如以上的代码,点击按钮时,会先触发sum方法,然后冒泡触发sum2方法,如果外面像阻止冒泡,可以在里面的click后添加.stop以阻止事件冒泡

      3.once:事件只触发一次(常用):

      这个就很好理解了,事件只触发一次

      后面三个不常用,我没怎么听懂,有学习需要的建议原视频

      4.capture:使用事件的捕获模式:
      5.self:只有event.target是当前操作的元素时才触发事件:
      6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕:

      如果需要多个修饰符,比如既要阻止冒泡,又要阻止默认行为,可以@click.prevent.stop这代表先阻止默认行为,再阻止冒泡。实际上他们哪个先阻止,效果是一样的

      1.7.3 键盘事件

      keydown,按下去就触发事件

      keyup,按下去,抬上来之后才出发事件

      event:当前事件

      event.target:当前事件操作的元素

      event.target.value 这是这个例子中input的value

      <input @keyup='print'>print(event){console.log(event.target.value);}

      效果:

      那问题来了,如果我们不想每次按键的时候都在控制台输出,而是按特定的案件才会输出,怎么办呢

      我们知道每一个按键都有一个keyCode值(没事,我也是才知道),我们可以先在控制台输出一下

      可以看到,每次按完按键都会输出按键对应的键码,

      我们输入回车,发现对应的键码是13,所以我们可以在方法中添加一个校验,如果触发当前事件的按键键码不是13,就不执行,这样,就只有回车时才会打印了。

      实际上,以上操作可以直接在@keyup后加.enter来完成:

      <input @keyup.enter='print'>print(event){console.log(event.target.value);}

      这里的enter是回车键的别名,@keyup.enter=’print’的意思是按下enter键后会触发print方法

      键盘的每一个按键,除了键码外也有自己对应的名字,keyu后可以添加每一个按键的名字

      我们可以这样获取当前按键的名字和键码:

      print(event) { console.log(event.key,event.keyCode); }

      .key就是按键的名字

      如果要按下ctrl键触发,可以写@keyup.Control或者@keyup.17

      如果要求按下ctrl+y触发,我们可以写@keyup.ctrl.y

      这里的ctrl是别名

      注意项:

      1. Vue中常用的按键别名:
        回车=>enter
        删除=>delete(捕获“删除”和“退格”键)
        退出=>esc
        空格=>space
        换行=>tab
        上=>up
        下=>down
        左=>1eft
        右=>right

      2. Vue未提供别名的按键,可以使用按键原始的key值去绑定,但由两个单词组成的要注意要转为kebab-case(短横线命名)

      3. 系统修饰键(用法特殊):ctrl、alt、shift、meta(win)
        (I).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
        (2).配合keydown使用:正常触发事件。

      4. 也可以使用keyCode去指定具体的按键(不推荐)

      5. Vue.config.keyCodes.自定义键名=键码,可以去定制按键别名

      1.8 计算属性

      我们现在要完成一个需求,就是在两个input框中分别填写姓和名,要求自动在后面拼写出完整的姓名

      为了横向对比,我们分别用{{}},methods,和计算属性完成这个需求

      1.8.1 {{}}

      这个就太简单了

      直接上代码

      <body><div id="root">姓:<input v-model="firstName"><br/>名:<input v-model="lastName"><br/>全名:<span>{{firstName}}+{{lastName}}</span></div></body><script type="text/javascript">new Vue({el: '#root',data: {firstName: '',lastName:''}})</script>

      1.8.2 methods

      可以在插值语法中调用方法,然后在方法中返回

      注意,如果在{{}}中的方法不加(),在页面中显示的是方法体,加了()之后,返回的才是方法中return的值,这和之前的绑定事件不一样

      <body><div id="root">姓:<input v-model="firstName"><br/>名:<input v-model="lastName"><br/>全名:<span>{{fullname()}}</span></div></body><script type="text/javascript">new Vue({el: '#root',data: {firstName: '',lastName:''},methods: {fullname(){return this.firstName+this.lastName}}})</script>

      1.8.3 computed 计算属性

      计算属性:
      1,定义:要用的属性不存在,要通过己有属性计算得来。
      2,原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
      3.get函数什么时候执行?
      (1).初次读取时会执行一次。
      (2).当依赖的数据发生改变时会被再次调用。
      4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
      5.备注:
      1,计算属性最终会出现在vm上,直接读取使用即可。
      2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。

      当我们需要的数据是从两个已有的属性中计算得来的,这个计算得来的新属性就被称作计算属性

      <script type="text/javascript">new Vue({el: '#root',data: {firstName: '',lastName: ''},computed: {fullname: {get() {return this.firstName + '-' + this.lastName}}}})</script>

      computed中的都是计算属性,和data很像,但是有get和set方法,底层是Objcet.defineproperty实现的,然后插值模板中直接写属性名就可以 了: {{fullname}}

      1.8.4 计算属性的简写

      当某一个计算属性只有get,没有set的时候,可以简写成函数的样子

      <script type="text/javascript">new Vue({el: '#root',data: {firstName: '',lastName: ''},computed: {fullname: function(){ //这一行也可以写成fullname(){ return this.firstName + '-' + this.lastName}}})</script>

      当然不要看到他长得像函数,就把他当成函数了,在{{}}中使用的时候,还是不能添加括号的。

      1.9 监视属性

      推荐插件

      Vue 3 Snippets 会提示vue代码

      1.9.1 watch 监视属性

      就是添加了一个新的配置项,watch,

      当watch中监视的数据发生改变时,就会调用watch中的方法

      直接引出watch中的方法,handler:

      <body><div id="root">姓:<input v-model="firstName"><br /><button @click="firstName++">点我</button></div></body><script type="text/javascript">new Vue({el: '#root',data: {firstName: 1},watch: {firstName: {handler() {console.log("firstname被改了")}}}})</script>

      在页面中点击按钮修改firstName的值的时候,就会调用watch中的handler方法

      handler可以接收两个参数,第一个是修改后的数据,第二个是修改前的数据:

      handler(newvalue,oldvalue) { console.log("firstname被改了" +newvalue+" "+oldvalue) }

      watch是在数据被修改之后,才会触发,如果在配置项中添加一个immediate属性,就会在一开始加载页面的时候,就触发一次:

      watch: {firstName: { handler() {immediate:true,console.log("firstname被改了")}}

      同时,计算属性中的数据也可以在watch中被监视,使用方法相同 。

      除了直接在vue()中配置以外,watch还可以在vue实例中手动配置:

      <script type="text/javascript">var vm = new Vue({el: '#root',data: {firstName: 1}})vm.$watch('firstName', {handler(newvalue, oldvalue) {console.log("firstname被改了" + newvalue + " " + oldvalue)}})</script>

      记得在vm.$watch()中,firstName要添加单引号,这是因为js中对象(还是变量?我不太清楚)需要用单引号表示,我们在vue中没有添加单引号是因为我们简写了。

      1.9.3 深度监视

      事情是这样的,当我们date中存储一个对象number,里面有数据a和b,我们改变这个a的值时,想要监视a的变化,而不是监视整个number的变化,该怎么做呢

      <div id="root">{{number.a}}<button@click="number.a++">点我增加</button></div><script type="text/javascript">new Vue({el:'#root',data:{ number:{a:1,b:1 }},watch:{'number.a':{handler(a,b){console.log("我又被改了"+a+b);}}}} )</script>

      没错,方法就是直接使用number.a,但是注意,我们在number.a边上添加了单引号,这是为什么呢。
      实际上,我们在使用这些变量名时都是引用的key,在语法规范中,key就是要添加单引号,但当只有一个单词时,在vue框架中可以省略这个单引号,但是当不是一个单词时,就要把单引号重新加上

      那如果我们想要当number中的a或者b任意一个改变了,就检测到number,我们该怎么做呢

      watch:{'number':{handler(a,b){console.log("我又被改了"+a+b);}}}

      我们发现,直接使用number,不起作用。

      实际上,number是这个对象的key,number后面的大括号实际上是这个对象的地址值,我们这样写,监视的就是对象的地址值,a变了,b变了,但是地址值是不会变的。

      如何让watch监视number中的值呢,我们在watch的number中添加一个配置项deep:

      watch:{number:{deep:true,handler(a,b){console.log("我又被改了"+a+b);}}}

      这样就会监视number中的数据的改变

      1.9.4 监视的简写

      当你的监视项只有一个handler时,就可以简写,就好像计算属性,当只有get方法的时候,就可以简写

      //原来的watch:{number:{handler(a,b){console.log("我又被改了"+a+b);}}}//修改后的: watch:{number(a,b){console.log("我又被改了"+a+b);}}

      或者,使用$f符添加,和之前的一样

       vm.$watch('number',{deep:true,handler(a,b){console.log("我被修改啦"+a+b)}})

      或者简写模式:

      vm.$watch('number',function(a,b){console.log("我被修改啦"+a+b)})

      1.9.5 computed和watch的区别

      总结:
      computed和watch之间的区别:
      1 computed能完成的功能,watch都可以完成。
      2 watch能完成的功能,computed.不一定能完成,例如:watch可以进行异步操作。

      两个重要的小原则:

      1. 所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象。
      2. 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象。

      1.8 class和style样式

      1.8.1 class样式

      我们使用:class来绑定动态的样式

      <div id="root"><div class="basic" :class="mood">{{number.a}}</div><div class="basic" :class="moodArr">{{number.b}}</div><div class="basic" :class="moodObj">{{number.b}}</div></div>...data:{ number:{a:1,b:2, }, mood:'happy', moodArr:['happy'], moodObj:{happy:true }},

      肯定的不需要改变的样式就放在class中,需要变化的就放在:class中

      1.8.2 style样式

      正常的内联style样式:

      <div class="basic" style="background-color:red">测试</div>···使用动态的style样式```html<div class="basic" :style="styleObj">{{number.b}}</div>...data:{ styleObj:{backgroundColor:'red' }},

      在style前面添加一个:就可以了,和class一样

      总结:
      绑定样式:
      1 c1ass样式
      写法:c1ass=“xxx”xxx可以是字符串、对象、数组。
      字符串写法适用于:类名不确定,要动态获取。
      对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
      数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
      2 style样式
      :style=”{fontsize:Xxx)“其中xxx是动态值。
      :style=”[a,b]”其中a、b是样式对象。

      1.9 条件渲染

      v-show

      <h1 v-show="true"></h1>

      当v-show后面的双引号中可以是true,false,1===3(false),或者是一个data中的变量a:

      <h1 v-show="a"></h1>...data:{a:true}

      v-if

      <h1 v-if="true"></h1>

      v-show是节点还在,只是动态的控制他的隐藏或者显示,而v-if是把整个节点全都弄没了

      v-else-if
      v-else

      <h1 v-if="n===1">1</h1><h1 v-else-if="n===2">2</h1><h1 v-else-if="n===3">3</h1><h1 v-else>4</h1>

      这四个需要连在一起,不可以被打断

      后面的用的比较多
      当我有三个相同判断条件的想简写:

      <h1 v-if="n===1">1</h1><h1 v-if="n===1">2</h1><h1 v-if="n===1">3</h1>

      如上,三个的判断条件都是一样的,该如何简化呢,第一反应肯定是在外面包上一个div:

      <div v-if="n===1"><h1>1</h1><h1>2</h1><h1>3</h1></div>

      但是这样会破坏我们页面的结构,比如我们要找body下的h1,就找不到了,所以我们可以使用另外一个标签:template

      <template v-if="n===1"><h1>1</h1><h1>2</h1><h1>3</h1></template>

      这个标签不会破坏页面的结构,但是template只能和v-if配合使用,不能和v-show配合使用

      1.10 列表渲染

      1.10.1 基本列表

      v-for 类似于for循环,
      当我们想要实现类似于下图的效果时,肯定是不能写死数据的,这就要我们通过遍历的方式显示数据

      在遍历数组时,数组元素后面的一个参数,是遍历时的key值,因为我们这里没有自定义key,所以默认是012<ul><li v-for="(person,b) in persons">{{b}}--{{person.name}}--{{person.age}}</li></ul>遍历对象时,括号中第一个参数是对象中键值对的值,第二个参数是键值对的键,第三个参数是这个这条遍历的数据的key<ul><li v-for="(value,key,b) in car">{{b}}--{{key}}--{{value}}</li></ul>遍历字符串时,括号中第一个参数是字符串这个位置的值,第二个参数是这个这条遍历的数据的key<ul><li v-for="(value,key) in str">{{key}}--{{value}}</li></ul>... data: {persons: [{ id: "001", name: "ice", age: "13" },{ id: "002", name: "peach", age: "12" },],car: {speed: "20km/h",year: "2014",},str: "i am a word",},

      展示效果:

      我们要求,每一个遍历的数据都需要一个独有的key,在第一个例子中,可以这样写

      <ul><li v-for="(person,index) in persons" :key="person.id"> {{index}}--{{person.name}}--{{person.age}}</li></ul>

      也可以直接写:key=“index”,这就代表默认的索引就是我们要的key
      具体关于key的下一节讲

      遍历指定次数:

      <ul><li v-for="(number,index) in 5" :key="index"> {{number}}--{{index}}</li></ul>

      1.10.2 key的原理和使用

      面试题:react、vue中的key有什么作用?(key的内部原理)

      1. 虚拟D0M中key的作用:
        key是虚拟DoM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DoM】,
        随后Vue进行【新虚拟DoM】与【旧虚拟DoM】的差异比较,比较规则如下:
      2. 对比规则:
        (1).旧虚拟DoM中找到了与新虚拟DoM相同的key:
        a.若虚拟D0M中内容没变,直接使用之前的真实D0M!
        b.若虚拟D0M中内容变了,则生成新的真实D0M,随后替换掉页面中之前的真实D0M。
        (2).旧虚拟DoM中未找到与新虚拟DoM相同的key
        创建新的真实DOM,随后渲染到到页面。
      3. 用index作为key可能会引发的问题:
        1,若对数据进行:逆序添加、逆序删除等破坏顺序操作:
        会产生没有必要的真实D0M更新==>界面效果没问题,但效率低。
        2.如果结构中还包含输入类的D0M:
        会产生错误D0M更新=>界面有问题。
      4. 开发中如何选择key” />

      1.10.3 列表过滤(查询效果)

      实现如下效果:


      两种方法:
      1watch监视:
      注意点:

      1. 使用一个数组persnsOfSearch来接受过滤后返回的值
      2. 在watch中添加一个immediate,已确保一开始的时候就运行一次watch来显示数据
      3. indexOf显示方法参数在字符串中第一次出现的索引,不存在的返回-1,如果方法参数是''空字符串,返回0
      <body><div id="root"><label>姓名:</label><input v-model="name"><ul><li v-for="(person) in persnsOfSearch">{{person.name}}--{{person.age}}</li></ul></div></body><script type="text/javascript">var vm = new Vue({el: '#root',data: {name: '',persnsOfSearch: [],persons: [{ id: '001', name: 'ice', age: '17' }, { id: '002', name: 'ipeach', age: '18' }, { id: '003', name: 'icepeach', age: '19' }]},watch: {name: {immediate: true,handler(newValue, oldValue) {this.persnsOfSearch= this.persons.filter((p) => {return p.name.indexOf(newValue) != -1})},}}})</script>

      使用计算属性实现:

      <body><div id="root"><label>姓名:</label><input v-model="name"><ul><li v-for="(person) in persnsOfSearch"> {{person.name}}--{{person.age}}</li></ul></div></body><script type="text/javascript">var vm = new Vue({el: '#root',data: {name:'',persons: [{ id: '001', name: 'ice', age: '17' }, { id: '002', name: 'ipeach', age: '18' }, { id: '003', name: 'icepeach', age: '19' }]},computed:{persnsOfSearch(){return this.persons.filter((p) => {return p.name.indexOf(this.name) != -1})} }})</script>

      可以看到,使用computes明显要更简单一些,所以当computed和watch都可以实现某个功能时,使用computed更好一些

      1.10.4 排序

      还是在computed中排序
      注意点:

      1. 在计算属性中,先过滤,后排序,把过滤好的数据暂时存到一个数组中,然后排序,再返回
      2. 使用sort(a,b)的方法来排序:
        若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
        若 a 等于b,则返回 0。
        若 a 大于 b,则返回一个大于 0 的值。
        简单点就是:比较函数两个参数a和b,返回a-b 升序,返回b-a 降序
        效果:
      <body><div id="root"><label>姓名:</label><input v-model="name"><button @click="sortType = 0">原顺序</button><button @click="sortType = 1">降序</button><button @click="sortType = 2">升序</button><ul><li v-for="(person) in persnsOfSearch">{{person.name}}--{{person.age}}</li></ul></div></body><script type="text/javascript">var vm = new Vue({el: '#root',data: {name: '',sortType: 0,//0 原顺序 1 降序 2 升序persons: [{ id: '001', name: 'ice', age: '17' }, { id: '002', name: 'ipeach', age: '18' }, { id: '003', name: 'icepeach', age: '19' }]},computed: {persnsOfSearch() {const arr = this.persons.filter((p) => {return p.name.indexOf(this.name) != -1})if (this.sortType) {arr.sort((p1, p2) => {return this.sortType === 1 " />.age - p1.age : p1.age - p2.age})}return arr;}}})</script>

      1.10.5 监视数据改变的原理

      Vue监视数据的原理:

      1. vue会监视data中所有层次的数据。
      2. 如何监测对象中的数据
        通过setter实现监视,且要在new Vue时就要传入要检测的数据
        (1).对象中后追加的属性,Vue默认不做响应式处理
        (2).如需给后添加的属性做响应式,请使用如下API:
        Vue.set(target,propertyName/index,value)或者
        vm.$set(target,propertyName/index,value)
      3. 如何监测数组中的数据?
        通过包裹数组更新元素的方法实现,本质就是做了两件事:
        (1).调用原生对应的方法对数组进行更新。
        (2).重新解析模板,进而更新页面。
      4. 在Vue修改数组中的某个元素一定要用如下方法:
        1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
        2.Vue.set()或者vm.set()特别注意:Vue.set()和vm.set() 特别注意:Vue.set()和vm. set()特别注意:Vue.set()vm.set()不能给vm或vm的根数据对象添加属性!!

      1.11 获取表单数据

      朋友们,这个很简单,我直接上总结了
      还可以参考官方这部分教程,例子要全一些:
      表单输入绑定
      收集表单数据:

      1. ,则v-model收集的是value值,用户输入的就是value值。
      2. ,则v-model收集的是value值,且要给标签配置value值。

      1.没有配置input的value属性,那么收集的就是checked(勾选or未勾选,是布尔值)
      2.配置input的value属性:
      (1)v-model的初始值是非数组,那么收集的就是checked(勾选or未勾选,是布尔值)
      (2)v-mode1的初始值是数组,那么收集的的就是va1ue组成的数组

      备注:v-mode1的三个修饰符:
      1azy:失去焦点再收集数据
      number:输入字符串转为有效的数字
      trim:输入首尾空格过滤

      1.12 过滤器

      过滤器在vue3中已经被取消了,而且过滤器能实现的功能,computed,methods之类的基本都能实现,所以简单概括
      过滤器:
      定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
      语法:

      1. 注册过滤器:Vue.filter(name,callback)或new Vue{filters:({}】
      2. 使用过滤器:{{xxx|过滤器名}}或v-bind:属性=“xxx | 过滤器名”
        备注
      3. 过滤器也可以接收额外参数、多个过滤器也可以串联
      4. 并没有改变原本的数据,是产生新的对应的数据

      1.13 内置指令

      1.13.1 v-text

      我们学过的指令:
      v-bind:单向绑定解析表达式,可简写为:xxx
      v-mode:双向数据绑定
      v-for:遍历数组/对象/字符串
      v-on:绑定事件监听,可简写为
      v-if:条件渲染(动态控制节点是否存存在)
      v-else:条件渲染(动态控制节点是否存存在)
      v-show:条件渲染(动态控制节点是否展示)
      v-text指令:
      1.作用:向其所在的节点中谊染文本内容。
      2.与插值语法的区别:V-text会替换掉节点中的内容,{{xx}}则不会。

      1.13.2 v-html指令

      1.作用:向指定节点中谊染包含html结构的内容。
      2.与插值语法的区别
      (1).v-html会替换掉节点中所有的内容,{{xx}}则不会.
      (2).v-html可以识别html结构.
      3.严重注意:v-htm1有安全性问题!!!!
      (1).在网站上动态渲染任意HTML是常危险的,容易导致XSS政击。
      (2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!

      1.13.3 v-cloak指令

      v-cloak指令(没有值):

      1. 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性.
      2. 使用css配合v-cloak可以解决网速慢时页面展示出{{xx}}的问题。
      <style>[v-cloak]{dispaly:none}</style>...<h2 v-cloak>{{}}</h2>

      1.13.4 v-once

      需求:如果我们想要展示某一个数据的初识值,即使数据被改变也只展示初识值,就可以使用v-once

      <h1 v-once>{{time}}</h1>

      1. v-once所在节点在初次动态渲染后,就视为静态内容了。
      2. 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。

      1.13.5 v-pre指令

      1.跳过其所在节点的编译过程。
      2.可利用它跳过过没有使用指令语法、没有使用插值语法的节点,会加快编译。

      就是说标签上加了这个之后,就不会再编译这一个标签了,所以只要我们用到了插值,指令就不要用这个

      <h2 v-pre>你好</h2><h2 v-pre>当前的值是:{{n}}</h2>

      1.13.6 自定义指令

      各位好啊,自定义指令的教程较为复杂,我有些犯懒了,这里就直接贴上老师的笔记了:

      1.14 生命周期

      分开的截图(为了让您看的更清晰一些):


      完整图:

      首先生命周期说的是Vue的生命周期而不是vm的生命周期
      vm的一生(vm的生命周期):
      将要创建===>调用beforeCreatei函数。
      创建完毕===>调用created函数。
      将要挂载===>调用beforeMount函数。
      (重要)挂载完毕===>调用mountedi函数。=======>【重要的钩子】
      将要更新===>调用beforeUpdatei函数。
      更新完毕===>调用updated函数。
      (重要)将要销毁===>调用beforeDestroyi函数。=====>【重要的钩子】
      销毁完毕==>调用destroyed函数。

      人生最重要的时刻:出生(mounted时候,我们一上来要做的事情都放在这)和将要离开的时候(beforeDestory 关闭你以前订阅的消息,关闭定时器,删除浏览记录之类的)

      2 组件

      好耶,我们终于进入第二章了!前面学了那么久,竟然还只是第一张,我真的栓Q,还好坚持到现在。
      学完组件,就开始学脚手架了,激动的嘞~

      我们要搞懂,什么是组件,为什么要用组件

      2.1 模块和组件,模块化和组件化

      传统的写页面的方式:
      写html,写css,写js,然后写新的页面时,复制相同的css,js代码,再加上自己的代码

      2023了,谁还用传统方式编程啊(md,我就是)

      模块:

      1. 理解:向外提供特定功能的js程序,一般就是一个js文件
      2. 为什么:js文件很多很复杂
      3. 作用:复用js,简化js的编写,提高js运行效率

      组件:

      1. 理解:用来实现局部特定)功能效果的代码集合(html/css/js/image.)
      2. 为什么:一个界面的功能很复杂
      3. 作用:复用编码,简化项目编码,提高运行效率

      模块化:当应用中的js都以模块来编写的,那这个应用就是一个模块化的应用。

      组件化:当应用中的功能都以组件的方式来编写,那这个应用就是一个组件化的应用。

      2.2 非单文件组件

      2.2.1 基本使用

      创建组件的api:Vue.extend({})
      大括号里面,几乎和我们之前写vm一样,该data就data,该methods就methods
      但是不能用el哦

      Vue中使用组件的三大步骤:
      一、 定义组件(创建组件)
      二、 注册组件
      三、 使用组件(写组件标签)
      一、如何定义一个组件?
      使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别:
      区别如下:

      1. el不要写,为什么?
        最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
      2. data必须写成函数,为什么?
        避免组件被复用时,数据存在引用关系。
        备注:使用template可以配置组件结构。
        二、如何注册组件?
        1.局部注册:靠new Vue的时候传入components选项(只在这一个实例里生效)
        2.全局注册:靠Vue.component(‘组件名’,组件)
        三、
        编写组件标签:
      <body><div id="root"><hello></hello><hr><h1>{{msg}}</h1><hr><school></school><hr><student></student></div><div id="root2"><hello></hello></div></body><script type="text/javascript">Vue.config.productionTip = false//第一步:创建school组件const school = Vue.extend({template:`

      学校名称:{{schoolName}}

      学校地址:{{address}}

      `
      ,// el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。data(){return {schoolName:'江南大学',address:'无锡'}},methods: {showName(){alert(this.schoolName)}},})//第一步:创建student组件const student = Vue.extend({template:`

      学生姓名:{{studentName}}

      学生年龄:{{age}}

      `
      ,data(){return {studentName:'桃桃',age:18}}})//第一步:创建hello组件const hello = Vue.extend({template:`

      你好啊!{{name}}

      `
      ,data(){return {name:'Tom'}}})//第二步:全局注册组件Vue.component('hello',hello)//创建vmnew Vue({el:'#root',data:{msg:'你好啊!'},//第二步:注册组件(局部注册)components:{school,student}})new Vue({el:'#root2',})
      </script>

      2.2.2 注意项

      几个注意点:

      1. 关于组件名:
        一个单词组成:
        第一种写法(首字母小写):school
        第二种写法(首字母大写):School
        多个单词组成:
        第一种写法(kebab-case命名):my-school
        第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
        备注:
        (1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
        (2).可以使用name配置项指定组件在开发者工具中呈现的名字。
      //定义组件const s = Vue.extend({name:'peach',template:`<div><h2>学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2></div>`,data(){return {name:'尚硅谷',address:'北京'}}})

      之后,开发者工具中显示的名字就是peach了
      2. 关于组件标签:
      第一种写法:
      第二种写法:
      备注:不用使用脚手架时,会导致后续组件不能渲染。

      1. 一个简写方式:
        const school = Vue.extend(options) 可简写为:const school = options

      2.2.3 嵌套组件

      实际上,嵌套组件就是前两节的使用,只不过是在创建一个组件时,本身再添加之前创建的组件,没有什么其他的东西,很多同学觉得困难,是因为前两节没学好

      <body><div id="root"></div></body><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。//定义student组件const student = Vue.extend({name:'student',template:`

      学生姓名:{{name}}

      学生年龄:{{age}}

      `
      ,data(){return {name:'尚硅谷',age:18}}})//定义school组件const school = Vue.extend({name:'school',template:`

      学校名称:{{name}}

      学校地址:{{address}}

      `
      ,data(){return {name:'尚硅谷',address:'北京'}},//注册组件(局部)components:{student}})//定义hello组件const hello = Vue.extend({template:`

      {{msg}}

      `
      ,data(){return {msg:'欢迎来到尚硅谷学习!'}}})//定义app组件const app = Vue.extend({template:``,components:{school,hello}})//创建vmnew Vue({template:'',el:'#root',//注册组件(局部)components:{app}})
      </script>

      2.2.4 关于VueComponent

      1. school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
      2. 我们只需要写或,Vue解析时会帮我们创建school组件的实例对象,
        即Vue帮我们执行的:new VueComponent(options)。
      3. 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
      4. 关于this指向:
        (1).组件配置中:
        data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
        (2).new Vue(options)配置中:
        data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
      5. VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
        Vue的实例对象,以后简称vm。

      实际上 vc和vm是很像的双胞胎

      2.2.5

      首先我们要知道一个前置知识:
      这段看不懂的,需要去学一下es6中的高级js知识

      <script>//定义一个构造函数 function Demo(){this.a = 1this.b = 2}//创建一个Demo的实例对象const d = new Demo()console.log(Demo.prototype) //显示原型属性console.log(d.__proto__) //隐式原型属性console.log(Demo.prototype === d.__proto__)//程序员通过显示原型属性操作原型对象,追加一个x属性,值为99Demo.prototype.x = 99console.log('@',d) </script>

      各位好,为了速成(做项目),我先不看视频了找个笔记去学一下
      看的这个笔记:
      笔记地址

      组件的自定义事件总结:

      全局事件总线

      消息订阅

      axios


      上图中2,3都是封装的1,如果1不能用了,2,3就都不能用了。
      然后jQuery的80%内容都在封装dom,剩下的才是封装一些周边的东西,比如$.get,$.post
      然后fetch和xhr是平级的,但是有两个问题,就是它封装了两次promise,所以要then两次才能拿到数据,然后它存在兼容性问题,比如ie浏览器就不可以使用fetch
      综上,我们使用axios

      首先,我们写一个axios的get

      运行的时候我们发现,哎呀妈呀跨域了,为什么会跨域呢,原因是我们违背了同源原则
      同源原则:协议名,主机名,端口号
      如下图,端口号对不上

      实际上,我们请求之后,服务器是收到了请求,而且把数据返回了,但是浏览器一看,哎不同源,就把数据藏起来了

      解决方法
      1cors:
      在服务器里,返回数据的时候,添加了一些请求头,然后浏览器一看,你都这么表态了,那我就把数据给你吧。所以在服务器解决跨域问题才是真正的解决跨域

      2 jsonp
      只能解决get请求的

      3 配置代理服务器

      使用方法:1 nginx(有点麻烦) 2 vue-cli

      vue-cli:
      添加配置的第一种方法:

      vue-cli添加配置的第er二种方法

      加上·pathRewrite:{'/atguigu':''的意思是,在把请求中的atguigu去掉

      总结:


      vuex

      我们现在用的是vue2,所以要安装vuex3