Vue笔记

171 阅读19分钟

Vue笔记

1.mvvm(双向数据绑定)

  • model 数据模型(js对象)
  • viewModel 视图模型(vue实例)
  • view视图(html+css)

​ vue实现的是 数据映射到视图 视图事件绑定数据 vue实例实现中间桥梁 render(data) => view

​ 开发者只需要关心数据的变更,视图的更新交给vue

2.渐进式理解

  1. 声明式渲染(无需关心如何实现)
  2. 组件系统
  3. 客户端路由(vue-router)
  4. 大规模状态管理(vuex)
  5. 构建工具(vue-cli)

3.vue的两个核心点

​ 1.响应的数据变化

​ 当数据发生变化 -> 视图的自动更新

​ 2.组件的视图组件

​ ui页面映射为组件树 划分组件可维护.可复用.可测试

4.vue的安装方法 单文件

1.引入csdn的文件

<script src="https://cdn.jsdelivr.net/npm/vue"></script>

2.通过npm安装

​ npm install vue 安装vue的包

​ 然后用script 引入node_modules/vue/dist/vue.js

5.引入vue后的一个Vue构造函数

let vm = new Vue({
    el:""    ->指定vue需要管理的部分(视图),不能挂载到html和body
    data:{
    	msg:''		//data中的数据会被vm代理  可以通过vm实例来取里面的内容
		}
})

el:"" 可以指定html部分,跟querySelector的操作一样

data:{ } vm构造对象中数据模型 vue中用来存放数据的地方

6在视图中显示数据

在管理的dom可以使用 {{}} 来使用data中的数据 当数据改变时 视图中也会改变

  <div id='app'>{{msg}}</div>

{{ }} 中 可以放表达式 放赋值语句 取值 三目运算符

{{msg=='huaixu'?1:0}}

7.视图控制数据

表单元素 修改内容绑定视图修改

表单元素 -> input checkbox textarea radio select

vue指令 -> 只是dom上的行间属性 vue给这类属性赋予了一定的意义 来实现特殊的功能 所有指令都以 v- 开头 value属性默认情况下会vue忽略掉 select checked 都没有意义

v-model => 表单和数据的双向绑定

在只有一个chebox的情况下 会把此值转化为boolean类型 如果为true表示选中

如果是多个的话 需要使用value属性并且数据类型是数组 会把选中的数据加入数值中

<input  type='text' v-model='msg'>
v-model 会将msg的值 会赋予输入框,输入框的值改变了会影响数据

<input  type='checkbox' v-model='msg' value='草莓'>
data:{msg:[]}
checkbox如果选中的情况下 会把value值写入其绑定的数组中

v-model中的修饰符

.number 如果不是数字不会修改数据 .lazy 当鼠标点击其他位置才会修改数据

v-text =>在dom中绑定数据

​ 使用{{}} 当网络或者网页加载慢时 会出现原始状态 所以一般使用v-text或者把引入js文件写在之前(不建议)

v-once => 只绑定一次 当数据再次发生变化 也不导致数据刷新

<div v-once></div>

v-html => 把html字符串当做html渲染,一定是可以信任的html(可能有漏洞)

​ 直接用数据的话会把数据的值直接显示,但是有些可能是html代码,所以可以使用v-html 将代码显示为html结构

8.数据响应的变化

​ vue会循环data中的所有数据(数据劫持) 依次增加getter setter

1.使用变量时 先要初始化 否则新加的属性 不会导致页面刷新

new Vue({
	el:'',
	data:{
	a:{	
			school:""
		}			
	}
})
{{a.school}}  -> 在视图使用data中对象的属性

2.vm.$set() 时 此方法可以给对象添加响应式的数据变化

3.替换原对象 -> vm.a = { school:'zzzzz'}

9.data中数组数据

1.改变数组中的某一项是监控不到的

2.也不能使用改变数组长度的方法

data:{ arr:['1','2','3']}
//错误演示     vm.arr[0] = 100;
//错误		vm.arr.length -=2;

