视频:【尚硅谷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的特点
- 采用组件化模式,提高代码复用率、且让代码更好维护。
 
组件化:

以后其他人想用这个activity功能,直接应用我的这个文件就行
更好维护:哪个部分出了问题,就到哪个组件维护
- 声明式编码,让编码人员无需直接操作DOM,提高开发效率。
 
js:用代码拼接html 这是命令式编码

命令式:同学,我渴了,你往前走两步,到饮水机面前,拿出杯子,倒点水,回头走到我旁边,往我嘴里倒水
声明式:同学,我渴了。然后同学就把水装给我了
- 使用虚拟DOM+优秀的Dif算法,尽量复用DOM节点。
 
咱们还是用js举例
原来你声明了变量,赋值以后写到html页面上,之后,如果你的数据变了,刷新页面的时候,相当于把原来的删除了,又从头添加了数据。

而vue呢,先把三个数据转换成虚拟dom,然后再转换成页面中的真实dom
数据变化之后,又生成了新的虚拟dom,他会把新的虚拟dom和原来的dom进行比较,然后会把原本的数据复用,再添加上多出来的dom(这里的赵六)

- 学习Vue之前要掌握的javaScript基础知识:
ES6语法规范 结构函数,模板字符串,箭头函数
ES6模块化 默认暴露,同意暴露,分别暴露
包管理器 npm yarn cnpm
原型、原型链
数组常用方法 过滤一个数组,
axios
promise 
当然,如果哪个不会,老师也会简单回顾一下
1.1.4 vue网站简单了解(vue2文档)
Vue.js (vuejs.org)
- 教程
 
按照教程说的一步一步来
- API
 
不会的就找字典
- 风格指南
 
会教你怎么写出优雅的vue代码
- 示例
 
看示例的时候,往右划一划,就能看到代码
- cookbook
 
编码技巧: 1 js基本功 2 vue代码一些小技巧
指南和cookbook的不同:指南教你什么好,什么不好;cookbook教你实用的技巧
- 工具 核心插件
 
公司开发时用到的 ,很重要
- 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一点用也没有,我们可以去掉,完全不受影响

总结
- 
想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象:
 - 
root容器里的代码依然符html规范只不过混入了一些特殊的vue语法:
 - 
root容器里的代码被称为【Vue模板】
 
1.2.2 分析小案例
- 容器和实例之间的关系是一对一的,一一对应
 - 以后如果数据多了,会有组件功能来分担数据
 - =={{}}==中必须写成js表达式
 
区分js表达式和js代码
- js表达式:可以生成一个值,可以放在任何一个需要值的地方
- a
 - a+b
 - Data.now() 生成当前时间戳
 - demo(1) 函数调用表达式
 - x==y ? ‘a’:‘b’ 三元表达式
 - 以上的东西都是可以在左边用一个const x= 接住的
 
 - js代码(语句)
- if(){}
 - for(){}
 
 
- vue开发者工具
 

可以直接在这里修改数据
- 一旦data中的数据发生改变,那么模板中用到该数据的地方也会自动更新
 
1.3 模板语法
1.3.1 效果
实际上,模板语法有两大类,一类就是{{}},插值语法
还有一类叫指令语法
比如,我们想在一个<a href=""></a>标签里,动态存入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-???,此处我们只是拿v-bind举个例子。
如果一个页面有多个地方,需要name这个变量怎么办:
我们可以name1,name2但是可读性不高,所以我们可以在data中再新建对象,如图:

使用这样的方法区分不同的变量
1.4 数据绑定
1.4.1 单向数据绑定
v-bind是单向数据绑定
<input v-bind:value="name">
在这个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模型的启发,设计时参考了这个模型
- M 模型(model) 对应data中的数据
 - V 视图(View) 模板(页面结构)
 - 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:true
        get: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:true
        get: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 事件的基本使用:
- 使用v-on:xxx或@xxx绑定事件,其中xxx是事件名:
 - 事件的回调需要配置在methods对象中,最终会在vm上:
 - methods中配置的函数,不要用箭头函数!否则this就不是vm了:
 - methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象:
 - @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中的事件修饰符:
