Vue 介绍
-
-
Vue.js (读音 /vju:/ view)
-
渐进式 JavaScript 框架3.1 渐进式 :
小型项目 就可以使用 vue 就高度了随着页面的复杂程序提高,就要学习 vue-rouer 来管理更多的页面再随着项目的数据越来越多,管理数据也变得麻烦起来了,就开始使用 vuex 来管理数据
框架和库的区别
1. 库(Library) , 代表 : jquery
-
库就是一系列函数的集合, 我们开发人员在使用库的时候,想要完成什么样的功能,就调用库中提供的某个方法
比如 : 想要添加样式, 就调用 jquery 中的 .css() / .addClass()
-
库起到了一个辅助的作用, 在使用库的是时候,是由开发人员说了算, 也是由开发人员起主导作用.
比如 : 想给 A:设置样式 A.css(), B:addClass() C:style.background='red'
2. 框架 (Framework), 代表:vue
-
在使用框架的时候,是由框架说了算,由框架起到了主导作用,
-
框架是一套完整的解决方案,框架中制定了一套规则,使用框架的时候,只需要按照规则,把代码放到合适的地方,然后框架会在合适的时机,主动调用开发人员的代码
比如 : 想用vue,组件里遍历就得使用 v-for, 下次不用 v-for 了,使用 for 不行 v-for='item in list'
3. 主要区别 : 控制反转
也就是 : 谁起到了主导作用
-
使用库的时候 : 开发人员起主导作用
-
使用框架的时候:框架起到了主导作用
-
从体量上看,框架一般比库大
-
会发现使用框架的时候,会受到很多限制
MVC + MVVM
MVC
-
MVC 是一种软件架构模式,也有人叫做设计模式
-
M : Model 数据模型 (专门用来操作数据,数据的 CRUD)
-
V : View 视图 (对于前端来说,就是页面)
-
C : Controller 控制器 (是视图和数据模型沟通的桥梁,用于处理业务逻辑)
-
看图
MVVM
Vue 使用的是 MVVM 模式为什么要学习 MVVM ?
-
MVVM ===> M / V / VM
-
M : model 数据层
-
V : view 视图层
-
VM : ViewModel 视图模型
-
核心 : M <===> VM <===> V
MVVM 优势
-
MVC 模式 将应用程序划为三个部分,实现职责分离
-
但是,在前端中,经常要通过 js 代码来进行一些逻辑操作,最终还要把这些逻辑操作展示页面中, 也需要
频繁的操作DOM
-
比如 : ajax 请求、添加、修改、设置样式、动画
-
-
MVVM 提出来的思想 通过
数据双向绑定
让数据自动的双向同步-
V (修改视图) --> M
-
M (修改数据) --> V
-
-
采用的是 : 数据驱动视图的思想, 数据是核心
-
以后如果想要操作 DOM, 立马想到的不是应该是拿到元素设置,而是数据
Vue 中的 MVVM
-
注意 : 不推荐直接手动操作 DOM
每个人操作 DOM 的方法不一样,会造成性能不一样官网 : 虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例。
学习 Vue 要转化思想
-
数据驱动视图 : 不要再想着怎么操作 DOM, 而是想着如何操作数据
起步 - Hello Vue
基本使用
-
安装 :
npm i vue
(小写) -
导入 :
<script src='./vue.js'></script>
-
实例 vue
const vm = new Vue({
// 指定 vue 管理的边界
el: '#app',
// 提供视图中 需要的数据
// 视图可以直接使用data中的数据
data: {
msg: 'xxx'
}
})
使用注意点
-
vm 官网建议
-
Vue 构造函数首字母大写
-
参数是一个对象
-
id='#app', 其他也可以
-
边界外的无法使用 msg
{{}} 插值表达式
-
{{}} Mustache 小胡子语法, 插值表达式
-
作用 : 使用
{{}}
从data
中获取数据,并展示在模板中 -
说明 :
{{}}
中只能出现 js 表达式
-
表达式 (有返回值的)
-
常见的数据类型
1 'abc' false [] {}
-
数据类型 和 运算符结合在一起
1+2 arr.join('-') true ? 123 : 321
-
-
语句
if语句 for语句
-
{{}} 语法 不能作用在 HTML 元素的属性上
数据双向绑定
一个 input + v-model
v-model 指令 : 数据双向绑定的指令
作用 : 把data中的msg值 和 input上的值 绑定到一起
注意 : v-model只能用在 表单控件上 (input checkbox 等)
> 可以在浏览器分别演示 V => M 和 M =>V
Object.defineProperty
let obj = {}
let temp
obj.name = 'zhanhgsan'
// 参数1 : 要给哪个对象设置属性
// 参数2 : 给对象设置什么属性
// 参数3 : 属性的修饰符
Object.defineProperty(obj, 'name', {
set: function(newVal) {
console.log('赋值了', newVal)
},
get: function() {
console.log('取值了')
return temp
}
})
数据双向绑定的原理
-
<input type="text" id="txt" />
-
演示 : V ==> M
//1. 拿到文本框
const txt = document.getElementById('txt')
//2. 时刻监听txt ,拿到最新的值
txt.oninput = function() {
console.log(this.value)
obj.name = this.value
}
//3. 数据模型
var obj = {}
let temp
Object.defineProperty(obj, 'name', {
// 给属性赋值的时候会掉
set: function(newVal) {
console.log('调用了set', newVal)
temp = newVal
txt.value = newVal
},
get: function() {
console.log('调用了get')
return temp
}
})
-
V => M
//1. 获取 input的值,最新值
//2. 通过监听oninput 拿到最新值
//3. 把最新值赋值给 obj.name
//4. 就会掉了set方法,就会修改了数据
-
M => V
//1. obj.name = 'xxx'
//2. 调用 set方法
//3. 把值赋值给input元素
指令学习
指令
-
指令 : 就是一个特殊的标记, 起一个辅助作用, 使 html 具备原来没有的功能
-
vue 中 所有的指令, 都是以 v-开头的
-
比如 : v-model v-bind v-if v-for 等等
v-model (常用)
说明 : 用在
表单
元素中, 用来实现数据双向绑定
(input checkbox 等等)作用 : 将数据txt
和文本框的值
绑定到一起, 任何一方发生改变,都会引起对方的改变注意 : v-model 在不同类型的表单元素中,该指令的作用不同
<!-- 文本输入框 绑定的是值 -->
<input type="text" v-model="txt" />
<!-- 多选框 绑定的选中状态 -->
<input type="checkbox" v-model="isChecked" />
v-text 和 v-html
说明 : 设置文本内容
-
v-text : 相当于之前的 innerText , 设置文本内容(不识别 html 标签) == 标签内部{{}}
-
v-html : 相当于之前的 innerHTML , 设置文本内容(是被 html 标签)
-
数据
msg1: '<a>这是一条信息</a>',
msg2: '<a href="#">我也是一条信息</a>'
v-bind (常用)
说明 : 动态绑定数据 (单向)出现原因 : 在 HTML 属性中, 无法使用插值表达式步骤:
// 加载静态数据
<a href="https://wbaidu.com">aaa</a>
// 想加载动态数据 {{ }}可以获取data中的数据
// 但是 {{}} 不能使用在属性中
<a href="{{ src }}">aaa</a>
// 所以使用v-bind
<a v-bind:href="{{ src }}">aaa</a> ok
<img v-bind:src="src"> ok
缩略 : v-bind 全部省略 只留下一个
:
改为 :
<a :href="src">aaa</a> ok
<img :src="src" /> ok
以后 使用静态加载数据 :
<a href="https://wbaidu.com">aaa</a>
动态加载数据 :<a :href="href">aaa</a>
v-bind 和 v-model 的区别
// v-model : 数据双向绑定 表单元素上
// : : 动态绑定数据(单向) 任意元素动态读取属性
容易出错点 :
<!-- v-model 数据双向绑定 -->
<!--场景 : 表单元素中 -->
<input type="checkbox" v-model="isChecked1" /> <br />
<!-- v-bind 数据动态绑定 (单向) -->
<!--场景 : 主要用在属性中 -->
<input type="checkbox" :checked="isChecked2" />*
操作样式
1.操作样式
<!-- 1. 静态类名 -->
<h1 class="red">哈哈</h1>
<!-- 2. 动态类名 -->
<h1 :class="cls">哈哈</h1>
<!-- 3. 最常用 -->
<!-- :class 里的值是一个对象
键 : 类名 (可能会要,也可以不要)
值 : 布尔值, true/false 确定类要不要
-->
<h1 :class="{ red:isRed , fz:isFZ}">哈哈</h1>
<!-- 4. style -->
<h1 :style="{ color : 'red', fontSize : fz + 'px' }">哈哈</h1>
2.其他操作
<!-- 1 -->
<!-- 重点 -->
<div :class="{ active: true }"></div>
===>
<div class="active"></div>
<!-- 2 -->
<div :class="['active', 'text-danger']"></div>
===>
<div class="active text-danger"></div>
<!-- 3 -->
<div :class="[{ active: true }, errorClass]"></div>
===>
<div class="active text-danger"></div>
--- style ---
<!-- 1 -->
<h1 :style="{ color : 'red', fontSize : fz + 'px' }">哈哈</h1>
<!-- fz : 80 -->
<!-- 2 将多个 样式对象 应用到一个元素上-->
<!-- baseStyles 和 overridingStyles 都是对象 -->
<!-- 如果有相同的样式,以后面的样式为准 -->
<div :style="[baseStyles, overridingStyles]"></div>
v-on 指令
注册事件/绑定事件
-
v-on:click 绑定了一个单击事件
: 后面是事件名称
<button v-on:click="fn">按钮</button>
-
缩写 : @click='fn'
<button @click='fn'>按钮</button>
-
函数写在
methods
里面
fn : function(){ ... }
fn() { ... }
-
函数里面的 this 指的就是 vm 实例
> 在函数里面操作数据
- 获取数据 this.msg
- 修改数据 this.msg = 'XXX'
-
传参5.1 正常传参
@click='fn(123)'
5.2 事件对象 $event
<!-- 4.1 绑定事件对象的时候, 没有添加小括号,此时,直接在方法中,通过参数 e 就可以获取到事件对象 -->
<!-- 4.2 如果添加小括号,就拿不到事件对象了,vue留了一个$event -->
<button @click="fn1($event,123)">我是按钮</button>
v-for
-
v-for 指令: 遍历数据,为数据中的每一项生成一个指令所在的标签
-
代码
<!-- 需求1 : 最常用 遍历数组 -->
<!-- 作用 : 遍历 list1 数据, 为数据中的每一项生成一个li标签 -->
<!-- item 数组里的每一项元素 -->
<ul>
<li v-for="(item,index) in list1">{{ item }} - {{ index }}</li>
</ul>
<!-- 需求2 : 遍历元素是对象的数组 -->
<ul>
<li v-for="item in list2">{{ item.name }} - id:{{ item.id }}</li>
</ul>
<!-- 需求3 : 遍历对象 -->
<ul>
<li v-for="(item,key) in obj">{{ item }}-{{key}}</li>
</ul>
<!-- 需求4 : 想要生成10个h1 -->
<h1 v-for="item in 10">我是h1 {{ item }}</h1>
: key
-
说明 :Vue 中推荐, 在使用 v-for 的时候,添加 key 属性
-
介绍 :
就地复用
<!-- 显示组件 -->
<p v-for="(item,index) in list" :key="index">
{{ item.name}} <input type="text" />
</p>
<!-- 数据 -->
data: { list : [ { id : 1, name : '老罗' }, { id : 2, name : '涛涛' }, { id : 3,
name : '聪聪' } ]
<!-- 演示 -->
vm.list.unshift({id:4,name:'马哥'})
-
怎么使用 key
3.1 如果数组里的元素不是对象,并且又不会改变数组的顺序的话 => :key='index' 3.2 如果数组里的元素是对象,,使用对象里的固定属性,并且是唯一, id 3.3 语法 : :key='item.id' 3.4 以后,写了v-for之后,立马写好 :key
事件修饰符
-
.prevent 阻止默认行为
-
一般用在 a标签阻止跳转默认行为 , 相当于 :
e.preventDefault()
.prevent 阻止默认行为,调用 event.preventDefault() (常用) @click.prevent = 'fn'
-
其他不常用事件修饰符 :
- .stop 阻止冒泡,调用 event.stopPropagation() - .capture 添加事件侦听器时使用事件捕获模式 - .self 只当事件在该元素本身触发时,才会触发事件 - .once 事件只触发一次
异步 DOM 更新
-
Vue 中采用了
异步DOM更新
的机制 -
什么是异步 DOM 更新
-
数据发生改变后, vue 没有立即将数据的改变更新到视图中,
-
而是等到数据不再变化的时候 一次性的 将 数据的改变更新到视图中
//1. 验证了 for (let i = 0; i < 1000; i++) { this.count++ }
-
为什么是异步 DOM 更新?
-
性能的考虑
-
因为对于前端来说, 修改数据进行 DOM 操作是常有的事情,如果频繁操作 DOM,会严重影响页面的加载性能
-
DOM 操作这是前端的性能的瓶颈
-
比如 : for (let i = 1; i < 10000; i++>) 如果同步 就要重新渲染 1000 次
-
验证 异步 DOM 更新 :
//2. 直接获取data 中的值 ,会立马获取成功
console.log(this.count)
this.count++
console.log(this.count)
// 但是 通过dom来获取count的值,因为DOM更新这个count值是异步的,是需要一点时间的
console.log(document.querySelector('h1').innerText);
this.count++;
console.log(document.querySelector('h1').innerText);
-
需求 : 在数据更新后,立即获取到更新后的内容???>
DOM 更新后,会执行 this.$nextTick() 的回调函数,所以能拿到值
// setTimeout(() => {
// console.log(this.$el.children[0].innerText)
// }, 1000)
this.$nextTick(() => {
console.log(this.$el.children[0].innerText) // 100
})
监听 watch
-
说明 : Vue 中可以通过 watch 配置项,来监听 vue 实例中数据的变化
-
基本使用
watch: { // 监听age属性的数据变化 // 作用 : 只要age的值发生变化,这个方法就会被调用 // 第一个参数 : 新值 // 第二个参数 : 旧值,之前的前 age(newVal,oldVal){ console.log('新 :',newVal); console.log('旧 :',oldVal); } }
-
基本使用案例 :需求 : 监听用户名文本框字符个数(3-6),并显示格式验证
<input type="text" v-model="name" />
<span v-show="isShow">用户名的字符 在 6-12之间</span> if
if (newVal.length >= 3 && newVal.length <= 6 ) {
-
监听对象 (数组也属于对象)
// data :
data: {
obj: {
name: 'zs'
}
},
// 组件
<input type="text" v-model="obj.name" />
// 监听
-
开始监听对象的属性
// 从对象的角度来监听的
因为对象和数组都是引用类型,引用类型变量存的是地址,地址没有变,所以不会触发watch
obj:{
// 深度监听 属性的变化
deep:true,
// 立即处理 进入页面就触发
immediate: true,
// 数据发生变化就会调用这个函数
handler( newVal ) {
console.log( newVal.name );
}
},
// 从属性的角度来监听
'obj.name' ( newVal ) {
console.log('监听对象的属性',newVal);
}
其他指令 v-else-if 和 v-else
-
v-else : 两种情况的
<h1 v-if="age >= 18">成年人</h1>
<h1 v-else>未成年</h1>
-
v-else-if : 三种以上情况
<h1 v-if="num >= 30">老年人</h1>
<h1 v-else-if="num >= 18 && num < 30">成年人</h1>
<h1 v-else>未成年</h1>
其他指令 v-once
-
v-once 作用 : 告诉 vue 这个标签中的内容,只需要解析一次即便是数据再发送改变, 那么,这个标签中的内容,也不会被更新
-
代码
比如说第一次登陆先显示登陆一欢迎信息
<p>{{ num }}</p>
<p v-once>带 onece的 {{ num }}</p>
其他指令 v-pre
-
添加 v-pre 指令,就是告诉 vue 这段节点中没有指令或表达式,不需要解析这样,Vue 就跳过这一段内容的解析,从而,提升性能
-
代码
<p>{{ num }}</p>
<p v-pre>带 v-pre {{ num }}</p>
其他指令 v-cloak
1.代码
<!-- 组件 -->
<h1 v-cloak>{{ msg }}</h1>
<!-- 样式 -->
[v-cloak] { display: none }
<!-- 实例vm前阻塞一下 -->
alert(1)
-
分析
// 1.页面为什么会闪???闪是因为页面的内容 由 {{ msg}} ==> 100
// 2. 解决办法 : 使用遮盖
// 2.1 给要遮盖的元素添加一个 v-cloak 指令
// 2.2 使用属性选择器,添加样式
// 2.3 vue 会在解析模板后,将 v-cloak指定,从页面中移除
// 移除指令的时候,{{}} 已经变为对应的数据
-
注意 : 演示每次右键打开,不要在当前页面刷新,有缓存的
-
如果很多元素都需要遮盖,那么久就给父元素添加这个指令
生命周期函数
-
所有的 vue 组件,都是 vue 实例, 一个组件对应一个实例,并且接收相同的选项对象(一些根实例特有的选项除外)
-
实例生命周期也叫做 : 组件生命周期
生命周期介绍
-
简单说 : 一个组件(实例) 从开始到最后消灭所经历的各种状态,就是一个组件(实例)的生命周期
-
生命周期钩子函数的定义 : 从组件被创建,到组件挂在到页面上运行,再到页面关闭组件被销毁,这三个阶段总是伴随着组件各种的事件,这些事件,统称为组件的生命周期函数 (简称 : 钩子函数)
-
开发人员可以通过 vue 提供的钩子函数,让我们写的代码参与到 vue 的生命周期里面来,让我们的代码在合适的阶段起到相应的作用
注意 :
-
注意 : vue 在执行过程中 会自动调用
生命周期钩子函数
, 我们只需要提供这些钩子函数即可 -
注意 : 钩子函数的名称都是 vue 中规定好的
学习 vue 组件生命周期 学什么?
-
Vue 内部执行的流程(难)
-
钩子函数如何使用 (两个重要的钩子函数 created mounted)
钩子函数 - beforeCreate
-
说明 : 在实例初始化之前,数据观测 和 event/watcher 事件配置之前被调用
-
组件实例刚被创建,组件属性计算之前, 例如 data 属性 methods 属性
-
注意 : 此时,无法获取 data 中的数据 和 methoids 中的方法
-
场景 : 几乎不用
钩子函数 - created (掌握)
-
说明 : 组件实例创建完成,属性已绑定, 可以调用 methods 中的方法、可以获取 data 值
-
使用场景 : 1-发送 ajax 2-本地存储获取数据
-
beforeCreate() { // 无法获取数据和事件 console.warn('beforeCreate', this.msg, this.fn) }, created() { console.warn('created', this.msg, this.fn) },
Has 'el' option ?
-
YES => 就是正常的 el 边界
-
NO => 可以注释,但是必须要手动添加
vm.$mount(el)
去指定边界
vm.$mount('#app')
Has template
option?
-
No => 将 el 的 outerHtml 作为模板进行编译 ( outerHTML = 自身 + innerHTML )
-
YES =>
// 如果提供了 template, 那么 vue 就会将 template 的内容进行编译,编译后,替换页面中 vue 管理的边界
template : `
<h1>嘻嘻</h1>
`,
钩子函数 - beforeMounted()
-
说明 : 在挂载开始之前被调用 (挂载:可以理解DOM 渲染)
钩子函数 - mounted() (掌握)
-
说明 : 挂载之后, DOM 完成渲染
-
使用场景 : 1-发送 ajax 2-操作 DOM
-
记得把template去掉 // 渲染DOM之前 beforeMount() { // 渲染之前的 <h1 id="h1" @click="fn">{{ msg }}</h1> console.log(document.querySelector('h1')) }, // 渲染DOM之后 <h1 id="h1">测试</h1> mounted() { console.log(document.querySelector('h1')) }
钩子函数 - beforeUpdated()
-
说明:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
-
注意:此处获取的数据是更新后的数据,但是获取页面中的 DOM 元素是更新之前的
小提示 : 打印 this.$el ,打开小三角是之后的,是因为打印是有监听的功能,展示的是后面更改之后的
钩子函数 - updated()
-
说明:组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
-
beforeUpdate() { // 更新之前的值 : 信息 console.warn('beforeUpdate',document.querySelector('h1').innerText) }, updated() { // 更新之后的值 : 信息1111 console.warn('updated', document.querySelector('h1').innerText) }
钩子函数 - beforeDestroy()
-
说明:实例销毁之前调用。在这一步,实例仍然完全可用。
-
使用场景:实例销毁之前,执行清理任务,比如:清除定时器等
created() {
this.timerId = setInterval(() => {
console.log(1111);
}, 500);
},
// 如果当组件销毁了,还不清除定时器会出现性能问题
// 在浏览器中可以尝试销毁 vm.$destroy()
// 最后销毁
beforeDestroy() {
clearInterval(this.timerId)
},
钩子函数 - destroyed()
说明:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
使用钩子函数来完善 数据存储
created {
this.list = JSON.parse(localStorage.getItem('list'))
}
使用接口的形式发送数据
json-server 提供假数据接口
-
json-server 作用 : 根据指定的 JSON 文件, 提供假数据接口
-
地址 : json-server
-
使用步骤
1. 全局安装 json-server : `npm i -g json-server` 2. 准备一个json数据 3. 执行 : `json-server data.json` > json数据参考 json数据可以参考 : { "todos": [ { "id": 1, "name": "吃饭", "age": 20 } ] }
-
REST API 格式
* 1. 查询 : GET
* 2. 添加 : POST
* 3. 删除 : DELETE
* 4. 更新 : PUT 或者 PATCH(打补丁)
axios 发送请求 (重点掌握)
读音 : /艾克笑丝/
作用 : 一个专门用来发送 ajax 请求的库, 可以在浏览器或者 node.js 中使用
Promise based HTTP client for the browser and node.js
以Promise为基础的HTTP客户端,适用于:浏览器和node.js
封装ajax,用来发送请求,异步获取数据
使用步骤
1. 本地安装 axios : `npm i axios`
2. 导入 axios
3. 使用
过滤器
概念 :
-
vue 中的过滤器(filter) : 数据格式化 ,
-
也就是说,让数据按照我们规定的一种格式输出
-
比如 : 对于日期来说,将日期格式化转化为
年-月-日 小时:分:秒
格式的过程
// 直接显示
<h1>{{ date }}</h1>
显示 : 2019-01-11T10:11:19.566Z
不是我们想要的
我们想要的 : 2019-01-11 18-11-53
全局过滤器 和 局部过滤器
-
说明 : 通过全局方式创建的过滤器,在任何一个组件中都可以使用
-
注意点: 使用全局过滤器的时候,应该先创建全局过滤器,再创建 Vue 实例
-
局部创建的过滤器 只能在当前 vue组件中使用
-
怎么注册 全局过滤器
// 第一个参数 : 过滤器的名字
// 第二个参数 : 是一个回调函数,只要使用过滤器的时候,这个回调函数就会执行
/// 通过回调函数的返回值得到格式化后的数据
Vue.filter('date', res => {
return '嘻嘻'
})
过滤器
-
概念 :
-
vue 中的过滤器(filter) : 数据格式化 ,
-
也就是说,让数据按照我们规定的一种格式输出
-
比如 : 对于日期来说,将日期格式化转化为
年-月-日 小时:分:秒
格式的过程
// 直接显示
<h1>{{ date }}</h1>
显示 : 2019-01-11T10:11:19.566Z
不是我们想要的
我们想要的 : 2019-01-11 18-11-53
-
全局过滤器 和 局部过滤器
-
说明 : 通过全局方式创建的过滤器,在任何一个组件中都可以使用
-
注意点: 使用全局过滤器的时候,应该先创建全局过滤器,再创建 Vue 实例
-
局部创建的过滤器 只能在当前 vue组件中使用
-
怎么注册 全局过滤器
// 第一个参数 : 过滤器的名字
// 第二个参数 : 是一个回调函数,只要使用过滤器的时候,这个回调函数就会执行
/// 通过回调函数的返回值得到格式化后的数据
Vue.filter('date', res => {
return '嘻嘻'
})
-
使用过滤器 示例 :
// 组件
<h1>时间戳-格式 {{ date2 | date }}</h1>
// js
Vue.filter('date', res => {
return `${res.getFullYear()}-${res.getMonth()}-${res.getDate()} ${res.getHours()}:${res.getMinutes()}:${res.getSeconds()}`
})
-
moment 插件
-
使用
1. 安装 : `npm i moment` 2. 引入 : 3. 使用
-
日期 => 指定格式
moment(res).format('YYYY-MM-DD HH-mm-ss')
-
时间戳 => 指定格式
moment(res).format('YYYY-MM-DD HH-mm-ss')
-
// 全局 Vue.filter('date', res => { return moment(res).format('YYYY-MM-DD HH-mm-ss') })
-
参数问题
-
示例
<h1>时间戳-格式 {{ date2 | date('YYYY-MM-DD HH-mm-ss',888) }}</h1>
// 默认值
Vue.filter('date', (res, format = 'YYYY-MM-DD', arg) => {
console.log(arg)
return moment(res).format(format)
})
局部过滤器
在 vm 的配置项里写一个
filters
对应的是一个对象
使用过滤器 示例 :
// 组件
<h1>时间戳-格式 {{ date2 | date }}</h1>
// js
Vue.filter('date', res => {
return `${res.getFullYear()}-${res.getMonth()}-${res.getDate()} ${res.getHours()}:${res.getMinutes()}:${res.getSeconds()}`
})
moment 插件
-
使用
1. 安装 : `npm i moment` 2. 引入 : 3. 使用
-
日期 => 指定格式
moment(res).format('YYYY-MM-DD HH-mm-ss')
-
时间戳 => 指定格式
moment(res).format('YYYY-MM-DD HH-mm-ss')
-
// 全局 Vue.filter('date', res => { return moment(res).format('YYYY-MM-DD HH-mm-ss') })
组件
一 : 组件化开发
-
概念 :将一个完整的页面,抽离成一个个独立的组件,最终,通过这一个个独立组件完成整个的页面(项目)的功能
-
组件化开发的优势/作用 : 复用
-
官网 : 组件是可复用的 Vue 实例
二 : 组件的基本使用
-
Vue 中的两种注册组件的方法 1.全局注册 2.局部注册
全局组件在所有的vue实例中都可以使用 局部组件在所有的当前实例中可以使用
2) 注册全局组件 - 基本使用 1
/**
* 第一个参数 : 组件名
* 第二个参数 : 是一个配置对象, 该配置对象与 Vue 实例的配置对象几乎完全相同
* 也就是说: vue实例中用到的配置项,和组件中的配置项几乎相同
*/
Vue.component('hello', {
template: `
<h1 class="red">这是hello组件</h1>
`
})
-
注意点
-
注册全局组件也是放到 vm 实例之前
-
模板只有一个根节点
-
组件的配置项和 vue 实例 的配置项一样 (如:data、methods、filters、watch、computed、钩子函数等)
-
组件的 data 是一个函数 返回一个对象
var Component = function() {}
// 使用对象
Component.prototype.data = {
demo: 123
}
// 使用函数
Component.prototype.data = function() {
return {
demo: 111
}
}
var component1 = new Component()
var component2 = new Component()
component1.data().demo = '8888'
console.log(component2.data().demo) // 456
示例:
<h1 @click='fn' class="red">这是hello组件</h1>
methods: {
fn() {
console.log('fn')
}
},
computed: {},
watch: {},
filters: {}
}
组件通讯 (介绍)
-
组件是一个独立、封闭的个体
-
也就是说 : 组件中的数据默认情况下, 只能在组件内部使用,无法直接在组件外部使用
-
可以将 vue 实例看做一个组件
-
对于组件之间需要相互使用彼此的情况,应该使用 组件通讯 机制来解决
-
组件通讯的三种情况 :
-
父组件将数据传递给子组件(父 -> 子)
-
子组件将数据传递给父组件 (子 => 父)
-
非父子组件(兄弟组件)
父 ==> 子 (重点) 两步
-
将要传递的数据,通过属性传递给子组件
<child :msg="pmsg"></child>
-
子组件通过 props 配置项,来指定要接收的数据
props: ['msg']
完善 TodoMVC => 完成 传值 + 渲染列表页
子 ==> 父 (重点) 三步
1 父组件中提供一个方法
pfn(arg) {
console.log('父组件中接受到子组件传递过来的数据:', arg)
}
2 将这个方法传递给子组件
// 自定义事件 <child @fn="pfn"></child>
3 子组件调用这个方法( 触发父组件中传递过来的自定义事件 )
// 这个方法是点击事件触发的
handleClick() {
// 调用父组件中的方法 fn
// 注意:通过 $emit 方法来触发事件 fn
// 第一个参数:表示要触发的自定义事件名称,也就是 @fn
// 第二个参数:表示要传递给父组件的数据
this.$emit('fn', 'child msg')
}
非父子之间通讯 ( 组件 => 组件 ) (重点)
需求 : 组件 jack ===> 恁弄啥哩 ===> 组件 rose
-
是通过
事件总线 (event bus 公交车) 的机制
来实现的 -
事件总线 : 实际上就是一个
空Vue实例
-
可以实现任意两个组件之间的通讯,而不管两个组件到底有什么样的层级关系
-
看图
-
示例 :
// 第一步 : 事件总线
var bus = new Vue()
// 第二步 : 发送数据 可在点击事件里 触发事件
// 参数1 : 唯一标识 参数2:参数
bus.$emit('todo', '恁弄啥哩?')
// 第三步 : 接收数据 可在 created 里 注册事件
bus.$on('todo', arg => {
console.log('接收过来的', arg)
})
prop 的大小写
-
官 : HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。
html 的标签和 属性 都是一样,忽略大小写
<H1 TITLE="哈哈">我是h1</H1>
-
官 : 这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名不好使了
-
<child :cMsg="pmsg"></child>
会报警告,父传子也接收不到了 -
原因是 : 接收的属性是:cMsg, 接收的数据名,因为忽略大小写,数据已为 : cmsg
-
所以已经准备要读取的 是 cmsg 的值,找不到,所以要报警告
You should probably use "c-msg" instead of "cMsg".
-
方式 1 : 全用小写,不要使用驼峰命名
接收 :
cmsg
props/读取 :cmsg
-
方式 2 官 : 需要使用其等价的 kebab-case (短横线分隔命名) 命名:
接收 :
:c-msg='pmsg'
props/读取 :cMsg
(一定要注意是 props ,所以只会出现在父传子,不存在子传父里)
路由 (重难点)
-
路由 : 是浏览器 URL 中的
哈希值
( # hash) 与展示视图内容
之间的对应规则
-
指路
在 web App 中, 通过一个页面来展示和管理整个应用的功能.
SPA 往往是功能复杂的应用,为了有效管理所有视图内容,前端路由 应运而生.
简单来说,路由就是一套映射规则(一对一的对应规则), 由开发人员制定规则.
当 URL 中的哈希值( `#` hash) 发生改变后,路由会根据制定好的规则, 展示对应的视图内容
-
vue 中的路由 : 是 hash 和 component 的对应关系, 一个哈希值对应一个组件
基本使用
-
-
安装路由 :
npm i vue-router
-
-
-
引入路由
-
<script src="./vue.js"></script>
// 千万注意 :引入路由一定要在引入vue之后,因为vue-router是基于vue工作的
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
-
-
实例路由对象+挂载到 vue 上
const router = new VueRouter()路由实例 与 Vue 实例 关联到一起验证路由是否挂载成功, 就看打开页面,最后面有没有个
#/
详细使用步骤 ( 四步骤 )
-
-
3.1 入口 (#哈希值)
// 方式1 : url地址为入口 调试开发用
输入url地址 改变哈希值
`01-路由的基本使用.html#/one`
// 方式2 : router-link+to
-
3.2 设置路由规则
// path : 路由路径
// component : 将来要展示的路由组件
routes: [{ path: '/one', component: One }, { path: '/two', component: Two }]
-
3.3 组件
一个哈希值对应一个组件
const One = Vue.component('one', {
template: `
<div> 子组件 one </div>
`
})
-
3.4 出口
<!-- 出口 组件要展示的地方-->
<router-view></router-view>
使用注意事项
-
入口(哈希)
-
最常用的入口
<!-- 1. 入口 -->
<!--
to 属性 , 实际上就是哈希值,将来要参与路由规则中进行与组件匹配
router-link 组件最终渲染为 : a标签, to属性转化为 a标签的href属性
-->
<router-link to="/one">首页</router-link>
-
组件
组件可以改为对象格式
const One = {
template: `
<div> 子组件 one </div>
`
}
-
过程 : 入口 ==> 路由规则 ==> 组件 ==> 出口
-
演示 : 多个组件匹配
-
示例 :
<div id="app">
<!-- 1 路由入口:链接导航 -->
<router-link to="/one">One</router-link>
<router-link to="/two">Two</router-link>
<!-- 4 路由出口:用来展示匹配路由视图内容 -->
<router-view></router-view>
</div>
<!-- 导入 vue.js -->
<script src="./vue.js"></script>
<!-- 导入 路由文件 -->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3 创建两个组件
const One = Vue.component('one', {
template: '<h1>这是 one 组件</h1>'
})
const Two = Vue.component('two', {
template: '<h1>这是 two 组件</h1>'
})
// 0 创建路由对象
const router = new VueRouter({
// 2. 路由规则
routes: [
{ path: '/one', component: One },
{ path: '/two', component: Two }
]
})
const vm = new Vue({
el: '#app',
//0. 不要忘记,将路由与vue实例关联到一起!
router
})
</script>
精确匹配和模糊匹配
-
精确匹配 : router-link-exact-active 类名 : 只有当
浏览器地址栏中的哈希值 与 router-link 的 to 属性值,完全匹配对,才会添加该类
-
模糊匹配: router-link-active 类名 : 只要
浏览器地址栏中的哈希值
包含 router-link 的 to 属性值,就会添加该类名 -
解决办法 : 加个 exact
<router-link to="/" exact>
One
</router-link>
-
注意 : 精确匹配和模糊匹配,只对添加类名这个机制有效,与路由的匹配规则无关!!!