3.改变数组的方法可以使用 pop push shift unshift sort reserve splice

4.以及遍历数组的方法

vm.arr = vm.arr.map(item => item*3)    可以导致页面刷新

10.v-for

以前的循环数据 -> 拼接字符串 innerHTML

vue提供一个指令 v-for 解决循环问题 更高效 会复用原有的机构

要循环谁就在谁身上增加v-for属性 默认是 value of 数据

<div v-for='item in items'>{{item}}  </div>

写一个参数是子项 第二个参数是索引 (item,index) in arr

<div v-for='(item,index) in items'>{{item}}  ---{{index}}  </div>

v-for 的其他运用

<div v-for="a in 'aaaa'">{{a}}  </div><div v-for='a in 10'>{{a}}  </div>

v-for 对象 能拿到里面的每一项

<div v-for='(value,key,index) in object'>{{index}}:{{key}}:{{value}}  </div>

11.v-on vue事件

以前的添加事件的方法 -> 获取对象 再添加事件 | 行内绑定的方法 都是window上的 局部的方法绑定不到

vue中绑定事件的指令 v-on:事件名 简写 @事件名

事件名带参数的情况下可以写 参数 不用带参数就可以不用写

<div v-on:click=''>  </div>

methods:{} -> vue对象中放方法的地方 data中也能写方法 但是最好是写在methods中

不能重复声明 methods和data中的数据会全部被放到vm上,而且名字不能冲突 冲突会报错 methods中的this都是指向的实例

<div v-on:click='fn'>  </div>methods:{ 	fn:function(){ 			alert(this.a.name)	}}

传事件对象

1.写括号 fn() -> methods接收写个形参 可以获得事件对象

2.手动传递事件对象 fn($event,111) -> fn(event,number) (形参)

事件修饰符

@click.stop -> 阻止事件冒泡 修饰符 .stop

@事件.capture -> 事件捕获

@事件.prevent -> 阻止默认事件

@事件.once ->只能触发一次

@事件,self -> 只有点击自己的时候会触发

12.axios在vue中的使用

vue有专门的方法来发送ajax请求 那就是created生命周期钩子函数 在数据被初始化后调用,this的指向也是vm实例

下载axios ->

npm  install axios

然后再script标签引入

axios的写法

created(){
	axios.get('url').then((res)=>{
		this.arr = res.data
	})
}
import axios from  'axios'

// 设置默认的请求前缀
axios.defaults.baseURL = 'http://localhost:3000';

axios.interceptors.response.use(res => {
      return  res.data                //在这里统一拦截结果  吧结果处理成res.data
});

//封装axios请求的方法
// 获取轮播图数据  返回的是一个promise对象
export let getSliders = () =>{
      return axios.get('/sliders')
}

//获取热门图书接口
export let getHotBook = () =>{
        return axios.get('/hot')
}

哪里用哪里引入axios 第三方模块 直接在vue组件中引用就可以了 官方组件需要在main.js中引用

13.promise 解决回调问题

传统回调函数写法

function buy(callback){	setTimeout(function(){		let a = 'baicai';		callback(a);	},2000)}buy(function(val){	console.log(val)})

回调函数: 将后续的处理逻辑传入当前要做的事, 事情做好后调用此函数

promise 解决回调问题的 promise三个状态

  • 成功状态 resolve
  • 失败状态 reject
  • 等待状态 pending
  1. resolve 代表的是转向成功态

  2. reject 代表的是转向失败态

  3. resolve和reject都是函数

promise的实例就一个then方法

then方法有两个参数 也就是promise构造方法带的两个方法参数 在promise中使用这两个参数 也就是调用then里面的方法

resolve调用的是then方法参数一这个方法 reject调用的是then方法中参数二这个方法 已经写死了

let app = new Promise((resolve,reject)=>{        resolve('das')      })app.then(  (resolve)=>{  },(reject)=>{  })

14.v-bind 绑定样式

在视图中给dom加上 v-bind属性 可以绑定实例中的data属性

<div v-bind:title='xx'></div>//此时完成了  dom的title与实例中data数据的绑定

