Vue笔记
1.mvvm(双向数据绑定)
- model 数据模型(js对象)
- viewModel 视图模型(vue实例)
- view视图(html+css)
vue实现的是 数据映射到视图 视图事件绑定数据 vue实例实现中间桥梁 render(data) => view
开发者只需要关心数据的变更,视图的更新交给vue
2.渐进式理解
- 声明式渲染(无需关心如何实现)
- 组件系统
- 客户端路由(vue-router)
- 大规模状态管理(vuex)
- 构建工具(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
-
resolve 代表的是转向成功态
-
reject 代表的是转向失败态
-
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;}
可以给每个transition加name属性 进行单独控制
<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.两部分组成由get 和 set(不能只写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
实现单页开发的方式
-
通过哈希值(hash)记录跳转的路径 (可以产生历史管理) 不会导致404 如果使用hash的方式 不支持seo
-
浏览器自带的历史管理的方法 **history ** (history.pushState()) 可能会导致404错误,vue-router的原理
-
开发时使用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改样式**
- 可以在style中设置class .router-link-active
- 在vue-router构造函数中配置参数 更改默认样式类名
const router = new VueRouter({ routes,linkActiveClass:'active' })
使用js方式进行路由跳转
再讲vue-router实例挂入根组件之后,每个组件都会拥有一个名字叫**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上
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级路由
配置总结:**
- 创建组件
- 配置路由
- 实例化VueRouter
- 挂载路由
- 放置组件
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.组件
- 组件替代传统的页面开发 提高开发效率 方便重复使用 便于协同开发 更容易被管理和维护
- vue中的组件是一个自定义标签, vue就会把他看成一个组件, 只要不是w3c规范之内的标签,vue都会把它当做组件
- 组件是相互独立的 不能跨组件 实例vm也是一个组件 组件中拥有生命周期函数
- 如果组件公用了数据 会导致同时更新 组件的特点是独立
- 子组件不能直接使用父组件的数据(组件之间的数据交互)
- 组件理论上可以无限嵌套
组件分类
功能划分
- 页面级组件 一个页面是一个组件
- 基础组件 将可复用的部分抽离出来
组件命名规范
- 组件名不要带有大写 多个单词用 -
- 只要组件名和定义名字相同是可以的(首字母可以大写)
- html采用短横线隔开命名法,js中驼峰也是可以的
组件分类
- 全局组件: 可以声明一次在任何地方使用 局部组件: 必须告诉这个组件属于谁 -> 一般写插件的时候 用全局组件多些
- 组件中的数据必须是函数类型,返回一个实例作为组件的数据
<my-handsome></my-handsome>----------------------------------------Vue.component('my-handsome',{ //一个对象可以看成一个组件 template:'<div>我很英俊</div>'})
2.局部组件 使用的三部曲 :
- 创建这个组件
- 注册这个组件
- 引用这个组件
<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
- 新建一个js文件 引入vue 实例化vue 然后暴露这个实例
- 在要广播的地方引入刚才定义的实例
- 通过VueEmit.$emit('名称','数据')
- 在接受数据的地方通过 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的对象