- 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是别名
注意项:
- 
Vue中常用的按键别名:
回车=>enter
删除=>delete(捕获“删除”和“退格”键)
退出=>esc
空格=>space
换行=>tab
上=>up
下=>down
左=>1eft
右=>right - 
Vue未提供别名的按键,可以使用按键原始的key值去绑定,但由两个单词组成的要注意要转为kebab-case(短横线命名)
 - 
系统修饰键(用法特殊):ctrl、alt、shift、meta(win)
(I).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
(2).配合keydown使用:正常触发事件。 - 
也可以使用keyCode去指定具体的按键(不推荐)
 - 
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可以进行异步操作。
两个重要的小原则:
- 所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象。
 - 所有不被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的内部原理)
- 虚拟D0M中key的作用:
key是虚拟DoM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DoM】,
随后Vue进行【新虚拟DoM】与【旧虚拟DoM】的差异比较,比较规则如下: - 对比规则:
(1).旧虚拟DoM中找到了与新虚拟DoM相同的key:
a.若虚拟D0M中内容没变,直接使用之前的真实D0M!
b.若虚拟D0M中内容变了,则生成新的真实D0M,随后替换掉页面中之前的真实D0M。
(2).旧虚拟DoM中未找到与新虚拟DoM相同的key
创建新的真实DOM,随后渲染到到页面。 - 用index作为key可能会引发的问题:
1,若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实D0M更新==>界面效果没问题,但效率低。
2.如果结构中还包含输入类的D0M:
会产生错误D0M更新=>界面有问题。 - 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序刚除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
 
1.10.3 列表过滤(查询效果)
实现如下效果:
 
 
 两种方法:
 1watch监视:
 注意点:
- 使用一个数组persnsOfSearch来接受过滤后返回的值
 - 在watch中添加一个immediate,已确保一开始的时候就运行一次watch来显示数据
 - 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中排序
 注意点:
- 在计算属性中,先过滤,后排序,把过滤好的数据暂时存到一个数组中,然后排序,再返回
 - 使用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 ? p2.age - p1.age : p1.age - p2.age
                        })
                    }
                    return arr;
                }
            }
        }
    )
</script>
1.10.5 监视数据改变的原理
Vue监视数据的原理:
- vue会监视data中所有层次的数据。
 - 如何监测对象中的数据
通过setter实现监视,且要在new Vue时就要传入要检测的数据
(1).对象中后追加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value)或者
vm.$set(target,propertyName/index,value) - 如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1).调用原生对应的方法对数组进行更新。
(2).重新解析模板,进而更新页面。 - 在Vue修改数组中的某个元素一定要用如下方法:
1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
2.Vue.set()或者vm.
s
e
t
(
)
特别注意:
V
u
e
.
s
e
t
(
)
和
v
m
.
set() 特别注意:Vue.set()和vm.
set()特别注意:Vue.set()和vm.set()不能给vm或vm的根数据对象添加属性!! 
1.11 获取表单数据
朋友们,这个很简单,我直接上总结了
 还可以参考官方这部分教程,例子要全一些:
 表单输入绑定
 收集表单数据:
- ,则v-model收集的是value值,用户输入的就是value值。
 - ,则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之类的基本都能实现,所以简单概括
 过滤器:
 定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
 语法:
- 注册过滤器:Vue.filter(name,callback)或new Vue{filters:({}】
 - 使用过滤器:{{xxx|过滤器名}}或v-bind:属性=“xxx | 过滤器名”
备注 - 过滤器也可以接收额外参数、多个过滤器也可以串联
 - 并没有改变原本的数据,是产生新的对应的数据
 
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指令(没有值):
- 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性.
 - 使用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>

- v-once所在节点在初次动态渲染后,就视为静态内容了。
 - 以后数据的改变不会引起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,我就是)
模块:
- 理解:向外提供特定功能的js程序,一般就是一个js文件
 - 为什么:js文件很多很复杂
 - 作用:复用js,简化js的编写,提高js运行效率
 
组件:
- 理解:用来实现局部特定)功能效果的代码集合(html/css/js/image.)
 - 为什么:一个界面的功能很复杂
 - 作用:复用编码,简化项目编码,提高运行效率
 