v-bind 可以简写为 :属性名 =''

<div :title='xx'></div>//与上面的操作一样

使用v-bind 绑定css样式

:class 绑定的样式和class绑定的不冲突

​ 1.第一种方式 对象

x y z 是表示定义class样式<div class="x"  :class="{z:true,y:flag1}"> 	我是真的帅</div>对象 写法  {className:isActive}  -> 通过指定isActive这个变量来决定这个class是否使用  也可以直接写boolean值

​ 2.第二种方式 数组

 <div class="x"  :class="[class1,class2,{y:true}}]">  我是真的帅 </div>data:{    class1:'x',    class2:'y'}在data中给变量指定css类名,然后在视图中通过数组 写入,写在数组里面的变量或者 样式都会被使用 已定义的就会生效  如果没有定义就不会生效也可以嵌套第一种方式

行内样式的写法

对象写法

<div style='font-size:30px;'  :style="{backgroundColor:red,color:'pink'}"> 

数组写法

data:{	style1:{backgroundColor:red}	style2:{color:pink}}<div :style="[style1,style2,{fontSize:'30px'}]"

15.filter 过滤器

实例中filter, 用来写过滤器的一个集合对象

过滤器中的自定义方法(toFixed) 参数一 代表的是管道符( | ) 右边的内容 参数二可以通过调用过滤器方法 传递参数

 //vue 实例  filter:{  						toFixed(input,num){   //这里的this指向的是window                  return input.toFixed(num);          	}				} //视图      在视图通过 过滤器处理要展示的数据 相当于调用该方法 获取新的返回值           {{ item.productCount*item.productPrice | toFixed(2)}}

在视图中使用 | toFixed 就会调用过滤器里面的方法 不会改变原数据 只是改变视图中的显示效果

16.v-if v-show

v-if 是操作的是dom show操作的是样式

如果频繁切换dom 使用 v-show 当数据一开始确定下来就使用v-if

v-if 如果是false 就不会渲染这个元素 以及这个元素里面的元素

v-if 可以配合 v-else 连着使用

默认情况下 在切换dom时 相同结构会被复用 如果不需要复用 需要加 key

<div v-if='false' key='1'></div>

17.vue动画

只有dom从显示到隐藏,或者隐藏到显示,才能使用vue动画

transition
<transition>  	<div v-show="flag">demo</div></transition>

然后通过控制这个组件实现一些动画 在css中写这些样式 .v-xx 是控制所有的transition组件

//进入.v-enter{    opacity: 0;}//进入动画.v-enter-active{  transition: 1s linear;}//结束动画.v-leave-active{  opacity: 0; transition: 1s linear;}

可以给每个transitionname属性 进行单独控制

<transition name='jw'>      <div v-show="flag">demo</div> </transition>
.jw-enter{
    opacity: 0;
}
.jw-enter-active{
  transition: 1s linear;
}
.jw-leave-active{
    opacity: 0; transition: 1s linear;
}

18.animate.css动画库

安装:  npm install animate.css

引入animate.css

import 'animate.css'

然后再transition组件 加上进入和离开动画属性 属性值必须以animated开头 使用animate的class名

<transition 
    enter-active-class="animated bounceInUp" 
   	leave-active-class="animated  bounceOutDown">
        <div v-show="flag">我爱你</div>
 </transition>

transition 只能用于单个元素 不能用于多个元素

transition-group 用于多个元素动画时 必须加上索引 key 来区别不同的元素

v-for 默认会复用原有的dom元素 如果加了key 而且key不同他会认为是两个人了

19.computed 计算属性

computed 计算' 属性 ' 不是方法

1.方法不会有缓存,computed会根据依赖(归Vue管理的数据,可以响应式变化的)的属性进行缓存

2.两部分组成由getset(不能只写set) 一般情况下通过js赋值影响其他人或表单元素设置值的时候会调用set方法

3.如果写了set方法 并且val]给了别人 那么当前的a就不会被赋予结果了

4.需要配合v-model进行数据监听

