学习笔记|Vue的基础入门及使用
Vue的基础入门及使用
第一章 Vue核心
1.1 Vue的基本认识
1.1.1 官网
- 英文官网:https://vuejs.org/
- 中文官网:https://cn.vuejs.org/
- 渐进式JavaScript框架
- 作者:尤雨溪(一位华裔前Google工程师)
- 作用:动态 构建用户界面
- 1.遵循MVVM模式
- M:Model,模型,数据对象(data)
- V:View,视图,模板页面
- VM:ViewModel,视图模型(Vue的实例)
- 2.编码简洁,体积小,运行效率高,适合移动/PC端开发
- 3.它本身只关注UI,可以轻松引入Vue插件或其他第三库开发项目
- el:
- 指定dom标签容器的选择器
- Vue就会管理对应的标签及其子标签
- data:
- 对象或函数类型
- 指定初始化状态属性数据的对象
- vm也会自动拥有data中所有属性
- 页面中可以直接访问使用
- 数据代理:由vm对象来代理对data中所有属性的操作(读/写)
- methods:
- 包含多个方法的对象
- 供页面中的时间指令来绑定回调
- 回调函数默认有event参数,但也可以指定自己的参数
- 所有的方法由vue对象来调用,访问data中的属性可以直接使用this.xxx
- computed:
- 包含多个方法的对象
- 对状态属性进行计算返回一个新的数据,供页面获取显示
- 一般情况下是相当于是一个只读的属性
- 利用set/get方法来实现属性数据的计算读取,同时监视属性数据的变化
- 如何给对象定义get/set属性
- 在创建对象时指定:get name(){return xxx}/set name(value) {}
- 对象创建之后指定:Object.defineProperty(obj,age,{get(){},set(value){}})
- watch
- 包含多个属性监视的对象
- 分为一般监视和深度监视
xxx:function(value){} xxx:{ deep:true, handler:fun(value) }
- 另一种添加监视方法:vm.$watch(‘xxx’,function(value){})
- 包含多个属性监视的对象
- 借鉴Angular的模板和数据绑定技术
- 借鉴React的组件和虚拟DOM技术
- vue-cli:vue脚手架
- vue-resouce(axios):ajax请求
- vue-route:路由
- vuex:状态管理
- vue-lazyload:图片懒加载
- vue-scoller:页面滑动相关
- mint-ui:基于vue的UI组件库(移动端)
- element-ui:基于vue的UI组件库(PC端)
1.2.1 永远的HelloWorld
01_HelloWorld - 锐客网
Hello {{msg}}
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
const vm = new Vue({ // 配置对象 options
// 配置选项(option)
el: '#test',// element: 选择器,指定用vue来管理页面中的哪个标签区域
data: {
msg: 'World'
}
})
1.2.2 Vue的调试工具
文章图片
打开Vue页面,F12进入开发者调试,选择Vue,即可使用该调试工具。
1.2.3 Vue的MVVM
文章图片
1.3 Vue的模板语法
1.3.1 模板的理解:
- 动态的HTML页面
- 包含了一些JS语法代码
- 大括号表达式
- 指令(以v-开头的自定义标签属性)
模板语法 - 锐客网
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
new Vue({
el: '#app',
data: {
content: 'NBA I Love This Game',
url: 'http://www.baidu.com'
},
methods: {
test () {
alert('好啊!!!')
}
}
})
1.4 计算属性和监视
1.4.1 计算属性
- 在computed属性对象中定义计算属性的方法
- 在页面中使用{{方法名}}来显示计算的结果
- 通过VM对象的$watch()或watch配置来监视指定的属性
- 当属性变化时,回调函数自动调用,在函数内部进行计算
- 通过getter/setter实现对属性数据的显示和监视
- 计算属性存在缓存,多次读取只执行一次getter计算
计算属性和监视 - 锐客网
姓:
名:
姓名1(单向):
姓名2(单向):
姓名3(双向):
{{fullName1}}
{{fullName1}}
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
const vm = new Vue({
el: '#demo',
data: {
firstName: 'A',
lastName: 'B',
fullName2: 'A-B'
},// 计算属性配置: 值为对象
computed: {
//什么时候执行:初始化显示/相关的data属性发生变化
fullName1 () { // 属性的get()
console.log('fullName1()', this)
return this.firstName + '-' + this.lastName
},fullName3: {
// 回调函数的三个属性:1.你定义的2.你没有调用3.但是它执行了
// 回调函数:什么时候调用?用来做什么
// 当获取当前属性值时自动调用, 将返回值(根据相关的其它属性数据)作为属性值
get () {
console.log('fullName3 get()')
return this.firstName + '-' + this.lastName
},
// 当属性值发生了改变时自动调用, 监视当前属性值变化, 同步更新相关的其它属性值
set (value) {// fullName3的最新value值A-B23
console.log('fullName3 set()', value)
// 更新firstName和lastName
const names = value.split('-')
this.firstName = names[0]
this.lastName = names[1]
}
}
},watch: {
// 配置监视firstName
firstName: function (value) { // firstName发生了变化,相当于属性的set
console.log('watch firstName', value)
// 更新fullName2
this.fullName2 = value + '-' + this.lastName
}
}
})// 监视lastName
vm.$watch('lastName', function (value) {
console.log('$watch lastName', value)
// 更新fullName2
this.fullName2 = this.firstName + '-' + value
})
1.5 class与style绑定
1.5.1 理解
- 在应用界面上,某个(些)元素的样式是变化的
- class/style绑定就是专门用来实现动态样式效果的技术
- :class=‘xxx’
- 表达式是字符串:‘classA’
- 表达式是对象:{classA:isA,classB:isB}
- 表达式是数组:[‘classA’,‘classB’]
- :style="{color:activeColor,fontSize:fontSize+‘px’}"
- 必须是对象
- 其中activeColor/fontSize 是data属性
class与style绑定 - 锐客网
>
.classA {
color: red;
}
.classB {
background: blue;
}
.classC {
font-size: 20px;
}
1. class绑定: :class='xxx'
xxx是字符串
xxx是对象
xxx是数组
2. style绑定
:style="{ color: activeColor, fontSize: fontSize + 'px' }"
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
new Vue({
el: '#demo',
data: {
myClass: 'classA',
hasClassA: true,
hasClassB: false,
activeColor: 'red',
fontSize: '20px'
},methods: {
update () {
this.myClass = 'classB'
this.hasClassA = !this.hasClassA
this.hasClassB = !this.hasClassB
this.activeColor = 'yellow'
this.fontSize = '30px'
}
}
})
1.6 条件渲染
1.6.1 条件渲染指令
- v-if与v-else
- v-show
- 如果需要频繁切换,v-show较好
- 当条件不成立时,v-if的所有子节点不会解析(项目中使用)
条件渲染 - 锐客网
表白成功
表白失败
求婚成功
求婚失败
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
new Vue({
el: '#demo',
data: {
ok: true,
}
})
1.7 列表渲染
1.7.1 列表显示指令
- 数组:v-for/index
- 对象:v-for/key
- 删除item
- 替换item
- 列表过滤
- 列表排序
列表渲染 - 锐客网
测试: v-for 遍历数组
-
{{index}}--{{p.name}}--{{p.age}}
--
--
测试: v-for 遍历对象
- {{key}}={{item}}
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
new Vue({
el: '#demo',
data: {
persons: [
{name: 'Tom', age:18},
{name: 'Jack', age:17},
{name: 'Bob', age:19},
{name: 'Mary', age:16}
]
},methods: {
deleteP (index) {
this.persons.splice(index, 1) // 调用了不是原生数组的splice(), 而是一个变异(重写)方法
// 1. 调用原生的数组的对应方法
// 2. 更新界面
},updateP (index, newP) {
console.log('updateP', index, newP)
// this.persons[index] = newP// vue根本就不知道
this.persons.splice(index, 1, newP)
// this.persons = []
},addP (newP) {
this.persons.push(newP)
}
}
})
1.7.5 列表的搜索排序
过滤与排序 - 锐客网
-
{{index}}--{{p.name}}--{{p.age}}
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
new Vue({
el: '#demo',
data: {
searchName: '',
orderType: 0, // 0代表不排序, 1代表降序, 2代表升序
persons: [
{name: 'Tom', age:18},
{name: 'Jack', age:17},
{name: 'Bob', age:19},
{name: 'Mary', age:16}
]
},computed: {
filterPersons () {
//debugger
// 取出相关数据
const {searchName, persons, orderType} = this
let arr = [...persons]
// 过滤数组
if(searchName.trim()) {
arr = persons.filter(p => p.name.indexOf(searchName)!==-1)
}
// 排序
if(orderType) {
arr.sort(function (p1, p2) {
if(orderType===1) { // 降序
return p2.age-p1.age
} else { // 升序
return p1.age-p2.age
}})
}
return arr
}
},methods: {
setOrderType (orderType) {
this.orderType = orderType
}
}
})
1.8 事件处理
1.8.1 绑定监听
- v-on:xxx=“fun”
- @xxx=“fun”
- @xxx=“fun(参数)”
- 默认事件形参:event
- 隐含属性对象:$event
- .prevent:阻止事件的默认行为event.preventDefault()
- .stop:停止事件冒泡 event.stopPropagation()
- .keycode:操作的是某个keycode值的键
- .keyName:操作的是某个按键名的键(少部分)
07_事件处理 - 锐客网 1. 绑定监听
2. 事件修饰符
百度一下
3. 按键修饰符
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
new Vue({
el: '#example',
data: {},
methods: {
test1(event) {
alert(event.target.innerHTML)
},
test2 (msg) {
alert(msg)
},
test3 (msg, event) {
alert(msg+'---'+event.target.textContent)
},test4 () {
alert('点击了链接')
},test5 () {
alert('out')
},
test6 () {
alert('inner')
},test7 (event) {
console.log(event.keyCode)
alert(event.target.value)
}
}
})
1.9 表单输入绑定
1.9.1 使用v-model对表单数据自动收集
- text/textarea 文本
- checkbox 多选
- radio 单选
- select 选择
表单输入绑定 - 锐客网
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
new Vue({
el: '#demo',
data: {
username: '',
pwd: '',
sex: '男',
likes: ['foot'],
allCitys: [{id: 1, name: 'BJ'}, {id: 2, name: 'SS'}, {id: 3, name: 'SZ'}],
cityId: '2',
info: ''
},
methods: {
handleSubmit () {
console.log(this.username, this.pwd, this.sex, this.likes, this.cityId, this.info)
alert('提交注册的ajax请求')
}
}
})
1.10 Vue实例生命周期
1.10.1 生命周期流程图
文章图片
1.10.2 vue生命周期分析
- 1.初始化显示
- beforeCreate()
- created()
- beforeMount()
- mounted()
- 2.更新状态:this.xxx=value
- beforeUpdate()
- updated()
- 3.销毁vue实例:vm.$destory()
- beforeDestory()
- destoryed()
- created()/mounted():发送ajax请求,启动定时器等异步任务
- beforeDestory():做收尾工作,如:清除定时器
生命周期 - 锐客网
尚硅谷IT教育
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
new Vue({
el: '#test',
data: {
isShow: true
},beforeCreate() {
console.log('beforeCreate()')
},created() {
console.log('created()')
},beforeMount() {
console.log('beforeMount()')
},mounted () {
console.log('mounted()')
// 执行异步任务
this.intervalId = setInterval(() => {
console.log('-----')
this.isShow = !this.isShow
}, 1000)
},beforeUpdate() {
console.log('beforeUpdate()')
},
updated () {
console.log('updated()')
},beforeDestroy() {
console.log('beforeDestroy()')
// 执行收尾的工作
clearInterval(this.intervalId)
},destroyed() {
console.log('destroyed()')
},methods: {
destroyVue () {
this.$destroy()
}
}
})
1.11 过渡&动画
1.11.1 vue动画的理解
- 操作css的trasition或animation
- vue会给目标元素添加/移除特定的class
- 过渡的相关类名
- xxx-enter-active:指定显示的transition
- xxx-leave-action:指定隐藏的transition
- xxx-enter/xxx-leave-to:指定隐藏时的样式
文章图片
- 在目标元素外包裹
- 定义calss样式
- 指定过渡样式:transition
- 指定隐藏时的样式:opacity/其他
过渡&动画 - 锐客网
>
/*指定过渡样式*/
.xxx-enter-active, .xxx-leave-active {
transition: opacity 1s
}
/*指定隐藏时的样式*/
.xxx-enter, .xxx-leave-to {
opacity: 0;
}.move-enter-active {
transition: all 1s
}.move-leave-active {
transition: all 3s
}.move-enter, .move-leave-to {
opacity: 0;
transform: translateX(20px)
}
hello
hello
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
new Vue({
el: '#demo',
data: {
show: true
}
})new Vue({
el: '#demo2',
data: {
show: true
}
})
1.12 过滤器
1.12.1 理解过滤器
- 功能:对要显示的数据进行特定格式化后在显示
- 注意:并没有改变原本的数据,可以产生新的对应的数据
- 定义过滤器
Vue.filter(filterName,function(value[,arg1,arg2,....])){
// 进行一定的数据处理
return new Value
}
- 使用过滤器
{{myData|filterName}}
{{myData|filterName(arg)}}
1.12.3 代码实现
过滤器 - 锐客网
显示格式化的日期时间
{{time}}
最完整的: {{time | dateString}}
年月日: {{time | dateString('YYYY-MM-DD')}}
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript" src="https://cdn.bootcss.com/moment.js/2.22.1/moment.js">
>
// 定义过滤器
Vue.filter('dateString', function (value, format='YYYY-MM-DD HH:mm:ss') {return moment(value).format(format);
})new Vue({
el: '#test',
data: {
time: new Date()
},
mounted () {
setInterval(() => {
this.time = new Date()
}, 1000)
}
})
1.13 内置指令与自定义指令
1.13.1 常用内置指令
- v:text:更新元素的textContent
- v-html:更新元素的innerHTML
- v-if:如果为true,当前标签才会输出到页面
- v-else:如果为false,当前标签才会输出到页面
- v-show:通过控制display样式来控制显示/隐藏
- v-for:遍历数组/对象
- v-on:绑定事件监听,一般简写为@
- v-bind:强制绑定解析表达式,可以省略v-bind
- v-model:双向数据绑定
- ref:指定唯一标识,vue对象通过$els属性访问这个元素对象
- v-cloak:防止闪现,与css配合:[v-cloak]{display:none}
- 注册全局指令
Vue.directive('my-directive',function(el,binding){
el.innerHTML = binding.value.toupperCase()
})
- 注册局部指定
directives:{
'my-directive':{
bind(el,binding){
el.innerHTML = binding.value.toupperCase()
}
}
}
- 使用自定义指令
v-my-directive='xxx'
1.13.5 内置编码实现
内置指令 - 锐客网
>
[v-cloak] { display: none }
{{content}}
abcd
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
new Vue({
el: '#example',
data: {
content: '百度一下'
},
methods: {
hint () {
alert(this.$refs.msg.innerHTML)
}
}
})
1.13.6 自定义指令编码实现
自定义指令 - 锐客网
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript">
// 注册一个全局指令
// el: 指令所在的标签对象
// binding: 包含指令相关数据的容器对象
Vue.directive('upper-text', function (el, binding) {
console.log(el, binding)
el.textContent = binding.value.toUpperCase()
})
new Vue({
el: '#test',
data: {
msg: "I Like You"
},
// 注册局部指令
directives: {
'lower-text'(el, binding) {
console.log(el, binding)
el.textContent = binding.value.toLowerCase()
}
}})new Vue({
el: '#test2',
data: {
msg: "I Like You Too"
}
})
1.14 自定义插件
1.14.1 说明
- Vue插件是一个包含install方法的对象
- 通过install方法给Vue或Vue实例添加方法,定义全局指令等
插件 - 锐客网
type="text/javascript" src="https://www.it610.com/js/vue.js">
type="text/javascript" src="https://www.it610.com/article/vue-myPlugin.js">
type="text/javascript">
// 声明使用插件(安装插件: 调用插件的install())
Vue.use(MyPlugin) // 内部会调用插件对象的install()const vm = new Vue({
el: '#test',
data: {
msg: 'HaHa'
}
})
Vue.myGlobalMethod()
vm.$myMethod()new Object()
第二章 Vue组件化编码 2.1 使用vue-cli创建模板项目
2.1.1 说明
- vue-cli是vue官方提供的脚手架工具
- github:https://github.com/vuejs/vue-cli
- 作用:从https://github.com/vuejs-templates下载模板项目
- npm install -g vue-cli :全局安装vue-cli
- vue init webpack vue_demo :当前目录下创建项目名称为vue_demo的webpack模板
- cd vue_demo :进入vue_demo文件夹
- npm install :安装
- npm run serve :运行该项目
- 访问http://localhost:8080 :项目访问地址
- build:webpack相关的配置文件夹(基本上不需要修改)
- dev-serve.js:通过express启动后台服务器
- config:webpack相关的配置文件夹(基本上不需要修改)
- index.js:指定的后台服务的端口号和静态资源文件夹
- node_modules:vue的依赖
- src:源码文件夹
- components:vue组件及其相关资源文件夹
- App.vue:应用根主组件
- main.js:应用入口js
- static:静态资源文件夹
- .babelrc:babel的配置文件
- .selintignore:eslint检查忽略的配置
- .eslintrc.js:eslint检查的配置
- .gitignore:git版本管制忽略的配置
- index.html:主页面的文件
- package.json:应用包配置文件
- README.md:应用描述说明的readme文件
2.2.1 打包
- npm run build
- npm install -g serve
- serve dist
- 访问:http://localhost:5000
- 修改配置:webpack.prod.conf.js
output:{
publicPath:'/xxx/'//打包文件夹的名称
}
- 重新打包
- npm run build
- 修改dist文件夹为项目名称:xxx
- 将xxx拷贝到运行的tomcat的webapps目录下
- 访问:http://localhost:8080/xxx
2.3.1 说明
- ESLint是一个代码规范检查工具
- 它定义了很多特定的规则,一旦你的代码违背了某一规则,eslint会作出非常有用的提示
- 官网:http://eslint.org/
- 基本已经替代以前的JSLint
- ES
- JSX
- style检查
- 自定义错误和提示
- 语法错误校验
- 不重要或丢失的标点符号,如分号
- 没法运行到的代码块
- 未被使用的参数提醒
- 确保样式的统一规则,如sass或者less
- 检查变量的命名
- 0:关闭规则
- 1:打开规则,并且作为一个警告(信息打印黄色字体)
- 2:打开规则,并且作为一个错误(信息打印红色字体)
- .eslintrc.js:全局规则配置文件
'rules':{
'no-new':1
}
- 在js/vue文件中修改局部规则
/* eslint-disable no-new*/
new Vue({
el:'#body',
components:{App}
})
- .eslintignore:指令检查忽略的文件
*.js
*.vue
2.4 组件定义与使用
2.4.1 vue文件的组成(3个部分)
- 模板页面
页面模板
- JS模块对象
>
export default{
data(){//模板里面只能写方法
return:{}
},
methods:{},
computed:{}.
components:{}
}
- 样式
>
样式定义
2.4.2 基本使用
- 引入组件
- 映射成标签
- 使用组件标签
文章图片
>
//1.引入组件
import HelloWorld from './components/HelloWorld.vue'
export default {
// 2.映射组件标签
components:{
HelloWorld
}
}
>
2.4.3 关于标签名与标签属性名书写问题
- 写法一:一模一样
- 写法二:大写变小写,并用-连接
2.5.1 组件间通信基本原则
- 不要在子组件中直接修改父组件的状态数据
- 数据在哪,更新数据的行为(函数)就应该定义在哪
- props
- vue的自定义事件
- 消息订阅与发布(如:pubsub库)
- slot
- vuex(后面单独)
2.6.1 使用组件标签
2.6.2 定义MyComponent时
- 在组件内声明所有的props
- 方式一:只指定名称
props:['name','age','setName']
- 方式二:指定名称和类型
props:{
name:String,
age:Number,
setName:Function
}
- 方式三:指定名称/类型/必要性/默认值
props:{
name:{type:String,required:true,default:xxx}
}
2.6.3 注意
- 此方式用于父组件向子组件传递数据
- 所有标签属性都会成为组件对象的属性,模板页面可以直接引用
- 问题:
- 如果需要向非子后代传递数据,必须多层逐层传递
- 兄弟组件间也不能直接pops通信,必须借助父组件才可以
2.7.1 绑定事件监听
//方式一:通过v-on绑定
@delete_to="deleteTodo"
//方式二:通过$on()
this.$refs.xxx.$on('delete_todo',function(todo)){
this.deleteTodo(todo)
}
2.7.2 触发事件
//触发事件
this.$emit(eventName,data)
2.7.3 注意
- 此方式只适用于子组件向父组件发送消息(数据)
- 问题:隔代组件或兄弟组件间通信此种方式不合适
2.8.1 订阅消息
PubSub.subscribt('msg',function(msg,data){})
2.8.2 发布新消息
PubSub.publish('msg',data)
2.8.3 注意 优点:此方式可实现任意关系组件间的通信(数据)
2.8.4 事件的两个重要操作
- 绑定事件监听(订阅消息)
- 目标:标签元素
- 事件名(类型):click/focus
- 回调函数:function(event){}
- 触发事件(发布消息)
- DOM事件:用户在浏览器上对应的界面上做对应的操作
- 自定义:编码手动触发
2.9.1 理解 此方式用于父组件向子组件传递“标签数据”
2.9.2 子组件:Child.vue
name="xxx">不确定的标签结构1
组件不确定的标签结构
name="yyy">不确定的标签结构2
2.9.3 父组件:Parent.vue
xxx对应的标签结构
yyy对应的标签结构
第三章 Vue-Ajax 3.1 Vue项目中常用的2个ajax库
3.1.1 Vue-Resource vue插件,非官方库,vue1.x使用广泛
3.1.2 axios 通用的Ajax请求库,官方推荐,vue2.x使用广泛
3.2 Vue-Resource的使用
3.2.1 在线文档 https://github.com/pagekit/vue-resource/blob/develop/docs/http.md
3.2.2 下载 npm install vue-resource --save
3.2.3 代码使用
// 引入模块
import VueResource from 'vue-resource'
// 使用插件
Vue.use(VueResource)// 通过vue组件对象发送ajax请求
this.$http.get('/someURL').then(response)=>{
//请求成功的数据
console.log(response.data)//返回结果数据
},(response)=>{
//错误信息
console.log(response.statusText)//错误信息
}
3.3 axios的使用
3.3.1 下载 npm install axios --save
3.3.2 代码实现
// 引入模块
import axios from 'axios'//发送Ajax请求
axios.get(url).then(response=>{
console.log(response.data)//得到返回结果数据
}).catch(error=>{
console.log(error.message)//错误信息
})
第四章 Vue UI组件库 4.1 常用的UI组件库
- Mint UI:
- 饿了么开源的基于vue的移动端UI组件库
- Elment UI:
- 饿了么开源的基于vue的PC端UI组件库
4.2.1 下载 npm install --save mint-ui
4.2.2 实现按需打包
// 下载
npm install --save-dev babel-plugin-component
// 修改babel配置
"plugins":["transform-runtime",["component",{
"libraryName":"mint-ui",
"style":true
}]]
4.2.3 mint-ui组件分类
- 标签组件
- 非标签组件
- index.html
src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js">
>
if('addEventListener' in document){
document.addEventListener('DOMContentLoaded',function(){
FastClick.attach(document.body);
},false);
}
if(!window.Promise){
document.writelv('="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js">')
}
- main.js
import {Button} from 'mint-ui'
Vue.component(Button.name,Button)
- App.vue
Test
>
import {Toast} from 'mint-ui'
export default{
methods:{
handleClick(){
Toast('点击了测试');
}
}
}
第五章 Vue-router 5.1 理解
5.1.1 说明
- 官方提供的用来实现SPA(单页)的vue插件
- github:https://github.com/vuejs/vue-router
- 中文文档:http://router.vuejs.org/zh-cn/
- 下载:npm install vue-router --save
- VueRouter():用于创建路由器的构建函数
new VueRouter({
//多个配置项
})
- 路由配置
routes:[
{//一般路由
path:'/about',
component:About
},
{//自动跳转路由
path:'/',
redirect:'/about'
}
]
- 注册路由器
import router from './router'
new Vue({
router
})
- 使用路由组件标签
1.:用来生成路由链接
Go To XXX
2.:用来显示当前路由组件界面
5.2 基本路由
5.2.1 路由组件 文件夹命名:pages/views
示例路由组件:Home.vue/About.vue
5.2.2 应用组件:App.vue
About
5.2.3 路由器模块:src/router/index.js
export default new VueRouter({
routes:[
{
path:'/',
redirect:'/about'
},
{
path:'/about',
component:About
},
{
path:'/home',
component:Home
}
]
})
5.2.4 注册路由器:main.js
import Vue from 'vue'
import router from './router'
// 创建vue配置路由器
new Vue({
el:'#app',
router,
render:h=>h(app)
})
5.2.5 优化路由器配置 linkActiveClass:‘active’; //指定选中的路由链接的class
5.2.6 总结:编写使用路由的3步
- 定义路由组件
- 注册路由
- 使用路由
Message.vue
5.3.2 配置嵌套路由:router.js
path:'/home',
component:hoem,
children:[
{
path:'/home/news',
component:News
},
{
path:'message',//简化写法
component:Message
}
]
5.3.4 路由链接:Home.vue
News
Message
5.4 缓存路由组件对象
5.4.1 理解
- 默认情况下,被切换的路由组件对象会死亡释放,再次回来时是重新创建的
- 如果可以缓存路由组件对象,可以提高用户体验
5.5 向路由组件传递数据
5.5.1 方式1:路由路径携带参数(param/query)
- 配置路由
children:[
{
path:'mdetail/:id',
component:MessageDetail
}
]
- 路由路径
{{m.title}}
- 路由组件中读取请求参数
this.$route.params.id
5.5.2 方式2:属性携带数据
5.6 编程式路由导航
相关API
- this.$router.push(path):相当于点击路由链接(可以返回当前路由界面)
- this.$router.replace(path):用新路由替换当前路由(不可以返回当前路由界面)
- this.$router.back():请求(返回)上一个记录路由
- this.$router.go(-1):请求(返回)上一个记录路由
- this.$router.go(1):请求下一个记录路由
pushShow (id) {
this.$router.push(`/home/message/detail/${id}`)
}
6.1 说明
- 分析vue作为一个MVVM框架的基本实现原理
- 数据代理
- 模板解析
- 数据绑定
- 不直接看vue.js的源码
- 剖析github上仿vue实现的MVVM库
- 地址:https://github.com/DMQ/mvvm
- [].slice.call(lis):将伪数组转换为真数组
- node.noteType:得到节点类型
- Object.defineProperty(obj,propName,{}):给对象添加/修改属性(指定描述符)
- configurable:true/false 是否可以重新define
- enumerable:true/false 是否可以枚举(for…in/keys())
- value:指定初始值
- writable:true/false value是否可以修改
- get:回调函数,用来得到当前属性值
- set:回调函数,用来监视当前属性值的变化
- Object.keys(obj):得到对象自身可枚举的属性名的数组
- DocumentFragment:文档碎片(高效批量更新多个节点)
- obj.hasOwnProperty(prop):判断prop是否是obj自身的属性
Title - 锐客网 MVVMd
- test1
- test2
- test3
type="text/javascript">
//1. [].slice.call(lis): 根据伪数组生成对应的真数组
const lis = document.getElementsByTagName('li') // lis是伪数组(是一个特别的对象, length和数值下标属性)
console.log(lis instanceof Object, lis instanceof Array)
// 数组的slice()截取数组中指定部分的元素, 生成一个新的数组[1, 3, 5, 7, 9], slice(0, 3)
// slice2()
Array.prototype.slice2 = function (start, end) {
start = start || 0
end = start || this.length
const arr = []
for (var i = start;
i < end;
i++) {
arr.push(this[i])
}
return arr
}
const lis2 = Array.prototype.slice.call(lis)// lis.slice()
console.log(lis2 instanceof Object, lis2 instanceof Array)
// lis2.forEach()//2. node.nodeType: 得到节点类型
const elementNode = document.getElementById('test')
const attrNode = elementNode.getAttributeNode('id')
const textNode = elementNode.firstChild
console.log(elementNode.nodeType, attrNode.nodeType, textNode.nodeType)//3. Object.defineProperty(obj, propertyName, {}): 给对象添加属性(指定描述符)
const obj = {
firstName: 'A',
lastName: 'B'
}
//obj.fullName = 'A-B'
Object.defineProperty(obj, 'fullName', {
// 属性描述符:// 数据描述符//访问描述符
// 当读取对象此属性值时自动调用, 将函数返回的值作为属性值, this为obj
get () {
return this.firstName + "-" + this.lastName
},
// 当修改了对象的当前属性值时自动调用, 监视当前属性值的变化, 修改相关的属性, this为obj
set (value) {
const names = value.split('-')
this.firstName = names[0]
this.lastName = names[1]
}
})console.log(obj.fullName) // A-B
obj.fullName = 'C-D'
console.log(obj.firstName, obj.lastName) // C DObject.defineProperty(obj, 'fullName2', {
configurable: false, //是否可以重新define
enumerable: true, // 是否可以枚举(for..in / keys())
value: 'A-B', // 指定初始值
writable: false // value是否可以修改
})
console.log(obj.fullName2)// A-B
obj.fullName2 = 'E-F'
console.log(obj.fullName2) // A-B
/*Object.defineProperty(obj, 'fullName2', {
configurable: true,
enumerable: true,
value: 'G-H',
writable: true
})*///4. Object.keys(obj): 得到对象自身可枚举属性组成的数组
const names = Object.keys(obj)
console.log(names)
//5. obj.hasOwnProperty(prop): 判断prop是否是obj自身的属性
console.log(obj.hasOwnProperty('fullName'), obj.hasOwnProperty('toString'))// true false//6. DocumentFragment: 文档碎片(高效批量更新多个节点)
// document: 对应显示的页面, 包含n个elment一旦更新document内部的某个元素界面更新
// documentFragment: 内存中保存n个element的容器对象(不与界面关联), 如果更新framgnet中的某个element, 界面不变
/*
- test1
- test2
- test3
*/
const ul = document.getElementById('fragment_test')
// 1. 创建fragment
const fragment = document.createDocumentFragment()
// 2. 取出ul中所有子节点取出保存到fragment
let child
while(child=ul.firstChild) { // 一个节点只能有一个父亲
fragment.appendChild(child)// 先将child从ul中移除, 添加为fragment子节点
}// 3. 更新fragment中所有li的文本
Array.prototype.slice.call(fragment.childNodes).forEach(node => {
if (node.nodeType===1) { // 元素节点
node.textContent = 'atguigu'
}
})// 4. 将fragment插入ul
ul.appendChild(fragment)
6.3 数据代理
- 数据代理:通过一个对象代理对另一个对象(在前一个对象内部)中属性的操作(读/写)
- vue数据代理:通过vm对象来代理data对象中所有属性的操作
- 好处:更方便的操作data中的数据
- 基本实现流程
- 通过Object.defineProperty()给vm添加与data对象的属性对应的属性描述符
- 所有添加的属性都包含getter/setter
- getter/setter内部去操作dta中对应的属性数据
数据代理 - 锐客网 type="text/javascript" src="https://www.it610.com/article/js/mvvm/compile.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/mvvm.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/observer.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/watcher.js">
type="text/javascript">
const vm = new MVVM({
el: "#test",
data: {
name: '张三2'
}
})
console.log(vm.name)// 读取的是data中的name,vm代理对data的读操作
vm.name = '李四2' // 数据保存到data中的name上, vm代理对data的写操作
console.log(vm.name, vm._data.name)
6.4 模板解析
6.4.1 模板解析的基本流程
- 将el的所有子节点取出,添加到一个新建的文档fragment对象中
- 对fragment中的所有层次子节点递归进行编译解析处理
- 对大括号表达式文本节点进行解析
- 对元素节点的指令属性进行解析
- 事件指令解析
- 一般指令解析
- 将解析后的fragment添加到el中显示
- 根据正则对象得到匹配出的表达式字符串:子匹配/RegExp.$1 name
- 从data中取出表达式对应的属性值
- 将属性值设置为文本节点的textContent
模板解析_表达式_vue - 锐客网
{{name}}
type="text/javascript" src="https://www.it610.com/article/js/mvvm/compile.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/mvvm.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/observer.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/watcher.js">
type="text/javascript">
new MVVM({
el: '#test',
data: {
name: 'SADAMU'
}
})
6.4.3 模板解析2:事件指令解析
- 从指令名中取出事件名
- 根据指令的值(表达式)从methods中得到对应的事件处理函数对象
- 给当前元素节点绑定指定事件名和回调函数的dom事件监听
- 指令解析完后,移除此指令属性
模板解析_事件指令 - 锐客网
type="text/javascript" src="https://www.it610.com/article/js/mvvm/compile.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/mvvm.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/observer.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/watcher.js">
type="text/javascript">
new MVVM({
el: '#test',
data: {
msg: 'hello atguigu'
},
methods: {
test () {
alert(this.msg)
}
}
})
6.4.4 模板解析3:一般指令解析
- 得到指令名和指令值(表达式) text/html/class msg/myClass
- 从data中根据表达式得到对应的值
- 根据指令名确定需要操作元素节点的什么属性
- v-text—textContent属性
- v-html—innerHTML属性
- v-class—className属性
- 将得到的表达式的值设置到对应的属性上
- 移除元素的指令属性
模板解析_一般指令 - 锐客网
>
.aclass {
color: red;
}
.bClass {
font-size: 30px;
}
xxxxxx
type="text/javascript" src="https://www.it610.com/article/js/mvvm/compile.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/mvvm.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/observer.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/watcher.js">
type="text/javascript">
new MVVM({
el: '#test',
data: {
msg: '尚硅谷',
myClass: 'aclass'
},
methods: {
test () {
alert(this.msg)
}
}
})
6.5 数据绑定
6.5.1 数据绑定 一旦更新了data中的某个属性数据,所有界面上直接使用或间接使用此属性的节点更新
6.5.2 数据劫持
- 数据劫持是vue中用来实现数据绑定的一种技术
- 基本思想:通过defineProperty()来监视data中所有属性(任意层次)数据的变化,有变化就去更新界面
- Observer
- 用来对data所有属性数据进行劫持的构造函数
- 给data中所有属性重新定义属性描述(get/set)
- 为data中的每个属性创建对应的dep对象
- Dep(Depend)
- data中的每个属性(所有层次)都对应一个dep对象
- 创建的时机
- 在初始化define data中各个属性时创建对应的dep对象
- 在data中的某个属性值被设置为新的对象时
- 【学习笔记|Vue的基础入门及使用】对象的结构
{ id,//每个dep都有一个唯一的id subs//包含n个对应watcher的数组(subscribes的简写) }
- subs属性说明
- 当watcher被创建时,内部将当前watcher对象添加到对应的dep对象的subs中
- 当此data属性的值发生改变时,subs中所有的watcher都会受到更新的通知,从而最终更新对应的界面
- data中的每个属性(所有层次)都对应一个dep对象
- Compiler
- 用来解析模板页面的对象的构造函数(一个实例)
- 利用compile对象解析模板页面
- 每解析一个表达式(非事件指令)都会创建一个对应的watcher对象,并建立watcher与dep的关系
- complie与watcher的关系:一对多的关系
- Watcher
- 模板中每个非事件指令或表达式都对应一个watcher对象
- 监视当前表达式数据的变化
- 创建的时机:在初始化编译模板时
- 对象的组成
{ vm,//vm对象 exp,//对应指令的表达式 cb,//当表达式所对应的数据发生改变的回调函数 value,//表达式当前的值 depIds//表达式中各级属性所对应的dep对象的集合对象 //属性名为dep的id,属性值为dep }
- 模板中每个非事件指令或表达式都对应一个watcher对象
- 总结:dep与watcher的关系:多对多
- data中的一个属性对应一个dep,一个dep中可能包含多个watcher(模板中有几个表达式使用到了同一个属性)
- 模板中一个非事件表达式对应一个watcher,一个watcher中可能包含多个dep(表达式是多层的:a.b)
- 数据绑定使用到2个核心技术
- defineProperty()
- 消息订阅与发布
数据劫持-数据绑定 - 锐客网
{{name}}
type="text/javascript" src="https://www.it610.com/article/js/mvvm/compile.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/mvvm.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/observer.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/watcher.js">
type="text/javascript">
new MVVM({
el: '#test',
data: {
name: 'sadamu',// dep0
wife: { // dep1
name: 'binbin', // dep2
age: 18 // dep3
}
},
methods: {
update () {
this.name = 'avatar'
}
}
})
6.6 MVVM原理分析
文章图片
6.7 双向数据绑定
- 双向数据绑定是建立在单向数据绑定(model=>View)的基础之上的
- 双向数据绑定的实现流程
- 在解析v-model指令时,给当前元素添加input监听
- 当input的value发生改变时,将最新的值赋值给当前表达式所对应的data属性
数据双向绑定 - 锐客网
{{msg}}
type="text/javascript" src="https://www.it610.com/article/js/mvvm/compile.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/mvvm.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/observer.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/watcher.js">
type="text/javascript">
new MVVM({
el: '#test',
data: {
msg: 'haha'
}
})
第七章 Vuex 7.1 Vuex理解
7.1.1 vuex是什么
- github站点:https://github.com/vuejs/vuex
- 在线文档:https://vuex.vuejs.org/zh-cn/
- 简单来说,对vue应用中多个组件的共享状态进行集中式的管理(读/写)
- state:驱动应用的程序源
- view:以声明方式将state映射到视图
- actions:响应在view上的用户输入导致的状态变化(包含n个更新状态的方法)
文章图片
- 多个视图依赖于同一状态
- 来自不同视图的行为需要变更同一状态
- 以前的解决办法
- 将数据以及操作数据的行为都定义在父组件
- 将数据以及操作数据的行为传递给需要的各个子组件(有可能需要多级传递)
- vuex就是用来解决这个问题的
7.2.1 state
- vuex管理的状态对象
- 它应该是唯一的
const state={ xxx:initValue }
- 包含多个直接更新state的方法(回调函数)的对象
- 谁来触发:action中的commit(‘mutation名称’)
- 只能包含同步的代码,不能写异步代码
const mutations={ yyy(state,{data1}){ //更新state的某个属性 } }
- 包含多个事件回调函数的对象
- 通过执行:commit()来触发mutation的调用,间接更新state
- 谁来触发:组件中:$store.dispatch(‘action名称’,data1) //‘zzz’
- 可以包含异步代码(定时器,ajax)
const actions={ zzz({commit,state},data1){ commit('yyy',{data1}) } }
- 包含多个计算属性(get)的对象
- 谁来读取:组件中:$store.getters.xxx
const getters={ mmm(state){ return ... } }
- 包含多个module
- 一个module是一个store的配置对象
- 与一个组件(包含有共享数据)对应
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
7.2.7 组件中
import {mapState,mapGetters,mapActions} from 'vuex'
export default{
computed:{
...mapState(['xxx']),
...mapGetters(['mmm']),
},
methods:mapActions(['zzz'])
}{{xxx}}{{mmm}}@click="zzz(data)"
7.2.8 映射store
import store from './store'
new Vue({
store
})
7.2.9 store对象
- 所有用vuex管理的组件中都躲了一个属性store,它就是一个store对象
- 属性:
- state:注册的state对象
- getters:注册的getters对象
- 方法:
定是建立在单向数据绑定(model=>View)的基础之上的 - 双向数据绑定的实现流程
- 在解析v-model指令时,给当前元素添加input监听
- 当input的value发生改变时,将最新的值赋值给当前表达式所对应的data属性
数据双向绑定 - 锐客网
{{msg}}
type="text/javascript" src="https://www.it610.com/article/js/mvvm/compile.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/mvvm.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/observer.js">
type="text/javascript" src="https://www.it610.com/article/js/mvvm/watcher.js">
type="text/javascript">
new MVVM({
el: '#test',
data: {
msg: 'haha'
}
})
第七章 Vuex 7.1 Vuex理解
7.1.1 vuex是什么
- github站点:https://github.com/vuejs/vuex
- 在线文档:https://vuex.vuejs.org/zh-cn/
- 简单来说,对vue应用中多个组件的共享状态进行集中式的管理(读/写)
- state:驱动应用的程序源
- view:以声明方式将state映射到视图
- actions:响应在view上的用户输入导致的状态变化(包含n个更新状态的方法)
7.1.3 多组件共享状态的问题
- 多个视图依赖于同一状态
- 来自不同视图的行为需要变更同一状态
- 以前的解决办法
- 将数据以及操作数据的行为都定义在父组件
- 将数据以及操作数据的行为传递给需要的各个子组件(有可能需要多级传递)
- vuex就是用来解决这个问题的
7.2.1 state
- vuex管理的状态对象
- 它应该是唯一的
const state={ xxx:initValue }
- 包含多个直接更新state的方法(回调函数)的对象
- 谁来触发:action中的commit(‘mutation名称’)
- 只能包含同步的代码,不能写异步代码
const mutations={ yyy(state,{data1}){ //更新state的某个属性 } }
- 包含多个事件回调函数的对象
- 通过执行:commit()来触发mutation的调用,间接更新state
- 谁来触发:组件中:$store.dispatch(‘action名称’,data1) //‘zzz’
- 可以包含异步代码(定时器,ajax)
const actions={ zzz({commit,state},data1){ commit('yyy',{data1}) } }
- 包含多个计算属性(get)的对象
- 谁来读取:组件中:$store.getters.xxx
const getters={ mmm(state){ return ... } }
- 包含多个module
- 一个module是一个store的配置对象
- 与一个组件(包含有共享数据)对应
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
7.2.7 组件中
import {mapState,mapGetters,mapActions} from 'vuex'
export default{
computed:{
...mapState(['xxx']),
...mapGetters(['mmm']),
},
methods:mapActions(['zzz'])
}{{xxx}}{{mmm}}@click="zzz(data)"
7.2.8 映射store
import store from './store'
new Vue({
store
})
7.2.9 store对象
- 所有用vuex管理的组件中都躲了一个属性store,它就是一个store对象
- 属性:
- state:注册的state对象
- getters:注册的getters对象
- 方法:
- dispatch(actionName,data):分发调用action
推荐阅读
- EffectiveObjective-C2.0|EffectiveObjective-C2.0 笔记 - 第二部分
- 由浅入深理解AOP
- vue-cli|vue-cli 3.x vue.config.js 配置
- 2020-04-07vue中Axios的封装和API接口的管理
- 继续努力,自主学习家庭Day135(20181015)
- python学习之|python学习之 实现QQ自动发送消息
- Android中的AES加密-下
- 一起来学习C语言的字符串转换函数
- 定制一套英文学习方案
- 漫画初学者如何学习漫画背景的透视画法(这篇教程请收藏好了!)