1 MongoDB在NodeJS中操作
- 驱动:
mongodb
mongoose
1.1 document的操作
1.1.1 增
-
insertOne(Object)
-
insertMany(Array)
1.1.2 删
-
deleteOne(query)
-
deleteMany(query)
1.1.3 改
-
updateOne(query,{$set:data})
-
updateMany(query,{$set:data})
-
save(document)
1.1.4 查
-
find(query)
-
findOne(query)
1.1.5 条件与筛选
1.2 封装(重点)
async & await
2 了解VUE
- Vue.js 是一个基于
MVVM
模式的一套渐进式框架。它是以数据驱动和组件化的思想构建的,采用自底向上增量开发的设计。
2.1 前端框架发展史
-
Jquery(2006)
:节点操作简单易用,浏览器兼容 -
Angular(2009)
:MVC模式,双向数据绑定,依赖注入 -
React(2013)
:高性能(虚拟DOM) -
Vue(2014)
:综合angular与react的优点,MVVM模式,是一款高性能高效率的框架
2.2 架构模式
复杂的软件必须有清晰合理的架构,更容易开发、维护和测试
2.2.1 MVC
MVC
模式的意思是,软件可以分成三个部分。
-
模型
Model
:数据处理 -
视图
View
:数据展示 -
控制器
Controller
:业务逻辑处理(M和V之间的连接器)
-
View 传送指令到 Controller(用户发送指令)
-
Controller 完成业务逻辑后,要求 Model 改变状态
-
Model 将新的数据发送到 View,用户得到反馈
- 缺点:依赖复杂
- View 依赖 Controller 和 Model
- Controller 依赖 View 和 Model
2.2.2 MVP
MVP
架构模式是MVC
的改良模式(改进Controller, 把Model和View完全隔离开)
-
Model
-
View
-
Presenter
可以理解为松散的控制器,其中包含了视图的 UI 业务逻辑,所有从视图发出的事件,都会通过代理给Presenter
进行处理;同时,Presenter
也通过视图暴露的接口与其进行通信。
2.2.3 MVVM
由
MVP
模式演变而来
-
Model
-
View
-
ViewModel
类似与MVP中的Presenter
,唯一的区别是,它采用__双向绑定__:View的变动,自动反映在 ViewModel,反之亦然
- 核心思想:关注Model的变化,让MVVM框架利用自己的机制去自动更新DOM,从而把开发者从操作DOM的繁琐中解脱出来!
2.3 学习 Vue 需要改变关注点
-
jquery和原生js的关注点:节点
-
Vue中的关注点:数据
3 使用VUE
3.1 实例化new Vue()
var data = { name: 'zhoutest' }
var vm = new Vue({
el: '#app',
data: data
});
3.2 常用配置选项
3.2.1 关于DOM节点
el
(类型:Selector|Element)
Vue实例的挂载目标(实例中所有的属性/方法可直接在el中直接使用),挂载元素会被 Vue 生成的 DOM 替换
template
(类型:String)
模板,如果不指定则以ele所在元素作为模板
Selector
:提取内容到template标签,并指定选择器
render
(类型:Function)
template
的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个createElement(tagName,props,children)
方法作为第一个参数用来创建 VNode
- 优先级:
render
>template
>el.outerHTML
new Vue({
//...
el:'#app',
template:`<div>{{username}}</div>`,
render:createElement=>{
return createElement('h1',{title:'标题',class:'title'},'文章标题')
}
})
3.2.2 关于数据
data
(类型:Object|Function)
Vue 实例化时,它将
data
中所有的属性添加到__响应式系统__中,当这些数据改变时,视图会进行重渲染
computed
(类型:Object)
对于需要复杂逻辑或运算才能得到的值,应当使用计算属性
methods
(类型:Object)
一般用于编写公共方法、事件处理函数等,方法中的this指向实例,所以不应该使用箭头函数来定义 method 函数
watch
(Object)
监听属性(Function),监听的值被修改时会自动调用函数,当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的
watch: {
username: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
}
}
3.3 实例属性&方法
Vue 实例化时,会遍历
data/computed/methods
中所有属性/方法,并写入Vue的实例
3.3.1 属性特性
1. 值属性(有自己的值的属性)
-
configurable
可配置性(属性特性总开关) -
enumerable
可枚举性(是否可遍历) -
writable
可写性 -
value
2. 存储器属性(本身没有值,一般用于代理其他数据)
-
configurable
可配置性(属性特性总开关) -
enumerable
可枚举性(是否可遍历) -
get
监听读取操作 -
set
监听写入操作
3. 设置属性特性
-
Object.defineProperty(obj,key,descriptor)
-
Object.defineProperties(obj,descriptors)
Object.defineProperties(user,{
age:{
configurable:true
value:18
},
password:{}
})
4. 获取属性特性
-
Object.getOwnPropertyDescriptor(obj,key)
-
Object.getOwnPropertyDescriptors()
3.3.2 响应式属性
-
Vue在实例化时,会自动遍历data下的所有属性,并通过
Object.defineProperty()
把他们变成存储器属性,并写入Vue的实例 -
特点:对属性的修改UI会自动更新
-
原理:
getter&setter
let data = {
username:'zhoutest',
age:18,
password:123456
}
let vm = new Vue({
el:'#app'
data
})
设置响应式属性
-
设置初始化数据 data
-
Vue.set(target,key,val)
向__响应式系统__中的对象添加属性并自动渲染视图注意:
target
对象不能是 Vue 实例,或者 Vue 实例的根数据对象 -
数组变异方法
3.3.3 内置属性
除了数据属性,Vue 实例还提供了一些有用的实例属性与方法。它们都有前缀
$
,以便与用户定义的属性区分开来
-
$data
: 同 data -
$el
: 同 el节点 -
$refs
-
$parent
-
$children
-
$root
3.3.4 内置方法
-
数据data
-
$watch()
:监听数据变化,同watch配置选项 -
$set()
:Vue.set()的别名
-
-
事件event
-
$on()
:监听当前实例上的自定义事件 -
$off()
:移除自定义事件监听器 -
$emit()
:触发当前实例上的事件
-
-
生命周期函数
3.4 指令 directive
- 指令是带有
v-*
前缀的特殊属性,格式:v-指令名:参数.修饰符="值"
3.4.1 内置指令
1. 数据绑定
单向数据绑定
-
{{}}
:插值表达式差值表达式中应当放置一些简单的运算(data中的数据、函数执行、三元运算等),对于任何复杂逻辑,你都应当使用计算属性操作完成后再写入插值表达式
-
v-text
:显示文本 -
v-html
:显示html内容 -
v-bind
:
-
可绑定任意属性
<img v-bind:src="imgurl"> <!-- 简写 --> <img :src="imgurl">
-
对style与class的绑定
在将
v-bind
用于 class 和 style 时,Vue做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }" v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"> </div> <script> new Vue({ data: { isActive: true, hasError: false, activeColor: 'red', fontSize: 30 } }) </script> <!-- 最终结果:<div class="static active" style="color:red;font-size:30px"></div> -->
-
v-bind
无参数绑定对象<div v-bind="{username:'laoxie',age:18,gender:'男'}"></div> <!-- 等效于 --> <div v-bind:username="laoxie" v-bind:age="18" v-bind:gender="男"></div>
v-model
双向数据绑定
v-model
一般用于表单元素,会忽略所有表单元素的 value、checked、selected 特性的初始值而总是将 Vue 实例的数据作为数据来源
-
v-model
值绑定到value属性-
单行文本框
text
-
多行文本框
textarea
-
单选框
radio
-
选择框
select
(无value属性则与内容绑定) -
复选框
checkbox
-
初始值为数组,与value属性绑定
-
初始值为其他,与checked属性绑定(true,false)
-
true-value:设置选中时的值
-
false-value:设置补选中时的值
-
-
-
修饰符
-
lazy
:input触发改成change触发 -
number
:输出值为number类型 -
trim
:自动清楚前后空格
-
-
双向数据绑定原理
-
Model -> View
:响应式属性 -
View -> Model
:事件
-
-
v-model
的原理(替代方案)-
v-bind:value="val"
-
v-on:input="val=$event.target.value"
组件中使用v-model等效于:
v-on:input="val=arguments[0]"
-
列表渲染
-
v-for
可遍历
Array
|Object
|number
|string
|Iterable
-
遍历数组
<li v-for="(value, index) in arr">{{value}}</li>
-
遍历对象
<tr v-for="(value, key, index) in obj"> <td>{{index+1}}</td> <td>{{key}}-{{value}}</td> </tr>
-
key
:Vue 识别DOM节点的一个通用机制(用于diff算法)-
Vue对相同的元素进行展示排序等操作时,遵循“就地复用”原则,因为这样更加高效,性能更好
-
但对于依赖子组件状态或临时 DOM 状态 (如:表单输入值、复选框选中等)的列表,会出现操作混乱的问题
-
指定key属性后,意为去掉“就地复用”特性(建议尽可能在使用 v-for 时提供 key)
-
-
2. 显示隐藏
-
v-show
(频繁显示隐藏)通过display属性控制元素的显示隐藏
-
v-if
|v-else
|v-else-if
(不频繁的显示隐藏)通过创建/移除的方式控制元素的显示隐藏
影响页面性能几大因素
-
节点的频繁操作
-
事件绑定数量
-
....
Virtual DOM
一个结构类似与真实DOM节点的js对象
-
优化方式
-
优化节点操作
-
优化事件处理
-
....
-
-
虚拟DOM是怎么优化性能的:背后有一套强大的算法:
diff算法
-
key:唯一且稳定
// 虚拟DOM大概样子
{
type:'div',
attrs:{},
children:[{
type:'h1',
children:'2021'
},{
type:'ul',
children:[{
type:'li',
children:'1111'
}.{
type:'li',
children:'2222'
},{
type:'li',
children:'3333'
}]
}]
}
3. 事件绑定
格式:
v-on
:事件类型.修饰符="事件处理函数"
事件修饰符
-
stop
-
prevent
-
capture
-
self
:只当在event.target
是当前元素自身时触发处理函数(e.target === e.currentTarget
) -
once
事件将只会触发一次 -
按键修饰符
-
直接使用键码来作为按键修饰符
<!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` --> <input v-on:keyup.13="submit">
-
使用别名作为按键修饰符
left
up
right
down
enter
tab
esc
space
-
3.4.2 自定义指令
1. 全局指令
-
格式:
Vue.directive(name, option)
-
参数
-
name
:指令名字,使用格式:v-name -
option
-
Object
:放钩子函数 -
Function
:默认为bind和update的钩子函数
-
-
2. 局部指令
- 格式:
directives: {}
// 使用指令:v-zhoutest
Vue.directive('zhoutest', {
bind: function (el, binding, vnode) {
//binding参数如下
el.innerHTML =
'name: ' + JSON.stringify(binding.name) + '<br>' + //指令名
'value: ' + JSON.stringify(binding.value) + '<br>' + //指令值
'expression: ' + JSON.stringify(binding.expression) + '<br>' + //字符串形式的指令表达式
'arg: ' + JSON.stringify(binding.arg) + '<br>' + //指令参数,
'modifiers: ' + JSON.stringify(binding.modifiers) + '<br>' //指令修饰符
}
});
3.5 生命周期函数
beforeCreate()
-
初始化完成,但为往实例添加属性
-
应用:可以在这加个loading事件
created()
- 应用:在这结束loading,还做一些初始化,实现函数自执行
beforeMount()
-
可以获取节点,但数据未渲染
-
应用:在这发起ajax请求,拿回数据,配合路由钩子做一些事情
mounted()
实例挂载到 DOM
- 应用:节点操作
beforeUpdate()
- 数据有更新但未更新节点
updated()
- 更新节点完毕
beforeDestroy()
destroyed()
执行destroy()后,不会改变已生成的DOM节点,但后续就不再受vue控制了
- 应用:清除定时器、延迟器、取消ajax请求等
3.6 过滤器
Vue允许你自定义过滤器,可被用于一些常见的文本格式化。
- 过滤器可以用在两个地方:
双花括号插值
和v-bind
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
全局过滤器
格式:
Vue.filter(name, definition)
局部过滤器
格式:
filters属性
// 首字母大写
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
3.7 mixin
混入
混入一般用于组件选项的复用,并以一定的合并规则混入到组件中
全局mixin:Vue.mixin(options)
全局注册一个混入,会影响后面所有创建的每个 Vue 实例/组件(影响较大,一般用于插件编写)
Vue.mixin({
created: function () {
// created生命周期函数会混入到下面的Vue实例中,且不会影响原来的选项
console.log('global mixin:', this.username)
}
});
new Vue({
data:{
username:'zhoutest'
},
created(){
console.log('app.username', this.username)
}
});
局部mixins:mixins:[mymixin]
一般用于提取多个组件的公有部分配置
var mixin = {
data: function () {
return {
message: 'hello',
foo: 'abc'
}
}
}
new Vue({
mixins: [mixin],
data: function () {
return {
message: 'goodbye',
bar: 'def'
}
},
created: function () {
console.log(this.$data);// => { message: "goodbye", foo: "abc", bar: "def" }
}
})
3.8 开发插件
插件可以是一个对象(必须提供
install
方法),也可以是一个函数,它会被作为install
方法,并把 Vue 作为参数传入
3.8.1 插件类型
-
添加全局方法或者属性,如:
vue-custom-element
-
添加全局资源:指令/过滤器/过渡等,如
vue-touch
-
通过全局 mixin 方法添加一些组件选项,如:
vue-router
-
添加 Vue 实例方法,通过把它们添加到
Vue.prototype
上实现。 -
一个库,提供自己的 API,同时提供上面提到的一个或多个功能,如
vue-router
MyPlugin.install = function(Vue, options) {
// 1. 添加全局方法或属性
Vue.myGlobalMethod = function() {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件(影响后面定义的所有组件)
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
Vue.component('mycomponent',{
// 继承mixin中的created等配置
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
3.8.2 使用
通过全局方法
Vue.use()
使用插件。它需要在你调用new Vue()
启动应用之前完成
Vue.use(MyPlugin);//会自动调用MyPlugin中的install方法
new Vue({
//... options
})
4 组件 Component
- 优点:代码复用 & 便于维护
4.1 组件定义和使用
组件是可复用的
Vue
实例,带有一个名字,所以它们与new Vue
接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等(el选项除外)
4.1.1 组件要求
-
data 必须为
Function
类型 -
每个组件必须只有一个根元素,否则报错
-
注册时组件名可以是
kebab-case
或PascalCase
,但在html页面上使用时,必须写成遵循W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符)
4.1.2 定义
1. 全局组件
-
Vue.component(name, options)
,所有的Vue实例都可以使用 -
类似于
new Vue(options)
Vue.component('my-component', {
// ... options ...
template:'<p>我是全局组件</p>'
})
2. 局部组件
- 在某个Vue实例中通过
components
属性注册的组件为局部组件,只有当前实例能使用
var Child = {
data() {
return {
name: '我是局部组件'
}
},
template: '<h1>hello, {{name}}</h1>'
}
// 创建根实例
new Vue({
el: '#app',
components: {
Child
}
});
4.1.3 使用
- 使用组件时,组件
template
中的内容会替换调组件所在位置
<div id="app">
<my-component></my-component>
<child></child>
</div>
- 注意:由于 Vue 只有在浏览器解析和标准化 HTML 后才能获取模板内容,所以把组件嵌套在某些特定的元素(如
table, ul, ol, select
等)上时,会导致解析错误
<!-- table为已经存在html页面上的元素 -->
<table>
<my-row></my-row>
</table>
Vue.component('my-row',{
template:'<tr><td>test</td></tr>'
});
- 以上解析的结果为,tr被解析到了table外面,解决方式也很简单,利用特殊的
is
属性实现
<table>
<tr is="my-row"></tr>
</table>
4.2 组件通讯
原则:谁的数据谁修改
4.2.1 父组件 -> 子组件:props
-
组件实例的作用域是孤立的。
-
要让子组件使用父组件的数据,需要通过子组件的
props
选项
1. 步骤
-
在子组件上定义属性,并传递数据
-
在子组件中通过
props
配置参数接收数据
接收到的数据会自动称为子组件的属性
2. props
声明属性
-
声明的属性会自动成为组件实例的属性(可通过
this.xx
访问) -
prop
传递是单向的,当父组件的属性变化时,将传导给子组件,但是不会反过来
<blog-post mytitle="静态数据"></blog-post>
Vue.component('blog-post', {
props: ['mytitle'],
template: '<h3>{{ mytitle }}</h3>'
})
<blog-post :msg="message"></blog-post>
<!-- 传入一个对象 -->
<blog-post v-bind:author="{ name: 'zhoutest', age:18 }"></blog-post>
Vue.component('blog-post', {
props: ['msg','author'],
template: '<h3>{{ msg }}</h3>'
});
let vm = new Vue({
data:{
message:'hello zhoutest'
}
})
3. 非props属性
- 此类属性会自动成为组件根节点的属性(可通过
{inheritAttrs: false}
关闭)
4. prop
数据验证
对传入的
prop
属性进行校验,如:数据类型、必填、默认值等
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 匹配任何类型)
propA: Number,
// 多个可能的类型
propB: [ String, Number ],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字,无prop属性传入时,默认得到100
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
myscore: {
validator: function (value) {
// 这个值必须大于等于60,否则报错
return val >= 60
}
}
}
})
4.2.2 子组件 -> 父组件:自定义事件 + $emit
- Vue 遵循__单向数据流__原则,不允许在子组件中直接修改
props
传入的父组件数据,可以通过自定义事件系统,利用$emit()
方法触发父组件函数来达到修改的效果
1. 方法①
-
在子组件上定义一个事件
v-on:additem
-
在子组件内部触发这个自定义事件:
$emit()
2. 方法②
-
可以利用
v-bind:xx.sync
修饰符(如下color属性) -
子组件调用
this.$emit('update:xx',val)
触发更新
<div id="app">
<p :style="{fontSize:fontSize+'px'}">字体大小:{{fontSize}}</p>
<btn-change :font-size="fontSize" @bigger="updateFontSize" :color.sync="color"></btn-change>
</div>
<template id="myButton">
<button @click="changeSize">改变字体大小</button>
<button @click="changeColor">改变字体颜色</button>
</template>
<script>
new Vue({
el:'#app',
data:{
fontSize:16,
color:'red'
},
components:{
btnChange:{
props:['fontSize'],
template:'#myButton',
methods:{
changeSize(){
this.initFontSize++;
// 手动触发自定义事件并传递修改后的值
this.$emit('bigger',this.fontSize+1);
},
changeColor(){
this.$emit('update:color','#58bc58');
}
}
}
},
methods:{
updateFontSize(val){
// 触发自定义事件的事件处理函数,并修改字体大小
this.fontSize = val;
}
}
})
</script>
4.2.3 兄弟组件通信
- 组件A -> 父组件 -> 组件B
4.2.4 多层级组件通讯
- 利用一个 Vue 实例作为中间桥梁实现传参
事件总线 Bus
-
自定义事件
接收方自定义事件
$on()
-
触发自定义事件
发送方触发事件
$emit()
// 定义中间桥梁bus
let bus = new Vue();
//组件A
let comA = {
data(){
return {
msg:'I am A'
}
},
template:`<div>
<p>{{msg}}</p>
<button @click="send">传数据到B组件</button>
</div>`,
methods:{
send(){
bus.$emit('data',this.msg);
}
}
}
// 组件B
let comB = {
data:()=>({
msg:'I am B'
}),
mounted(){
bus.$on('data',val=>this.msg = val)
},
template:`<div><p>{{this.msg}}</p></div>`
}
// 创建实例,并注册子组件
new Vue({
el:'#app',
components:{
comA,
comB
}
});
4.3 内置组件
<component>
动态组件
is
:指定渲染的组件
<component v-bind:is="currentTabComponent"></component>
<keep-alive>
缓存组件
把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染可以添加一个 keep-alive
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们,主要用于保留组件状态或避免重新渲染
-
include
(String/Regexp):指定缓存组件名 -
exclude
(String/Regexp):指定不缓存的组件名
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
<slot>
内容分发
4.4 插槽
- 内容通讯:插槽
slot
4.4.1 利用组件内容进行通讯(组件外 -> 组件内)
- 在组件模板中利用内置组件
<slot></slot>
来承载组件内容,否则它的内容都会被忽略
默认插槽:<slot>
<!-- 使用组件 -->
<nav-link url="/home">首页</nav-link>
<!-- 定义组件 -->
<script>
Vue.component('nav-link',{
props:['url']
template:`<a :href="url"><slot></slot><span>Home</span></a>`
});
</script>
具名插槽:<slot name="xx">
-
模板内容:给
<slot/>
组件命名(设置name属性) -
组件内容:设置 slot 属性
v-slot:name
,实现内容精准显示到模板具体位置
<!-- 组件模板内容 -->
<template id="myTest">
<div>
<slot name="header">这是拥有命名的slot的默认内容</slot>
<slot>这是拥有命名的slot的默认内容</slot>
<slot name="footer">这是拥有命名的slot的默认内容</slot>
</div>
</template>
<!-- 使用组件 -->
<my-component>
<template v-slot:header>这里的内容显示到name为header的插槽</template>
<span>这里的内容显示到默认插槽</span>
<template v-slot:footer>这里的内容显示到name为footer的插槽</template>
</my-component>
4.4.2 作用域插槽(组件内 -> 组件外)
-
把需要传递的参数写入 slot 属性
-
v-slot="scope"
(scope为写入solt的所有属性组成的对象)
<!-- mynav组件模板 -->
<div class="box">
<slot :msg="msg" :username="username">{{username}}, {{msg}}</slot>
<slot name="footer" title="播放器" :player="player">{{player}}</slot>
</div>
<!-- 组件内容 -->
<mynav>
<!-- props为传过来的数据组成的对象 -->
<div slot-scope="props">{{props.msg}}, {{props.username}}</div>
<!-- Vue2.6+用法 -->
<div v-slot:default="props">{{props.msg}}, {{props.username}}</div>
<div v-slot:footer="foot">{{foot.title}}, {{foot.player}}</div>
</mynav>
5 模块系统
5.1 前言
常规的定义组件的方法在复杂的项目中存在以下缺点
-
全局定义 强制要求每个
component
中的命名不得重复 -
字符串模板 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的
-
不支持 CSS 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
-
没有构建步骤 限制只能使用 HTML 和 ES5 JavaScript, 而不能使用预处理器,如 Pug (formerly Jade) 和 Babel
5.2 vue单文件组件
-
Vue__单文件组件__(扩展名为 .vue),由于浏览器不支持
.vue
文件, 和ES6的模块化(import
,export
)开发, 必须利用babel
和webpack
工具来辅助实现编译成浏览器支持的格式 -
vue单文件优点
-
完整语法高亮
-
CommonJS 模块
-
组件作用域的 CSS
-
5.3 vue单文件组件开发流程
webpack打包
5.3.1 安装必要模块
"devDependencies": {
"html-webpack-plugin": "^3.2.0",
"vue": "^2.5.17",
"vue-loader": "^15.4.2",
"vue-template-compiler": "^2.5.17",
"webpack": "^4.18.0",
"webpack-cli": "^3.2.3"
}
5.3.2 设置webpack配置文件(webpack.config.js)
5.3.3 应用入口文件(app.js)
//ES6 引入其他模块(可以是js,css,vue单文件等)
import Vue from 'vue';
import App from './app.vue';
new Vue({
el:'#app',
// render 函数若存在,则忽略 template 或 el 元素中的内容
render(create){
return create(App);
}
});
5.3.4 单文件组件(app.vue)
<template>
<div class="container">
<h1>Hello {{name}}</h1>
<button class="btn btn-success">点击进入</button>
</div>
</template>
<script>
// 导出当前组件配置选项
export default{
data(){
return{
name:'Vue单文件组件'
}
}
}
</script>
<!-- 设置具有组件作用域的样式 -->
<style scoped>
h1{color:#58bc58;}
</style>
5.4 ES Module
浏览器和服务器通用的模块解决方案,完全可以取代
CommonJS
和AMD
规范
5.4.1 基本特点
-
每一个模块只加载一次, 并执行一次,再次加载同一文件,直接从内存中读取
-
每一个模块内声明的变量都是局部变量, 不会污染全局作用域
-
通过
export
导出模块,通过import
导入模块 -
ES6模块只支持静态导入和导出,只可以在模块的最外层作用域使用
import
和export
5.4.2 export
export
命令用于规定模块的对外接口,只允许导出最外层函数、类以及var、let或const声明的变量,可多次export,export出去后自动成为 模块对象的属性
export
后只能跟function
、class
、var
、let
、const
、default
、{}
1. 基本用法
//base.js
var myName = 'laoxie';
var age = 1995;
// 多次export
export { myName };
export let gender = "男";
export function show() {
console.log(666);
}
2. as
- 通常情况下,
export
输出的变量就是本来的名字,但是可以使用as
关键字重命名
function show() {
console.log('my name is show');
}
export { show as showName };
3. default
- 为模块指定默认输出,这样就可以在使用
import
指令的时候,不必知道所要加载的变量名或函数名
export default {
data:{
path:'/src/'
}
}
4. *
作为中转模块导出,把某个模块的所有相属性/方法导出
export * from './md.js';
5.4.3 import
-
import
命令用于导入其他模块提供的功能 -
格式:
import <module> from <url>
1. url 支持格式
// 支持
import base from 'http://laoxie.com/js/base.js';
import base from '/js/base.js';
import base from './base.js';
import base from '../base.js';
// 不支持
import base from 'base.js';
import base from 'js/base.js';
2. 基本用法
//从模块对象中导入属性为default的值,并赋值给变量res,无则得到undefined
import res from './base.js';
//导入模块对象中属性为myName的值并赋值给变量myName
import { myName } from './base.js';
3. as
修改变量名
//导入模块对象中属性为myName的值并赋值给变量username
import { myName as username } from './base.js';
4. *
导入整个模块对象
//导入整个模块对象,并赋值给myModule变量
import * as myModule from './base.js';
5.5 在 html 中使用 ES Module
浏览器支持 ES Module
在
<script>
标签中指定type="module"
<script type="module">
import res from './base.js';
console.log(res)
</script>
<script type="module" src="js/base.js"></script>
浏览器不支持ES Module
利用
webpack
等工具转换成ES5后引入(推荐)
6 过渡动画
<transition>
<transition-group>
<transition>
用于单个元素动画,<transition-group>
用于多个元素并解析为一个标签(默认:span)
6.1 属性
-
name
: 过渡类名前缀(默认:v)如设置name="fade",过渡类名变成:fade-enter / fade-enter-active /fade-leave / fade-leave-active
-
css
: boolean,是否使用 CSS 过渡类(默认:true)。设置为 false,将只通过组件事件触发注册的 JavaScript 钩子。
自定义过渡类名(可配合animate.css框架实现过渡效果)
-
enter-class
-
enter-active-class
-
enter-to-class
-
leave-class
-
leave-active-class
-
leave-to-class
<transition
enter-active-class="bounceIn"
leave-active-class="bounceOut"
>
</transition>
6.2 触发动画场景
Vue会自动检测是否设置
css动画
或JavaScript钩子
,并在下列情形中添加进入/离开过渡效果(css过渡或js过渡)
-
条件渲染 (使用 v-if)
-
条件展示 (使用 v-show)
-
动态组件
-
组件根节点
6.3 CSS过渡
通过CSS过渡类名
-
v-enter
:进入过渡的开始状态,元素被插入时生效,只应用一帧后立即删除 -
v-enter-active
:进入过渡的结束状态,元素被插入时就生效,在过渡过程完成之后移除 -
v-leave
:离开过渡的开始状态,元素被删除时触发,只应用一帧后立即删除 -
v-leave-active
:离开过渡的结束状态,元素被删除时生效,离开过渡完成之后被删除
6.4 JavaScript过渡
通过内置事件实现过渡动画效果,可以利用第三方动画库(如:velocity.js,jquery等)实现动画效果
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
</transition>
methods: {
// 过渡进入
// 设置过渡进入之前的组件状态
beforeEnter: function (el) {
// ...
},
// 设置过渡进入完成时的组件状态
enter: function (el, done) {
// ...
done()
},
// 设置过渡进入完成之后的组件状态
afterEnter: function (el) {
// ...
},
enterCancelled: function (el) {
// ...
},
// 过渡离开
// 设置过渡离开之前的组件状态
beforeLeave: function (el) {
// ...
},
// 设置过渡离开完成时地组件状态
leave: function (el, done) {
// ...
done()
},
// 设置过渡离开完成之后的组件状态
afterLeave: function (el) {
// ...
},
// leaveCancelled 只用于 v-show 中
leaveCancelled: function (el) {
// ...
}
}
7 面试题
-
响应式属性在哪个生命周阶段处理:创建阶段
-
在父子组件通讯过程中,在哪个生命周期函数最先获取到父组件传入的数据
-
在mounted生命周期函数中设置了定时器,组件销毁时定时器是否还在运行,如何清除
- ajax请求 -> 如何取消ajax请求(xhr.abort())