5.computed 默认调用get方法 必须要有return computed不支持异步

6.根据一个值变化后算出一个新的值 使用任何复杂的计算逻辑 都该使用computed

7.data和其他地方写了computed就不能再写了

8.computed监听的数据中的 一旦内部有任何变化 也会触发监听方法 比如get中的方法使用的数据某一项改变 就会导致自己的重新计算

9.计算属性是根据依赖进行缓存 只有影响该数据的数据的变化 才会导致监听属性的变化

computed:{	msg(){}			//默认调用get方法}---------------------//用对象的写法  可以自定义set getcomputed:{	msg:{		get(){},set(){}	}			}//实际用法  通过监听任一数据 返回一个新的数据  一旦监听的数据改变  computed对象也会进行更新computed:{	msg(){							return this.name+this.age;	}			}

20.watch 观察属性

1.观察数据的变化 当数据变化后执行一件事情

2.只有值变化的时候才会触发 支持异步 其他情况我们更善于使用computed

3.watch的属性名字要和观察的人的名字一样

4.watch的缺点在于要一个个去监听某个属性

watch:{	a(newVal,oldVal){		setTimeout(()=>{      console.log(newVal)    },200)	}}

深度监控:

watch 只能监控一层的变化 所以需要开启深度监控

默认写成函数 就相当于默认写了个handler

deep:true 表示开始深度监控

watch:{	todos:{    handler(){			//监控的对象里面的数据发生变化也会被监听到    },deep:true	}}

21.template标签

是vue提供给我们的 没有任何的实际意义 用来包裹元素用的 v-show 不支持template 只有v-if能够使用

<template v-if='true'></template>

可以通过id与组件绑定

<template id='name'></template>-----------------let home = { template:'#name' }

22.路由 vue-router

路由:访问不同的路径 就返回不同的结果

spa单页应用 single page application

实现单页开发的方式

  1. 通过哈希值(hash)记录跳转的路径 (可以产生历史管理) 不会导致404 如果使用hash的方式 不支持seo

  2. 浏览器自带的历史管理的方法 **history ** (history.pushState()) 可能会导致404错误,vue-router的原理

  3. 开发时使用hash的方式 上线的话我们会使用history的方式

安装vue-router

npm i vue-router --save

1.引入vue-router 自带VueRouter类

 const router = new VueRouter({  })

2.配置路由映射表 配置路径和组件的关系

let routes = [  { path:'/a',component:home},  ->配置的关系就是页面级组件  { path:'/a',component:home}		] 

3.将配置信息放入vue-router中 在这里使用一个属性 可以开启history方式进行跳转,就不使用hash模式了

	 const router = new VueRouter({ routes,mode:'history'  })

4.然后将vue-router放入实例中

let vm  = new Vue({ el:'#app' , router })

5.最后在视图中使用router-view组件 (这是vue-router 定义的全局组件)

router-view 此标签用来显示路由跳转后的结果

 <router-view></router-view>

使用router-link进行手动路径跳转 -> 按钮 声明式路由跳转

<router-link  to="/home" tag="button">首页</router-link>  tag ->指定路由链接样式  默认是a标签样式

给router-link改样式**

  1. 可以在style中设置class .router-link-active
  2. 在vue-router构造函数中配置参数 更改默认样式类名
const router = new VueRouter({ routes,linkActiveClass:'active'  })

使用js方式进行路由跳转

再讲vue-router实例挂入根组件之后,每个组件都会拥有一个名字叫**router(r的放的都是方法)的属性还有一个名字叫router**(有r的放的都是方法)的属性 还有一个名字叫**route**(没有r放得都是属性)

this.$router.push('/list')  //强制跳转路径this.$router.go(-1)  //返回某一级this.$router.replace('/list')  路由替换 讲当前的历史替换掉

routes配置

{path:'',component:home},   //默认展示的路由{path:'*',component:home},  //这个地方路径不会变 只是切换了组件而已{path:'*',redirect:'/home'},  //路径变 组件也要切换

路径参数

routes: {path:'/article/:c/:a',component:article}  ->/:a 路径参数,表示值必须要有 但是值是随机的

route.params:此时路径输入/article/2/d>实际vue会将主目录下的参数转为一个对象c:2,a:d这个对象会放在实例上的route.params**:此时路径输入 /article/2/d -> 实际vue会将主目录下的参数转为一个对象 {c:2,a:'d'} 这个对象会放在 实例上的 route.params

template:`<div>第 {{$route.params.c}} {{$route.params.d}}篇文章</div>`, -> $route.params.c|d 就可以取到路由中的参数

可以通过watch来今天**$route**属性变化 也就是路由参数变化来发送ajax

 watch :{ //路径参数发生变化  监控参数的变化来发送ajax 
 $route(){}}

router-link动态绑定路由参数

{path:'/detail/:bid',component:Detail,name:"detail"},
给路由指定名字  然后绑定动态参数
----------------------------
:to="{name:'detail',params:{bid:book.bookId}}" 
通过name指定路由 , 然后给params绑定路由参数

动态路由配置

会根据路由的跳转拉取组件 ,会自动引入 不需要在开头先引入

{  path:'/detail/:bid',  component:()=>import('../components/Detail.vue'),  name:"detail"}

在进入路由之前,每一次都会执行此方法 ,全局钩子 ,具有拦截功能

router.beforeEach(function(to,from,next){})   ->执行next() 才往下走

子路由(二级路由)

{	path:'/detail',  component:detail,  children:[      // children 中的路径永远不带/ 如果带/表示是1级路由      {path:'profile',component:profile},      {path:'about',component:about}  ]},

此时就有路由为 : /detail/profile

// children 中的路径永远不带/ 如果带/表示是1级路由

配置总结:**

  1. 创建组件
  2. 配置路由
  3. 实例化VueRouter
  4. 挂载路由
  5. 放置组件

23.自定义指令

directives: vue实例中写自定以指令的地方

<button v-color='flag'>变色</button>Vue({	directives:{	color(el,bandings):{	//el指代的是这个元素的   bandings接受的一系列关于该元素的参数		el.style.background = bingdings.value			}	},	data:{		flag:'red'	}})

24.生命周期钩子函数

生命周期

beforeCreate 创建之前 加载内部方法之后,data等方法还没有 用不到

created 创建后 获取ajax 初始化操作

beforeMount 挂载数据之前 //么有实际意义

mounted 挂载数据之后 操作dom,真实dom渲染完

beforeUpdate 数据更新之前 数据变化就会触发这个方法

Update 数据更新之后 数据更新完成就会触发这个方法

处理虚拟dom ->这两个方法一般使用watch替换掉,这两个方法是所有数据一旦有变动就会触发

beforeDestroy 实例销毁之前 可以清除定时器, 或者清除事件绑定

destroyed 销毁后

销毁后会移出监听器

25.实例上的方法

  • this.$data vm上的数据
  • this.$watch 监控
  • this.$el 当前控制的元素
  • this.$set 后加的属性 实现响应式的变化
  • this.$options vm上的所有属性
  • this.$nextTick() -> 异步方法 ,等待dom完成后获取dom 压栈
  • this.$refs 所有ref的集合,如果dom元素不是通过v-for循环出来的 只能获取到一个,通过v-for循环出来的 可以获取多个

ref属性如果放在组件上 获取的是组件的实例 并不是组件的dom元素 可以实现父组件使用子组件的方法

hide(){this.flag = false; }
<son red='load'></son>
-------------------
this.$refs.load.hide();  -> 通过获取实例的ref方法来调用子组件的方法

vue中DOM渲染是异步的,如果数据变化后想要获取真实dom中的内容,需要等待页面渲染完毕后获取,所有的dom操作,最好写在nextTick中

26.组件

  1. 组件替代传统的页面开发 提高开发效率 方便重复使用 便于协同开发 更容易被管理和维护
  2. vue中的组件是一个自定义标签, vue就会把他看成一个组件, 只要不是w3c规范之内的标签,vue都会把它当做组件
  3. 组件是相互独立的 不能跨组件 实例vm也是一个组件 组件中拥有生命周期函数
  4. 如果组件公用了数据 会导致同时更新 组件的特点是独立
  5. 子组件不能直接使用父组件的数据(组件之间的数据交互)
  6. 组件理论上可以无限嵌套

组件分类

功能划分

  1. 页面级组件 一个页面是一个组件
  2. 基础组件 将可复用的部分抽离出来

组件命名规范

  1. 组件名不要带有大写 多个单词用 -
  2. 只要组件名和定义名字相同是可以的(首字母可以大写)
  3. html采用短横线隔开命名法,js中驼峰也是可以的

组件分类

  1. 全局组件: 可以声明一次在任何地方使用 局部组件: 必须告诉这个组件属于谁 -> 一般写插件的时候 用全局组件多些
    • 组件中的数据必须是函数类型,返回一个实例作为组件的数据
<my-handsome></my-handsome>----------------------------------------Vue.component('my-handsome',{   //一个对象可以看成一个组件	template:'<div>我很英俊</div>'})

2.局部组件 使用的三部曲 :

  1. 创建这个组件
  2. 注册这个组件
  3. 引用这个组件
 <my-handsome></my-handsome>		-><my-handsome>  一样---------------------------------let handsome = {        template:'<div>我很英俊</div>',     	data(){            return obj        },     	methods: {            fn(){                this.school = 'hello'            }        },    } let handsome1 = {      template:'<div>我很英俊</div>'  }      ----------------------------------    components:{          'my-handsome':handsome,     			handsome1  } 

父子直接数据传递:

props属性 此属性是一个数组 里面的写的属性用于接收父组件传递的数据

可以通过在使用子组件的时候 进行绑定传递 子组件通过props数组中写对应的数据进行接受 然后就能在template中使用了

<my-handsom  :name='{{xxx}}'><my-handsome>
 ---------------
let handsom = { props:['name'],template:`<div>{{name}}</div>` }

但是 子组件改变数据只是自己接受的数据改了 并不会影响父级

多个组件使用一个数据 那么数据改变多个组件的中视图也会改变

父组件需要等待子组件挂载完成后再出发父组件的挂载

父组件给子组件传值

1.父组件调用子组件的时候 绑定动态属性 可以传递方法 数据 以及父组件这个对象

<v-son :title='xxx'></v-son>

2.在子组件里面通过props 接受父组件传过来的数据

​ props:[]

  • 父组件传过去的属性如果子组件以及定义 那么会报错 但是使用父组件的属性

ref属性传值

父组件主动获取子组件的数据和方法:

1.调用子组件的时候 定义一个ref

 <v-son ref='xxx'></v-son>

2.在父组件里面通过

 this.$refs.xxx.属性/方法

子组件主动获取父组件的数据和方法

 this.$parent.属性/方法

27.发布订阅

一种一对多的设计模式 -> 子组件想父组件传值

  • 发布 emit
  • 订阅 on

父亲绑定一些事件 儿子触发这个事件 将参数传递过去 单向数据流 父亲数据刷新 儿子就刷新

子组件绑定一个事件 当事件触发时 调用自己的方法 发布事件 this.$emit('child-msg',800)

参数一是需要监听人 参数二是我需要改变的数据

同时需要父组件在使用字组件的时候添加自定义事件 xxx=' xx ' -> 属性名是监听需要触发的事件人 属性值就是事件人需要干的事件 子组件的参数会被事件接受 作为实参

son:{		template:`<div>儿子:{{title}}      <button @click='getMoney()'>        多要钱    </button>  </div>`,   methods: {    getMoney(){      this.$emit('child-msg',800)     }	}}//触发自己的自定义事件  让父亲的方法执行}},}-----------<son :title='money' @child-msg='things'></son>----------------------------vue->methods: {things(val){ this.money = 800 } },

28.插槽

正常一个组件在父组件中使用 闭合标签里面是不是写内容的 就算写了也不会显示 插槽是能够将闭合标签里面写内容 然后在视图中能够显示

  • 插槽的作用 是定制模板
  • 模板中只能有一个根元素 可以通过元素属性定制模板
  • slot中可以放置一些默认的内容 如果传递了内容则替换掉
  • 如果没有名字的标签默认放置到default中

父组件在闭合标签中写内容 子组件在模板中使用插槽

<son>123</son>----------------------son:{ template:`<div><slot></slot></div>`}----------这样就能把123传入到div中

通过给插槽命名来指定插槽 ->slot = ' xxx '

<modal>
  <p slot='a'>123132</p><p slot='b'>6666</p>
</modal>
------------------------
<div>dialog <slot name='a'>
  </slot><slot name='b'></slot>
</div>

通过插槽将父组件方法传递给子元素

<modal>
  	<p slot='a' @click='fn'>123132</p>
</modal>
------------------------
这个fn是父组件的
methods:{alert(1)}
-------------------------
<div><slot name='a'> </slot></div>

29.vue自带的标签

template 标签 component标签 transition标签 slot标签

使用component标签动态绑定组件,通过绑定is属性来动态控制

   <input type="radio" v-model="radio" value="home">home            <input type="radio" v-model="radio" value="list">list<component :is="radio"></component>  ->is属性可以绑定组件  -=-------------------------  components:{home,list }  -------------------------------   data() {return  {modal:'modal',radio:'home' }}

这个实例可以做到两个按钮的选中来切换组件 ,但是这两个组件的切换会发生重复销毁和创建,比较耗性能,

所以要在component外面加上 keep-alive标签 这样就不会杀死组件 而是后台缓存 一般作用缓存,为的是后面的路由做准备, 如果缓存了就不会再走created mounted钩子函数

<keep-alive>      <component :is="radio"></component></keep-alive>

30.EventBus

正常情况下只有父子直接 祖先直接传递, 这样虽然能够进行传值等操作, 但是需要一层一层的往上传, 那还是相当的麻烦 所以提供了一种叫EventBus的操作, 虽然我们以后都用Vuex

正常情况下子组件发出事件 兄弟一监听事件 兄弟二发出事件 但是 这样没办法进行监听订阅 兄弟元素没办法监听到 所以需要一个叫EventBus的对象实现中间转折 也有缺陷哈

let EventBus = new Vue({})-------------------------------bor1created() {    // 给兄弟一 加监听事件    EventBus.$on('changedRed',(val)=>{        this.color = val;    })},-----------------------bor2change(){EventBus.$emit('changedRed',this.old);}

非父子组件传递数据(通信) -> EventBus

  1. 新建一个js文件 引入vue 实例化vue 然后暴露这个实例
  2. 在要广播的地方引入刚才定义的实例
  3. 通过VueEmit.$emit('名称','数据')
  4. 在接受数据的地方通过 VueEmit.$on('名称',function(){}) 接收

31.安装vue-cli

npm install vue-cli -g	全局安装vue-cli

然后就可以在任何文件夹初始化项目

vue init webpack <项目名称>

cd 项目名称

npm install 初始化安装 项目不能直接运行 就可以使用这个命令

npm run dev

32.模块

node模块的规范 commonjs 如果引用 导入 导出 针对js文件

cmd规范 seajs amd规范 require 需要引入 umd 就是为了做兼容处理的

esmodule ->如何定义模块 (一个js就是一个模块) 如果导出模块 (export) 如何使用模块 (import)

// 如果是第三方模块 必须要加 ./
// 如果是文件模块需要加./
// 有点像结构赋值了
// import 有声明的功能,还有预解释的效果也就是变量提升
// import {str,str2,a} from'./a.js'

// *表示接受所有参数  并把这些参数放入b对象中
// import * as b from './a.js'

// xxx表示default后的结果
import xx from './b.js'

console.log(xx);

33.vue-cli中main.js 讲解

import  Vue from 'vue'    
//这样直接引入vue  引用的并不是vue.js  引用的是vue的runtime 
//runtime 不支持template  只支持render
// vue = compiler + runtime (compiler可以编译模板 )
// compiler 有6k 

然后就直接 new Vue({]})

其中render函数的作用是讲虚拟dom渲染成真实的dom,

createElement返回的是虚拟dom

new Vue({    render:function(createElement){        console.log( createElement('h1','hello'));        return createElement('h1','hello');    }}).$mount('#app')------------------------------简写new Vue({    render:(h)=>h('h1',['hello',h('span','一则头条')])}).$mount('#app')

在vue-cli中一个.vue文件就是一个组件

而组建的结构就包括 template script style

<template></template><script>    ->规定必须是导出写法export default {		    data(){			->组件中的data都是方法 需要return数据        return {}    },methods:{},computed:{}.components:{}}</script><style scoped=''>   ->scoped 属性 让这个样式只能当前文件使用</style>

安装vue-loader 以及依赖 vue-template-compiler

vue-loader 解析.vue文件的 vue会自动的调用的下面的这个插件

vue-template-compiler 用来解析vue模板的

npm i  vue-loader vue-template-compiler --save-dev

然后在webpack.config.js配置

{test:/\.vue$/,use:'vue-loader'}

如果npm run dev 打包失败 那么需要在config.js配置

const VueLoaderPlugin = require('vue-loader/lib/plugin')--------------------------plugins:[    new VueLoaderPlugin()]

在main.js引入的vue文件,打印App出来是一个对象,

我们可以用这个对象来替换render函数中的createElement对象,来简单实现节点渲染,

所以才有vue-cli模板中的的结构

import App from './App.vue'
render:(h) => h(App)  

34.vue-cli项目结构

根组件会放在src目录 src里面一般放App mian.js index.html

页面级组件会新建一个文件夹 名字叫page或者components

至于基础组件会放在一个文件夹 叫base

路由也会抽离出来 放在一个文件夹

我们在main.js(根实例)中只引入了一个组件(App.vue),他会把这个组件渲染到#app里面,其他的组件都是在这个实例中进行引入的

如果在main.js引入很多组件来实现路径,相对来说很麻烦,所以我们要把router抽离出来

import Vue from 'vue';
// 这里也需要引入vue  因为模块化会形成闭包
import VueRouter from 'vue-router'
import Home from '../components/Home.vue'
import List from '../components/List.vue'

Vue.use(VueRouter) 

export default new VueRouter({
    routes:[
        {path:'/home',component:Home},
        {path:'/list',component:List},
    ]
})
-----------------------------
    import router from './router' 

在使用Vue-router的时候,和以前用引入js文件不一样的一点是,需要先使用Vue.use

Vue.use(VueRouter) 
//和以前不一样的地方 引入vue-router必须使用use  然后Vue注册两个全局组件  
//use  就是在vue中使用插件

35.写vue插件

import modal from './notify.vue'  //引入这个.vue返回的是一个对象

let notify = {      //需要在此对象拥有一个install方法

};
// this.$notify('吃饭了吗',{delay:1000});
notify.install = function(Vue,options={delay:3000}){
    Vue.prototype.$notify = function(message,opt={}){
        if(notify.el) return;
        if(document.body)
        options = {...options,...opt} //用自己调用插件时传递过来的属性,覆盖掉默认设置好的
        let V = Vue.extend(modal)   //返回的是一个构造函数的子类   参数是包含组件选的对象
        let vm = new V;

        let oDiv = document.createElement('div');  //创建一个div  将实例挂载到元素上
        vm.$mount(oDiv);
        vm.msg = message;
        document.body.appendChild(vm.$el); // 把当前实例这个真实对象扔到页面上
        notify.el = vm.$el;

        setTimeout(()=>{ //延迟多少秒 将dom元素移除掉
            document.body.removeChild(vm.$el);  //将实例上的元素删除掉
            notify.el = null;
        },options.delay);
    }   
}
//导出这个包含install的对象,如果使用Vue.use就会调用这个install  方法
export default notify;

- ---------------------------
import notify from './plugin/notify.js'

Vue.use(notify,{
    delay:2000
});  //使用带有install的对象