vue2.0学习笔记
Vue
特点
- 易用(html,es5,css)
- 灵活(核心库很小,压缩只有20k左右,渐进式技术栈[从易到难])
- 性能(虚拟dom)
注意:vue不支持ie8以及以下的版本
对比
1 react和vue
- 相似:只关注视图层,只帮助我们渲染(数据变化,重新渲染dom),使用 Virtual DOM,组件化,
- vue的不同:不用像react把所有的虚拟dom都写在render函数里,它采用传统的dom模板,所以比react多一个指令
- vue的优势:
1.在 React 应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树。在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,所以系统能精确知晓哪个组件确实需要被重渲染。你可以理解为每一个组件都已经自动获得了 shouldComponentUpdate,并且没有上述的子树问题限制。
2.在react中所有的都是js。Vue 的整体思想是拥抱经典的 Web 技术,并在其上进行扩展。在 React 中,所有的组件的渲染功能都依靠 JSX。
- vue的劣势:react拥有更丰富的生态圈
2 vue和angular
基础
1
- new Vue({})里面传一个配置对象,再是一个data属性,data里面是数据。
2
- el:挂载点,告诉当前应用的模板的位置(当前应用这个实例的模板的位置,让dom模板和实例相关联),将这个根实例挂载到app这个dom节点上,将dom当做根实例模板。(我们在new一个vue实例的时候,会去读这个el里面的所有的dom节点,把这些dom节点都当成模板)。
3 指令:当数据发生变化的时候,操作dom
- 指令的作用:(数据的变化映射到dom的行为,就是做dom操作的地方,凡是带V-的是vue提供的特殊属性)
- v-bind: 如果属性值是一个变量,在属性名前面加上v-bind
- 条件: v-if:是否显示当前的dom节点(0,false不显示,其他的显示)
- 遍历: v-for='t in todos' t遍历的每一个对象,in关键字,todos遍历的数组
- 处理用户操作: v-on:绑定事件 v-on:click='字符串' 字符串是一个函数的引用,在一个methods配置项中进行配置,methods是用来配置模板中处理函数的地方
- 双向绑定: v-model='value'
- 定义组件: 定义:Vue.component('todo-item', {
template: '<li>这是个待办项</li>'
})
使用:<todo-item></todo-item>
4 生命周期
初始化之前
- beforeCreate: vue实例化之前
- created: vue实例化之后
- beforeMount:插入真实的dom之前
- mounted: 渲染之后
初始化之后
- beforeUpdate:当数据发生改变之前,虚拟dom重新渲染之前
- updated:当数据发生改变之后
- beforeDestroy:销毁实例之前
- destroyed:销毁实例之后
5 语法
- v-html:输出真正的 HTML。站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容插值。
- v-once:通过使用 v-once 指令,能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上所有的数据绑定
- 双花括号中仅仅用来显示数据,加减乘除,三目运算符
- 过滤器:当我们想要格式化显示文本的时候,比如后台返回来的数据是0和1,我们需要将他转成男和女。
6 class style
class:
- 第一种,class后直接跟一个变量,这个变量必须为一个对象
<div :class='hot'>
hot:{
red:ture
}
- 对象语法 <div :class="{active:bool}"> active是class名,bool为变量值bool意思是如果bool值为true的话,就把key当做类名作用到当前的节点上,可以接受多个
- 数组语法:把类放到数组中,数组中存在的就把类作用到当前的dom上,可以使用三目
style:
<div v-bind:style="{ color: 'red', fontSize: 10+'px' }"></div>
<div :style="[red,fs]">好困好困好困,我想睡觉睡觉</div>
7 条件渲染
- v-if和v-else 中间不能有第三者。
- template:当我们想要显示和隐藏多个dom节点的时候使用,把一个 <template> 元素当做包装元素,并在上面使用 v-if。最终的渲染结果不会包含 <template> 元素
- v-else-if 可以支持多选一
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div >
- key:
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。
如果在两个template里面,v-if,v-else之间里面的dom节点相同的话,vue.js只会渲染一次第一个template里面的dom节点,复用,切换的时候也只会改变里面的值,上一次输入的数据会污染下一次的输入。当然不一定是template里面。
<template v-if="loginType">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
<button v-on:click='change'>点击</button>
只需添加一个具有唯一值的 key 属性即可
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
注意, <label> 元素仍然会被高效地复用,因为它们没有添加 key 属性。
- v-show
v-show改变的只是dom节点的display而已,那个元素始终被渲染并保存在dom中,不支持template和v-else。而v-if会在切换的过程中重建和销毁dom节点。
v-if是惰性的,如果在初始化这个dom节点之后,如果渲染的条件为假,就什么也不做,直到条件变为真的时候,才开始渲染。而v-show得话,不管初始的条件是什么,元素总是会被渲染。
因此,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销,因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件不太可能改变,则使用 v-if 较好。
8 列表渲染
- 根据一组数组的选项列表进行渲染,items是源数据数组,item是数组中的每个对象他的别名。index是索引,从0开始。
v-for="(item , index) in items" ,可以与tamplate一起使用。
- 可以遍历对象,value是每个对象的属性值,key为每个对象的属性名也就是key值。index为每个对象的索引。
<template v-for='(value,key,index) of oo'>
- 整数迭代
<p v-for='n in 10'>{{n}}</p>
- v-for 和 v-if
v-for的优先级比v-if高,也就是说先把所有数据先遍历出来,遍历完了之后,再调用v-if,判断它是否被显示。
- key
<div v-for="item in items" :key="item.id"> key不能重复,这个key的作用就是当你改变数据的时候,vue能够快速的定位到你操作的哪位元素。
- 数组更新检测的变化
变异方法:push() pop() shift() unshift() splice() sort() reverse()
所有的push,pop等方法都被vue进行重写了,这是因为vue无法检测到数组里面某一个对象的值发生了变化,目前js只能检测到对象里面的属性变化,没有办法检测这个对象发生了变化。当用vue重写后,调用push方法,会多做一些操作,触发视图的更新。那么vue是如何来进行数组方法的重写,Array.prototype.push=function(){},在这个函数里面来重写数据,触发视图的更新。
重塑数组:filter(), concat(), slice()
这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组。
- 显示过滤和排序
如果你想要进行数据筛选之后再进行显示的话,使用计算属性。
computed:{
AAA(){
return this.items.filter(function(item,index){
console.log(index);
return item.age>=18
})
}
}
9 事件处理器
- 监听事件:
可以用 v-on 指令监听 DOM 事件来触发一些 JavaScript 代码。
<button v-on:click="counter += 1">增加 1</button>
- 方法事件处理器
event对象:默认放在回调函数中的第一个参数
1:当v-on跟的函数表达式没有参数的时候,就把event对象放入到回调函数的第一参数
2:当回调函数跟了参数的时候,就要手动的传$event,<button v-on:click="al(2,$event)">注册</button>
在react中是不能在函数表达式中传递任何的参数,除非是箭头函数。
v-on:click="al"如果al函数没有参数,不需要写括号,如果al函数有参数,需要写括号。
- 事件修饰符
stop
prevent
capture:把事件执行从冒泡阶段切换到捕获阶段
self:当current.targrt===target,就是你点击的元素就是绑定的那个事件的元素。触发事件的那个dom节点就是你绑定事件的dom节点。只当事件在该元素本身(比如不是子元素)触发时触发回调。
once:只执行一次,当执行下一次的时候,就remove掉。
注意:使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 @click.prevent.self 会阻止所有的点击,而 @click.self.prevent 只会阻止元素上的点击。
- 键值修饰符
.tab .enter .delete .esc .space .up .down .left .right
@keyup 原生的事件名
<input type="text" @keyup.enter='show'>
哪一个键按下的时候,才执行对应的函数呢。
e.keyCode按键值
- 修饰键
.ctrl .alt .shift .meta
- 滑鼠按键修饰符
.left .right .middle
- 为什么要在html中监听事件
扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
因为你无须在 JavaScript 里手动绑定事件,仅仅只需要在你的ViewModel里面写函数,不需要调用绑定事件这些方法,让你的ViewModel显得很纯粹。
当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何自己清理它们。
10 表单控件绑定
v-model
- 文本
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
当input的value发生变化的时候,v-model指令就会把当前input的value,通过v-model后面的变量把他重新赋值给data。
- 多行文本
- 复选框
当单个复选框的时候,用v-model绑定一个变量的时候,返回的是这个checked的属性值,只有true或者false。<input type="checkbox" v-model="checked" checked/>
多个复选框的时候,v-model必须等于同一个值,表示他们是一起的多选,这个值必须为一个数组,如果勾选上某一个checkbox,就会将这个checkbox的value放到数组里去。
数据的(回显??):让复选框默认被勾上,直接在数组里面加上对应的value。
- 单选框
v-model等于一个变量,这个变量的值非数组
- 单选列表
<select v-model="selected">
<option value="">请选择</option>
<option value="CD">成都</option>
<option value="LS">乐山</option>
<option value="YA">雅安</option>
</select>
selected是绑定在select上的,如果想让下面的option选中谁,就让selected等于option里面的innerHtml,但是一般不用innerhtml,所以就添加value。
<select v-model="selected">
<option value="">请选择</option>
<option value="CD">成都</option>
<option value="LS">乐山</option>
<option value="YA">雅安</option>
</select>
<span>Selected: {{ selected }}</span>
注意:如果option下面已经有value的话,就不会匹配innerhtml了。
select 的 v-model要绑定 select这个dom上,当option有value的时候,这个变量就匹配的是value,否者就是option的innerHTML
- 修饰符
.lazy <input v-model.lazy="msg" >
在默认情况下,v-model 在 input 事件中同步输入框的值与数据 (除了 上述IME 部分),但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步,比如在做表单验证的时候,当这个表单失去焦点的时候,才提示。
.number
如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给 v-model 来处理输入值:
.trim
如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入
11 组件
- 什么是组件
自定义的html元素,扩展html(因为对于前端来说,一切都是呈现)。“封装”了可重用的代码 。
- 全局注册
Vue.component('my',{
template:`<div>今天天气很美</div>`
})
my:为组件名,组件是特殊的vue构造函数,在根实例配置对象中绝大部分配置项都可以在组件中一样使用,例如计算属性,data等,仅仅只是有一些配置项需要做特殊处理。
template:模板
- 局部注册
var myCom={
template:`<div>热热热</div>`
}
components:{
'my-com':myCom
}
什么时候使用局部组件,什么时候使用全局组件:在你这个组件要在多个页面引入的时候,就是用全局组件,否则就是子组件。实际工作中一般使用局部组件,然后在实例或者组件中通过components来进行引用。
- dom模板问题
table里面会将组件踢出去,它只认得tr,td,thead这些标签
浏览器在加载的时候,会先解析你的dom节点,然后就把你的组件踢出去了,这时候你的vue.js还没有执行。
<tr is="my-cn"></tr>
弄个假的tr,通过is这个属性告诉table这个tr是my-cn组件,浏览器解析这个dom节点的时候就不会把组件踢出去,当vue进行解析的时候,再将tr替换成vue组件
- data 必须为函数
如果data不是个函数,就会报错,因为组件在dom节点中是会被复用的,如果data为一个对象的话,多个组件引用的就是同一个对象里面的数据,同一个地址,点击其中一个组件的时候,会影响到其他对象。所以写一个data函数,为每个组件返回全新的 data 对象,vue会帮我们进行对象的拷贝,而不是复用地址。
- 组件传递数据
react中传递数据方式有两种,第一种是props,第二种是children,就是将组件里的innerhtml传递过去,接收的是所有的innerhtml,不太智能。
在 Vue 中,父子组件的关系可以总结为 props down, events up。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息
1 使用props传递数据
在子组件中props配置项中对传递的这个属性进行声明,
var myCom={
template:`<div>热热热{{count}}</div>`,
props:['count'] //在子组件中我期望以count这个属性名来获取一些数据
}
注意:如果你的属性是两个单词进行拼接的,那么在你进行props声明的时候,驼峰,但是在使用的时候,是小写加-。
Vue.component('child', {
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
<child my-message="hello!"></child>
- 单向数据流
为什么:如果修改了子组件里面的数据,进而修改了父组件的数据,这个数据又被这个父组件下的很多子组件使用,其他子组件的数据也会被修改,这时候就让这个数据流显得很混乱。
但是为什么我们想要修改prop中的数据呢,因为我们想要把这个数据当做是自己的来使用。
- prop验证
保证组件的健壮性。
props:{
countApp:Number
}
var myCom1 = {
template:`<div>勇敢一些!让你走的更远!{{myCount}}</div>`,
/*props:['myCount']*/
props:{ //验证属性的基本类型
/*myCount:[Number,String]*/
myCount:{
type:Number,
validator(value){
if(value>10){
return true
}
}
//default:2
//required:true //这个属性必传
}
}
};
validator:对传进来的数据进行具体的验证
- 非props属性(有问题)
可以将数据直接传入子组件,不需要在子组件的props中声明
- 自定义事件
在父组件中绑定一个自定义的事件,自定义事件的值就是父组件中的一个函数,传递这个自定义事件到子组件中,然后这个自定义事件就作为一个桥梁把父组件和子组件中的函数联系起来,在子组件中通过emit来触发在父组件中绑定的这个事件,也就是触发这个函数。
- sync修饰符
在子组件中修改父组件传递过来的一个数据,同时同步到父组件。
- 使用自定义事件的表单输入组件
自定义事件可以用来创建自定义的表单输入组件,使用 v-model 来进行数据双向绑定。
<my-com color='pink' v-model='msg'></my-com> 这是下面示例的语法糖
<my-com color='pink' v-bind:value='msg' @input='change'></my-com>
所以说要让父组件中的v-model生效的花,在子组件中需要接受一个value属性,在输入的时候触发input事件
var myCom={
template:`<div>
<input type='text' :class='[color]' :value='value' @input='change'/>
</div>`,
props:{
color:{
type:String,
default:'red'
},
value:{
type:String
}
},
methods:{
change(event){
this.$emit('input',event.target.value)
}
}
}
- slot:分发
在父组件中有多个innerHTML,通过<slot>在子组件里面得到它,如果想要区分每个slot的话,就在父组件中定义每个innerhtml的slot的值,然后在子组件中通过name属性,得到有与这个name属性相同的innerhtml。
父:
<span slot='2'>哈哈哈</span>
<span slot='1'>呵呵呵</span>
子:
<slot name='2'></slot>
<input type='text' :class='[color]' :value='val' @input='change'/>
<slot name='1'></slot>
- 动态组件
如果你这个项目页面没有太多,不需要引入路由,就使用动态组件
<div id="app">
<div>
<component :is="curPage"></component>
</div>
</div>
定义一个保留的component元素在根实例模板app里面,通过is这个特性,跟着一个变量curPage,让这个变量不停的切换组件,让组件加载到component这里来。就是说让多个组件挂载到一个挂载点(一个根实例模板下面),进行动态的切换。
- keep-alive
在vue中,当组件被切换出去的时候,默认会将他des消除,切换回来的时候,再new。不能让组价进行复用。如果想要切换出去的组件仍然保留在内存中,就加一个keep-alive指令参数。
<keep-alive>
<component :is="curPage"></component>
</keep-alive>
- 子组件索引
ref:在子组件中通过ref为子组件指定一个索引,在父组件中通过parent.$refs.profile得到这个子组件中相应的dom节点??
- 异步组件
当没有使用这个组件的时候,不会将这个组件下载下来,只有切换到这个组件之后,才将这个组件下载下来
- 组件的关系:props down,events up
props down:数据一般是由父组件通过属性向子组件传递,子组件在props中声明或者验证传过来的属性。
events up:父组件通过传递一个自定义的事件,这个自定义事件的值就是对应的函数,它作为桥梁将子父组件联系起来,然后在子组件中通过$emit触发这个事件,也就是这父组件中的那个函数。
12 过度效果
- 概念:元素从无到有,从有到无得一个过渡效果,所谓的过渡效果无非就是添加和删除类
- 触发的条件:条件渲染(v-if),条件展示(v-show),动态组件,根渲染, Vue 提供了 transition 的封装组件,给条件变化组件添加enter, leave过渡,分为enter,enter-active,enter-to
- 如何做动画效果
用transition组件将p节点包裹起来,定义一个name值,这个name值就是vue来动态添加删除类的前缀。
<transition name="fade">
<p v-if="show">hello</p>
</transition>
从无到有:
. fade-enter:定义进入过渡的开始状态,. fade-enter { opacity: 0 },下一步将要开始做动画的时候,干掉fade-enter。
. fade-enter-active : 定义过渡的状态,. fade-enter-active { transition: opacity .5s }, 在元素整个过渡过程中作用。在元素被插入的时候生效。在 transition/animation 完成之后移除。 这个类可以被用来定义过渡的过程时间,延迟和曲线函数。
. fade-enter-to :定义进入过渡的结束状态,不需要定义,因为元素默认的状态就是opacity : 1。
从有到无:
. fade-leave:定义离开过渡的开始状态,opacity : 1,不需要定义,因为元素默认的状态就是opacity : 1。
. fade-leave-active :定义过渡的状态,. fade-enter-active { transition: opacity .5s }, 在元素整个过渡过程中作用,在离开过渡被触发后立即生效,在 transition/animation 完成之后移除。 这个类可以被用来定义过渡的过程时间,延迟和曲线函数
. fade-leave-to:定义离开过渡的结束状态,在离开过渡被触发一帧后生效(于此同时fade-leave 被删除),就是fade-leave被干掉之后马上触发,在 transition/animation 完成之后移除。
- 什么时候使用css过渡(transition),什么时候使用css动画(animation)
只有两帧的情况下使用过渡,当有多帧并且想要设置中间状态的时候设置中间状态使用动画。
- css动画
- 自定义过渡类名
- 自定义钩子
在做动画的时候干的一些事情
- 初始化渲染
可以通过 appear 特性设置节点的在初始渲染的过渡
isux.tencent.com/css3/ 动画手册
13 自定义指令
想做dom操作的时候,就封装指令。目前而言,基本用不到。
- 钩子函数
<input type="text" v-focus />
Vue.directive('focus',{
inserted(el){ //当第一次绑定的时候,还不是真实的dom节点
el.focus()
}
})
bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。这个时候这个dom还是虚拟dom,还不是真正的dom节点。
inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。
componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
unbind: 只调用一次, 指令与元素解绑时调用。
14 路由
干嘛的:切换组件
用的版本:vue2的路由
代码:
<script src="vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 切换组件 -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
<router-link to="/user/wt">Go to User</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<!--当路由匹配到某个组件,加载到这里来。-->
<router-view></router-view>
</div>
</body>
<script>
// 如果使用模块化机制编程,導入Vue和VueRouter,要调用 Vue.use(VueRouter)
// 定义(路由)组件。
// 可以从其他文件 import 进来
const Foo = { template: `<div>foo
<router-view></router-view>
<router-link to="/foo/foo1">Go to foo1</router-link>
<router-link to="/foo/foo2">Go to foo2</router-link>
</div>`
}
const Foo1 = { template: '<div>foo1</div>' }
const Foo2 = { template: '<div>foo2</div>' }
//除了使用 <router-link> 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
//通过js来进行组件的切换,称为编程式导航
//router:路由实例,下面创建的,通过this.$router拿到路由实例
//push会生成历史记录,replace不会生成历史记录,
//go
const Bar = { template: `<div>bar
<button @click="goUser">Gouser</button>
</div>`,
data(){
return {
username:'haha'
}
},
methods:{
goUser(){
//js跳转
// this.$router.push('/user/13') //路由实例
// this.$router.replace({path:"user/yangj2"})
this.$router.push( {name:"user", params: { username:this.username},query: { plan: 'private' } })
}
}
}
//响应路由参数的变化:
//提醒一下,当使用路由参数时,例如从 /user/foo 导航到 user/bar,原来的组件实例会被复用。
//因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。
//不过,这也意味着组件的生命周期钩子不会再被调用。
//怎么办呢,使用$watch,来监测$route对象
//$route为路由对象,当路由匹配到谁的时候,就会把当前路由匹配的所有的信息注入到这个路由对象中,并把这个对象赋到当前这个组件当中
//to:切换过去新的路由对象 from:切换之前的路由对象
//beforeRouteEnter,组件内部的钩子,比create这些钩子都要先调用,是路由钩子
//在beforeRouteEnter之前,是拿不到组件的实例对象的,不能再这个钩子里面去调用this,因为这个组件都还没有被实例化
//不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
//beforeRouteUpdate;在当前路由改变,但是组件被复用的时候调用
const User = { template: '<div>user---{{$route.params.username }}---{{msg}}</div>',
data(){
return {
$route:'$route',
msg:'我的爱在等待'
}
},
// created(){
// console.log('呵呵');
// },
mounted(){
console.log(this.$route);
},
beforeRouteEnter(to, from, next){
// console.log(22);
// next();
setTimeout(function(){
next((vm)=>{
vm.msg="我的已回来!"
})
console.log(this.msg);
},2000)
},
beforeRouteUpdate(to, from, next){//当组件被复用的时候
console.log("fuyong");
next();
},
watch:{
$route (to,from){
// console.log(from,to);
}
}
}
// 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 命名路由
//重定向:如果没有任何匹配的路由,重定向到某一个组件,跟在最后面
const routes = [ //路由匹配规则
{ path: '/foo', component: Foo ,children:[
{
path:'foo1',
component:Foo1
},
{
path:'foo2',
component:Foo2
}
]},
{ path: '/bar', component: Bar },
{ path: '/user/:username',component:User,name: 'user'},
{ path:'/', redirect:'/foo'}
]
// 创建 router 实例,然后传 routes 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
//告诉路由器实例我们的路由匹配规则是什么
//history:路由匹配模式 ,路径切换
const router = new VueRouter({
routes // (缩写)相当于 routes: routes
})
//因为vue没有类似于react的should的钩子,它并不能对接收的数据进行限制,
//所以就增加了导航钩子,vue-router 提供的导航钩子主要用来拦截导航,让它完成跳转或取消。
//router.beforeEach,每一次路由切换的时候,都会执行的全局钩子
//next,一定要调用他,1)如果全部钩子都执行完了,则导航的状态就是确认的。next(false),当前切换的url会被重置到from路由对应的地址,next('/')跳转到对应的地址上去
//afterEach:一般不用,用户都切换过来了,还弄啥呢
router.beforeEach((to, from, next) => {
// console.log(to);
// if (true) { //登陆失效
// next();
// };
next();
})
// 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
//将路由实例传给vue这个实例,告诉当前app你使用了路由
const app = new Vue({
el:'#app',
router
})
// 现在,应用已经启动了!
</script>
</html>
15 安装vue-cli
1)npm i -g vue-cli
2)vue init webpack test
3)npm i
4)npm run dev
16 vue-cli项目
bulid:不用管,是用来帮我们启服务地方,唯一要操作的地方是dev-server,因为要在这里面进行数据的模拟。
config:一些配置文件
static:不能够通过npm安装的包,像zepto,swiper这些库,静态资源文件,想通过标签引入
src:所有项目存在的地方
assets:静态资源存放的地方,但是可以通过import导入。
main.js :项目的启动项,webpack的入口文件,el和template共存的话,就会把id为app的组件全部替换成template包含的组件。
App.vue :整个项目最外层的那个组件
stylus:css预编译语言,scoped:当前的css只作用到当前的模板上面
router-link-active:通过router-link切换的切换连接,切换到哪一个组件,会加上这个类
懒加载:创建异步组件,Vue.component,第二个参数为函数。当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。结合 Vue 的 异步组件 和 Webpack 的 code splitting feature, 轻松实现路由组件的懒加载。
我们要做的就是把路由对应的组件定义成异步组件:
const User = r => require.ensure([], () => r(require('@/pages/User.vue')), 'User')
不让组件同时加载进来,只有当用户点击切换的时候,才到服务器里面去读,将这个组件下载下来。才用require.ensure分开打包。
enusre:代码的分割,把组件放到了require.ensure里面的时候,webpack就知道要分开打包,不会放到主bundl里面,当路由匹配到这个组件的时候,再来下载这个异步组件。
第一个参数[ ] ,当去加载后面的User.vue组件的时候,这个参数是前置依赖的意思,就是你这个组件依赖于哪些组价。
第二个参数r是resolve的意思,当我们加载require后面的组件的时候去调用resolve函数
第三个参数是分组的意思,取成一样的,告诉webpack将这两个组件打包在一起
静态资源文件,例如static文件里面的reset文件,在index.html文件中用link标签进行引入
asset里面通过相对路径来进行访问,static通过绝对路径进行访问,静态资源目录在根目录,因为能够直接访问index.html页面
当我们使用模块化导入vue-router或者其他插件的时候,必须调用Vue.use(Router),把这个导入的路由放在Vue.use里面去,script标签就不需要放到Vue.use里面去,因为script标签将这个router挂载到window对象上去,全局就可以访问。但是组件化这块,它是一个独立的作用域,在他的内部是不会把他的变量暴露到全局上去,所以动态调用Vue.use(Router)
npm run build 打包
vue.js的插件 很多
vuex
仓库:用来存储数据,改变数据的地方,在所有的页面中,都导入这个仓库,如果想要修改仓库的数据的话,就执行特定的函数,让仓库执行修改。
vuex:状态管理,就是一个仓库
状态管理:
state:数据
view:视图,从状态中拿数据
action:在视图中触发一个函数,函数中修改状态
安装vuex,cnpm i --save vuex
有1,2的版本,安装的是2版本
state:在仓库里面具体存储数据的地方,谷堆,state,一个对象包含了所有的数据,一个仓库就只有一个state,一个谷堆
通过在实例中传递store 选项,提供了一种机制将状态从根组件『注入』到每一个子组件中。如果想要在组价中获取state之中的状态的话,通过this.$store.state.count获取
mapState:当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键,如果计算属性与state属性一样的时候可以使用这个参数,可以在数组里传入字符串,表示把this.$store.state.count映射到this.count这个计算属性
数组语法:这个语法不好的是万一有这个组件自身的计算属性的话,就不好操作了
computed:mapState([
'count',
'count2'
])
对象展开语法:对象扩展运算符的,把对象的 key value 展开成用,隔开的一个一个的键值对,为了与局部就是组件内部的计算属性混合使用,需要使用一个工具将多个对象合并在一起,采用对象的展开运算符
...mapState([
'count',
'count2'
])
mapState函数返回的是一个对象
getters:是state的扩展,有时候我们需要从store的state中派生一些状态,例如对列表进行过滤,Vuex 允许我们在store中定义 getters (可以认为是store的计算属性),getter接受state作为第一个参数。
getters:{
old(state){
return state.users && state.users.filter(function(item){
return item.age>=20;
})
}
}
filter函数:filter()方法中行参是一个回调函数.这个回调函数就是一个规则,返回一个布尔值.filter()方法会对数组中每一个元素使用这个回调函数.注意,这里说的是每一个元素.并且将返回值为true的元素装入一个新数组返回
mapGetters:mapGetters 辅助函数仅仅是将 store 中的 getters 映射到局部计算属性中。
Mutations: 改变state的地方,更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutations 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。不能直接调用hander, 这个选项就像注册事件,触发一个 increment的mutation,你需要以相应的type调用 store.commit(‘[type]’)。必须为同步函数,没有异步操作,因为vue.js写了一个工具,来一步一步监听我们的数据
mutations:{
increment(state,num){
state.count+=num;
}
}
methods:{
add(){
this.$store.commit('increment',2);
}
}
mapMutations:语法糖,这种方法无法传参数
mutations:{
increment(state){
state.count++;
}
}
methods:{
...mapMutations({
add:'increment'
})
}
如果mutation为一个变量的话,那样如果mutation中的key,也就是自定义的type类型发生改变,那么很多地方都需要改。所以推荐使用常量代替mutation的type(类型)用不用常量取决于你 —— 在需要多人协作的大型项目中,这会很有帮助。但如果你不喜欢,你完全可以不这样做。
es6是允许对象的key是一个变量的,但是要用方括号把他给括起来
Action:专门用来做异步操作,当异步操作结束后,再提交mutation,类似于mutation,action 提交 mutation,不是直接修改state,action可以包含任意异步操作。
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
数据放在dev.server.js里面,并且要放在app实例之后之前,因为webpack-dev-middleware这样的中间件,帮我们自动配置了history api cback,前段发过来的任何请求,都返回一个index.html。
increment({commit,state,getters}){
$.get('/api/list', function(data) {
console.log(data);
commit('MOREUSERS',data.list)
});
}
Action 通过 store.dispatch 方法触发:
getuser(){
this.$store.dispatch('increment')
}
mapActions:
...mapActions({
getuser:'increment'
})
注意:如果组件名为驼峰命名的话,比如myCom,在html里面引入的话,要是用my-com。对于自定义标签名,Vue.js 不强制要求遵循 W3C 规则 (小写,并且包含一个短杠),尽管遵循这个规则比较好。局部注册的对象名不能加-。以后局部注册的时候就使用驼峰myCom,在components里面定义组件名的时候就使用my-com,在html中引入的时候就使用my-com。
注意:
* {{}}里面只能用来显示数据的
* vue.js将当前data里面的所有属性都挂载到了vue实例上去了
* 组件是特殊的vue实例,只有组件才可以被销毁
* 带$的符号一般是vue.js内部的方法,一般不使用
* h5的新的api classList
vue最强大的功能是计算属性和组件
es6遍历器 fa? keys?
新姿势:
1 语法糖:它意指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法。语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读。不过其并没有给语言添加什么新东西。
重点
什么时候用到计算属性:模板中出现太多的逻辑,使用了过多的表达式,这样会让代码变得难以维护的时候使用。同时想要监听某些数据,当这些数据发生变化的时候会影响到其他的数据的时候使用。
计算属性:
1.
- 在配置对象中定义computed:{计算属性名:function(){ return 计算好的数据}}
2.特点:
- 1.会监听在这个计算属性中所依赖的任何数据,
- 2.计算属性会被缓存(当依赖的数据没有变化,多次使用的时候不会执行计算属性函数),
- 3.当依赖的数据发生变化的时候,计算属性的值会被重新计算并赋值。
- 4.get和set还可以监听计算属性自身的变化
4.getter和setter
- getter一般是获取计算属性的值
- setter当计算属性发生变化的时候,同时也会执行set,来修改原本依赖的数据
计算属性 VS 方法调用:计算属性会被缓存(当依赖的数据没有变化,多次使用的时候不会执行计算属性函数),函数的调用会在使用的地方多次执行函数,造成资源的浪费。
计算属性 VS Watch: Watch:只能一次监听一个数据变化(代码的冗余)。当你想在数据变化做异步操作时,使用它。watch的优点是可以设置中间状态。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
{{message}}
<span v-bind:title="message">指令是vue中有的而react没有</span>
<p v-if="bool">这里是vue的条件判断,与react不同的是react是在render的return之前使用if else进行判断或者直接在return里面使用三目运算符进行判断</p>
<ul>
<li v-for="t in tobos">{{t.text}}</li>
<todo-item></todo-item>
</ul>
<button v-on:click="change">这里演示vue的事件绑定</button>
<input type="text" v-model="val" />
<div v-html="span"></div>
</div>
</body>
<script>
//v-html能够将html字符串转化为html,但是对于这条指令要谨慎使用,我们一般使用{{}}引入变量,在{{}}中只能使用加减乘除已经三目运算符等简单的JavaScript语句与react类似,使用v-bind来使属性值改变
//指令的参数在指令后以冒号指明,比如v-bind:title="message"的参数是title,v-on:click="change"的产生是click
//指令的修饰符是以半角句号 . 指明的特殊后缀,比如v-on:click.prevent="change"的.prevent就是修饰符,表示触发本事件的时候会调用event.preventDefault()
Vue.component("todo-item",{
template:"<li>组件的使用就是像使用dom节点标签一样</li>"
})
var app=new Vue({
el:"#app",
data:{
message:"今天开始学vue",
bool:false,
span:"<span style='color:red'>双花括号只能将数据转化为纯文本而不是html,因此我们一般使用v-html:'变量'来转化html字符串</span>",
tobos:[{
text:"这是为了试验vue中的遍历"
},{
text:"vue中的遍历与react中的遍历不同,react一般使用map()方法返回一个数组,而vue直接使用v-for指令进行遍历"
},{
text:"v-for='遍历到的每一项 in 数组名'"
}],
val:"使用v-model实现的input中数据的双向绑定"
},
methods:{
change(){
alert("绑定的函数配置在methods对象下面");
this.bool=true
}
},
beforeCreate(){
//在将data挂载到实例以及初始化事件之前调用
console.log("在将data挂载到实例以及初始化事件之前调用");
},
created(){
//在实例创建好之后调用
console.log("在实例创建好之后调用")
},
beforeMount(){
//判断实例中是否配置el和template后调用
console.log("判断实例中是否配置el和template后调用")
},
mounted(){
//使用vue.js编译代码,成功插入dom后调用
console.log("使用vue.js编译代码,成功插入dom后调用")
},
beforeUpdate(){
//数据发生改变,虚拟dom还没有重新渲染之前调用
console.log("数据发生改变,但是虚拟Dom还没重新之前调用")
},
updated(){
//数据发生改变,虚拟dom重新渲染之后调用
console.log("数据发生改变,虚拟dom重新渲染之后调用")
console.log(this.message)
},
//在生命周期钩子函数中我们是能够拿到当前data中的数据的
beforeDestroy(){
//在调用$destory()后调用
console.log("在调用$destory()后调用")
},
destroyed(){
console.log("从真实dom中移除")
},
//一般不销毁实例,组件是特殊的实例,被销毁的一般是组件
})
</script>
</html>

浙公网安备 33010602011771号