模块化:当应用中的js都以模块来编写的,那这个应用就是一个模块化的应用。
组件化:当应用中的功能都以组件的方式来编写,那这个应用就是一个组件化的应用。
2.2 非单文件组件
2.2.1 基本使用
创建组件的api:Vue.extend({})
 大括号里面,几乎和我们之前写vm一样,该data就data,该methods就methods
 但是不能用el哦
Vue中使用组件的三大步骤:
 一、 定义组件(创建组件)
 二、 注册组件
 三、 使用组件(写组件标签)
 一、如何定义一个组件?
 使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别:
 区别如下:
- el不要写,为什么?
最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。 - 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:`
				<div class="demo">
					<h2>学校名称:{{schoolName}}</h2>
					<h2>学校地址:{{address}}</h2>
					<button @click="showName">点我提示学校名</button>	
				</div>
			`,
			// el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。
			data(){
				return {
					schoolName:'江南大学',
					address:'无锡'
				}
			},
			methods: {
				showName(){
					alert(this.schoolName)
				}
			},
		})
		//第一步:创建student组件
		const student = Vue.extend({
			template:`
				<div>
					<h2>学生姓名:{{studentName}}</h2>
					<h2>学生年龄:{{age}}</h2>
				</div>
			`,
			data(){
				return {
					studentName:'桃桃',
					age:18
				}
			}
		})
		//第一步:创建hello组件
		const hello = Vue.extend({
			template:`
				<div>	
					<h2>你好啊!{{name}}</h2>
				</div>
			`,
			data(){
				return {
					name:'Tom'
				}
			}
		})
		//第二步:全局注册组件
		Vue.component('hello',hello)
		//创建vm
		new Vue({
			el:'#root',
			data:{
				msg:'你好啊!'
			},
			//第二步:注册组件(局部注册)
			components:{
				school,
				student
			}
		})
		new Vue({
			el:'#root2',
		})
	</script>
2.2.2 注意项
几个注意点:
- 关于组件名:
一个单词组成:
第一种写法(首字母小写):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. 关于组件标签:
 第一种写法:<school></school>
 第二种写法:<school/>
 备注:不用使用脚手架时,会导致后续组件不能渲染。
- 一个简写方式:
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:`
				<div>
					<h2>学生姓名:{{name}}</h2>	
					<h2>学生年龄:{{age}}</h2>	
				</div>
			`,
			data(){
				return {
					name:'尚硅谷',
					age:18
				}
			}
		})
		//定义school组件
		const school = Vue.extend({
			name:'school',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
					<student></student>
				</div>
			`,
			data(){
				return {
					name:'尚硅谷',
					address:'北京'
				}
			},
			//注册组件(局部)
			components:{
				student
			}
		})
		//定义hello组件
		const hello = Vue.extend({
			template:`<h1>{{msg}}</h1>`,
			data(){
				return {
					msg:'欢迎来到尚硅谷学习!'
				}
			}
		})
		//定义app组件
		const app = Vue.extend({
			template:`
				<div>	
					<hello></hello>
					<school></school>
				</div>
			`,
			components:{
				school,
				hello
			}
		})
		//创建vm
		new Vue({
			template:'<app></app>',
			el:'#root',
			//注册组件(局部)
			components:{app}
		})
	</script>
2.2.4 关于VueComponent
- school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
 - 我们只需要写或,Vue解析时会帮我们创建school组件的实例对象,
即Vue帮我们执行的:new VueComponent(options)。 - 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
 - 关于this指向:
(1).组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
(2).new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。 - VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
Vue的实例对象,以后简称vm。 
实际上 vc和vm是很像的双胞胎
 
2.2.5
首先我们要知道一个前置知识:
 这段看不懂的,需要去学一下es6中的高级js知识
<script>
//定义一个构造函数
		 function Demo(){
			this.a = 1
			this.b = 2
		}
		//创建一个Demo的实例对象
		const d = new Demo()
		console.log(Demo.prototype) //显示原型属性
		console.log(d.__proto__) //隐式原型属性
		console.log(Demo.prototype === d.__proto__)
		//程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
		Demo.prototype.x = 99
		console.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
 ![]()