Vue全家桶(一):Vue基础+Vue-Cli+Vue组件化+过渡动画
目录
- 1.Vue概述
- 1.1 认识Vue
- 1.2 Vue的两核心
- 1.3 Vue的初体验
- 1.4 Vue的生命周期
- 2. Vue-CLI (Command Line Interface)
- 3. Vue基本使用
- 3.1 传统开发模式对比
- 3.2 Vue.js引入
- 3.3 Vue.js 案例分析
- 3.3.1 实例参数el、data、methods的写法
- 4. Vue模板语法
- 4.1 插值语法 {{xxx}}
- 4.2 指令语法
- 4.2.1 v-text、v-html、v-pre
- 4.2.2 v-cloak 指令
- 4.2.3 自定义指令
- 4.3 属性绑定 v-bind
- 4.3.1 绑定class属性
- 4.3.2 绑定style属性
- 4.4 计算属性
- 4.4.1 methods VS computed
- 4.4.2 监听属性watch及computed VS watch
- 4.4.3 computed与watch、methods的区别
- 4.3 事件监听 v-on
- 4.3.1 v-on事件修饰符号
- 4.3.2 v-on按键修饰符号
- 4.3.3 获取事件对象
- 4.4 条件渲染 v-if、v-show
- 4.5 列表渲染 v-for
- 4.5.1 基本用法
- 4.5.2 虚拟DOM、Diff算法、Key选用
- 4.5.3 列表过滤与排序
- 4.5.4 Vue数据监视
- 4.6 数据绑定 v-model
- 4.7 过滤器filter(Vue3已经移除)
- 4.8 模板语法应用——简易购物车
- 5. 组件基础
- 5.1 模块与组件、模块化与组件化
- 5.2 非单文件组件
- 5.2.1 组件基本使用
- 5.2.2 组件的嵌套
- 5.2.3 VueComponent构造函数
- 5.2.4 一个重要的内置关系
- 5.3 单文件组件
- 5.3.1 组件基本实例
- 5.3.2 组件间的通信
- 5.3.2.1 父组件传递子组件 props
- 5.3.2.2 子组件给传递父组件数据 $emit
- 5.3.3 父子组件之间的访问方法
- 5.3.3.1 子组件调用父组件的方法 $parent
- 5.3.3.2 父组件调用子组件的方法 $refs
- 5.3.4 全局事件总线(任意组件间的通信)
- 5.3.5 消息订阅与发布(任意组件通信)
- 5.4 组件插槽 slot
- 5.4.1 默认插槽
- 5.4.2 后备内容
- 5.4.3 具名插槽
- 5.4.4 作用域插槽
- 5.5 `mixin` 混入
- 5.6 plugin 插件
- 5.7 scoped 样式
- 5.8 nextTick
- 6. TodoList案例
- 6.1 目标功能界面
- 6.2 界面模块拆分
- 6.3 浏览器本地存储
- 7. 过渡和动画
1.Vue概述
1.1 认识Vue
Vue是一套用于构建用户界面的渐进式框架。
渐进式就跟这个图片一样,开发可以根据需求,逐渐递增所要的方式,但每个方式有不是依靠行特别强
Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
库是一个模块,而Vue是一套架构,会基于自身特点向用户提供一套相当完整的解决方案,而且控制权在框架本身;对项目的侵入性较大,使用者要按照框架所规定的某种特定规范进行开发,项目如果需要更换框架,则需要重新架构整个项目。
1.2 Vue的两核心
响应式的数据绑定:当数据发生改变,视图可以自动更新,可以不用关心dom操作,而专心数据操作
可组合的视图组件:把视图按照功能切分成若干基本单元,组件可以一级一级组合整个应用形成倒置组件树,可维护,可重用,可测试
1.3 Vue的初体验
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="./js/vue.global.js"></script><style>.box {width: 200px;height: 200px;background-color: darksalmon;display: none;}div.show {display: block;}</style>
</head>
<body><div id="app">{{message}}<h2 @click="isShow()">{{title}}</h2><div class="box" :class="{show}" style="color: #333; background-color: antiquewhite" :style="{width:'200px', height:h}"><ul><li v-for="item in articles.slice(0,5)" :title="item.content"><p>{{item.title}}</p><span>{{item.content}}</span></li></ul></div></div></body>
<script>//Vue2var vm = new Vue({el: '#app',data: {num: 0,},methods: {……},});//Vue3const app = Vue.createApp({data() {return {h: '500px',message: 'this is a test',title: 'Vue demo',show: true,articles: [{title:'Google',content:'Vue 的核心库只关注视图层'},{title:'souhu',content:'Vue 的核心库只关注视图层'},{title:'Google',content:'Vue 的核心库只关注视图层'},{title:'Google',content:'Vue 的核心库只关注视图层'},{title:'Google',content:'Vue 的核心库只关注视图层'},{title:'Google',content:'Vue 第三方库或既有项目整合'},{title:'xifang',content:'第三方库或既有项目整合'},{title:'baidu',content:'第三方库或既有项目整合'},{title:'baidu',content:'第三方库或既有项目整合'},{title:'baidu',content:'第三方库或既有项目整合'}]}},methods: {isShow() {this.show = !this.show;}}}).mount("#app")</script>
</html>
效果
1.4 Vue的生命周期
生命周期
:事物从诞生到消亡的整个过程
vue生命周期
:Vue 实例从创建到销毁的过程,vue生命周期钩子
:在达到某一阶段时去触发的函数
生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的,生命周期函数中的this
指向是vm
或 组件实例对象。
它可以总共分为8个阶段:
创建前/后, 挂载前/后,更新前/后,销毁前/销毁后
create
阶段:vue实例被创建
mount
阶段: vue实例被挂载到真实DOM节点
update
阶段:当vue实例里面的data数据变化时,触发组件重新渲染
destroy
阶段:vue实例被销毁
beforeCreate(创建前)
表示实例完全被创建出来之前,vue 实例的挂载元素$el和数据对象 data 都为 undefined,还未初始化。created(创建后)
数据对象 data 已存在,可以调用 methods 中的方法,操作 data 中的数据,但 DOM 未生成,$el
未存在 。beforeMount(挂载前)
vue 实例的$el
和data
都已初始化,挂载之前为虚拟的 DOM节点,模板已经在内存中编辑完成了,但是尚未把模板渲染到页面中。data.message
未替换。mounted(挂载后)
vue 实例挂载完成,data.message
成功渲染。内存中的模板,已经真实的挂载到了页面中,用户已经可以看到渲染好的页面了。实例创建期间的最后一个生命周期函数,当执行完 mounted 就表示,实例已经被完全创建好了,DOM 渲染在 mounted 中就已经完成了。beforeUpdate(更新前)
当 data 变化时,会触发beforeUpdate方法 。data 数据尚未和最新的数据保持同步。updated(更新后)
当 data 变化时,会触发 updated 方法。页面和 data 数据已经保持同步了。beforeDestory(销毁前)
组件销毁之前调用 ,在这一步,实例仍然完全可用。destoryed(销毁后)
组件销毁之后调用,对 data 的改变不会再触发周期函数,vue 实例已解除事件监听和 dom绑定,但 dom 结构依然存在。
常用的生命周期方法:
mounted()
:初始化操作,发送ajax请求, 启动定时器、绑定自定义事件、订阅消息等异步任务
beforeDestroy()
: 做收尾工作, 清除定时器、解绑自定义事件、取消订阅消息等
关于销毁Vue实例:
销毁后借助Vue开发者工具看不到任何信息
销毁后自定义事件会失效,但原生DOM事件依然有效
一般不会在beforeDestroy操作数据,因为即使操作数据,也不会再触发更新流程了。
Vue生命周期流程图
vue生命周期在真实场景下的业务应用:
- created:vue实例被创建
- mounted: 挂载元素,获取dom节点
- nextTick: 针对单一事件更新数据后立即操作dom
- updated: 任何数据的更新,做统一的业务逻辑处理
- watch: 监听具体数据变化,并做相应的处理
2. Vue-CLI (Command Line Interface)
Vue-CLI 是Vue官方提供的脚手架工具
Vue脚手架指的是vue-cli,它是一个专门为单页面应用快速搭建繁杂的脚手架,它可以轻松的创建新的应用程序而且可用于自动生成vue和webpack的项目模板。
利用vue-cli脚手架来构建Vue项目需要先安装Node.js和NPM环境。
- 开发环境:WebStorm
- 命令安装:npm install -g @vue/cli (安装最新版本vue-cli)
- 检查版本:vue --version
- 创建项目:vue create 项目名称
- 选择Vue3,默认安装插件
- 运行项目: npm run serve
目录结构
常见项目的目录结构,如下所示:
.
|-- build // 项目构建(webpack)相关代码
| |-- build.js // 生产环境构建代码
| |-- check-version.js // 检查node、npm等版本
| |-- dev-client.js // 热重载相关
| |-- dev-server.js // 构建本地服务器
| |-- utils.js // 构建工具相关
| |-- webpack.base.conf.js // webpack基础配置
| |-- webpack.dev.conf.js // webpack开发环境配置
| |-- webpack.prod.conf.js // webpack生产环境配置
|-- config // 项目开发环境配置
| |-- dev.env.js // 开发环境变量
| |-- index.js // 项目一些配置变量
| |-- prod.env.js // 生产环境变量
| |-- test.env.js // 测试环境变量
|-- node_modules //所需要依赖资源
|-- src // 源码目录
| |-- assets //存放资产文件,如静态资源
| |-- components // vue公共组件
| |-- router //存放路由js文件,用于页面的跳转
| |-- App.vue // 页面入口文件
| |-- main.js // 程序入口文件,加载各种公共组件
|-- static // 静态文件,比如一些图片,json数据等
| |-- data // 群聊分析得到的数据用于数据可视化
|-- .babel.config.js // bale的配值文件
|-- .editorconfig // 定义代码格式
|-- .gitignore // git上传需要忽略的文件格式
|-- README.md // 项目说明
|-- favicon.ico
|-- index.html // 入口页面
|-- package.json // 项目基本信息
|-- package-lock.json //包版本控制文件
|-- vue.config.js // vue可选的配值文件
.
文件名 | 说明 |
---|---|
dist |
存放使用npm run build 打包的项目文件
|
node_modules | 存放项目的依赖包 |
public | 存放静态文件。里面包含了几个文件: index.html是一个模板文件,webpack进行打包时会原封不动打包到dist文件夹中 |
src | 这里是我们要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件:assets: 放置一些资源文件,比如图片、字体等资源,webpack打包会把静态资源当作一个模块,打包到JS文件中。components: 目录里面放了一个组件文件,可以不用。App.vue: 项目入口文件,我们也可以直接将组件写这里,而不使用 components 目录。main.js: 项目的核心文件(入口文件)。 |
package.json | 模块基本信息项目开发所需要模块,版本,项目名称 |
package-lock.json | 是在 npm install时候生成一份文件,用以记录当前状态下实际安装的各个npm package的具体来源和版本号 |
babel.config.js | 是一个工具链,主要用于在当前和较旧的浏览器或环境中将ECMAScript 2015+代码转换为JavaScript的向后兼容版本 |
gitignore | git上传需要忽略的文件格式 |
vue.config.js | 保存vue配置的文件,可以用于设置代理,打包配置等 |
README.md | 项目说明 |
输入npm run dev命令来启动项目
运行成功后在浏览器输入:http://localhost:8080
设置Eslint的语法检查
3. Vue基本使用
3.1 传统开发模式对比
//原生JS<div id="msg"></div><script type="text/javascript">var msg = 'Hello World'var div = document.querySelector('#msg');div.innerHTML = msg</script>
<div id="msg"></div><script type="text/javascript" src="js/jquery.js"></script><script type="text/javascript">var msg = 'Hello World';$('#msg').html(msg);</script>
3.2 Vue.js引入
//script 引入
<script src="js/vue.js"></script>//CDN 引入
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>//生产版本
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
3.3 Vue.js 案例分析
Vue的基本使用步骤:
- 提供标签用于填充数据
- 引入Vue.js库文件
- 创建Vue实例
- 并配置对象
- 把vue提供的数据填充到标签里面
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><title></title></head><body><div id="app"><!-- 插值表达式{{}} --><div>{{num}}</div><!-- 事件绑定v-on --><div><button v-on:click="handle">点击</button></div></div><!-- //引入vue --><script type="text/javascript" src="js/vue.js"></script><script type="text/javascript">//创建vue实例 vm (ViewModel) var vm = new Vue({el: '#app',data: {num: 0,},methods: {// ES6 的对象字面量方法简写允许我们省略对象方法之后的冒号及function关键字// handle:function(){// this.num++;// }handle() {this.num++;},},});</script></body>
</html>
3.3.1 实例参数el、data、methods的写法
el
:指定当前Vue实例为哪个标签服务(值可以是CSS选择器或者DOM元素),el有2种写法:
(1) new Vue时候配置el属性。
const vm = new Vue({el:'#root', //第一种写法data:{msg:' '}
})
- 先创建Vue实例,随后再通过
vm.$mount(’#root’)
指定el的值。
除了数据 property,Vue 实例还暴露了一些有用的实例 property 与方法。它们都有前缀 $,以便与用户定义的 property 区分开来
const vm = new Vue({data:{msg:' '}
})
vm.$mount('#root') //第二种写法 */
data
用于存储数据(值是一个对象或函数),数据供el
所指定的标签使用,data有2种写法:
(1) 对象式
data:{msg:' '
}
(2) 函数式
data(){return{msg:' '}
}
如何选择:目前data的哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。
methods
: 该属性用于在Vue对象中定义方法。
- 事件的回调需要配置在methods对象中,最终会在vm上;
- methods中配置的函数,不要用箭头函数!否则this就不是vm
- methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象;
4. Vue模板语法
Vue模板语法包括两大类:
4.1 插值语法 {{xxx}}
功能:用于解析标签体内容
双大括号表达式{{xxx}}
xxx 是js 表达式,可以直接读取到 data 中的所有区域,也可以调用对象的方法和计算属性
{{ number + 1 }}
{{ ok ? ‘YES’ : ‘NO’ }}
{{message.split(‘’).reverse().join(‘’)}}
4.2 指令语法
功能:用于解析标签(包括:标签熟悉、标签体内容、绑定事件…)
指令(以v-xxx
开头的自定义标签属性)【很多】
4.2.1 v-text、v-html、v-pre
(在{{}}和v-指令进行数据绑定时,支持js单个表达式)
v-once
<p v-once>{{msg}}</p>
数据执行一次性插值,数据改变时,插值处内容不更新,不响应
v-once
的应用场景:以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。v-pre
<p v-pre>{{msg}}</p>
,内容原封不动的展示,跳过其所在节点的编译过程。v-text
<p v-text='msg'></p>
,向其所在的节点中渲染文本内容。
v-text
与插值语法的区别:v-text
会替换掉节点中的内容,{{xx}}
则不会。v-html
<p v-html='title'></p>
,可以输出html代码
v-html
与插值语法的区别:
(1).v-html
会替换掉节点中所有的内容,{{xxx}}
则不会。
(2).v-html
可以识别html结构。
严重注意:v-html
有安全性问题!!!!
(1). 在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2). 一定要在可信的内容上使用v-html
,永不要用在用户提交的内容上!
data:{msg:'test message',title:`<h1 style='color:red'>Title</h1>`
}
<div id="app"><div>{{msg}}</div><div v-text='msg'></div><div v-html='msg1'></div><div v-pre>{{msg}}</div></div>
var vm = new Vue({el: '#app',data: {msg: 'Hello Vue',msg1: '<h1>HTML</h1>'}});
4.2.2 v-cloak 指令
v-cloak
应用场景:解决插值表达式存在的问题——“闪烁”
渲染普通文本有2种方式:{{}}
与v-text
<div id="app">{{msg}}</div>
<div id="app" v-text="msg"></div>
new Vue({el: '#app',data: {msg: '欢迎Vue!'}})
“闪动”的意思:
在使用{{}}
展示或更新页面数据时:当网速比较慢时,会出现一个不好的过度现象,会让用户先看到我们的表达式(上面页面中的{{msg}}
),然后才看到data中的值(欢迎Vue!)------->即所谓的闪烁问题!
如何解决该问题:
使用v-cloak
指令,不让未经解析的html模板显示在页面
使用v-cloak
指令,然后为其设置css样式display:none;
即上述代码可修改为:
ref : 为某个元素注册一个唯一标识, vue对象通过$refs属性访问这个元素对
v-cloak
指令的用法:
- 提供样式
[v-cloak]{display: none;
}
- 在插值表达式所在的标签中添加v-cloak指令
<div id="app" v-cloak>{{msg}}</div>
原理: 先通过样式隐藏内容,然后在内存中进行值的替换,替换好之后再显示最终的结果。
v-cloak
指令本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak
属性
说明: 但有时添加完毕后变量仍会显示(即闪烁问题没解决),这是怎么回事呢?原来是 v-cloak
的display属性被优先级别高的样式覆盖所导致,所以最好再添加一个 !important ,将其优先级设置为最高,防止被其他优先级高的dispaly:none样式所覆盖。
[v-cloak]{display: none !important;
}
4.2.3 自定义指令
自定义指令:内置指令不满足需求,需要自己定义指令使用
需求1:定义一个v-big
指令,和v-text
功能类似,但会把绑定的数值放大10倍。
需求2:定义一个v-fbind
指令,和v-bind
功能类似,但可以让其所绑定的input元素默认获取焦点。
一、定义语法
- 局部指令
//写法一:
new Vue({ directives:{指令名:回调函数}
})
//写法二:
new Vue({directives{指令名:配置对象}
})
实例1
<div id="root"><h2>当前的n值是: <span v-text = 'n'></span></h2><h2>放大10倍后的n值是:<span v-big='n'></span></h2><button @click="n++">n+1</button><input type="text" v-fbind:value = 'n'>
</div>
const vm = new Vue({el: '#root',data: {n: 12},directives: {//写法一:回调函数写法//el,指令所绑定的元素(真实DOM). binding,一个对象,包含以下属性:name:指令名,不包括 v- 前缀。value:指令的绑定值 arg:传给指令的参数,big(el, binding) {console.log(el, binding,this) //注意,此处的this是windowel.innerText = binding.value * 10;},fbind(el, binding){onsole.log(el, binding)el.value = binding.valueel.focus() //不能获取焦点},//写法二:配置对象写法 在不使用inserted钩子函数时可以使用方法一简写big: {//指令与元素成功绑定时(一上来)bind(el, binding) {el.innerText = binding.value * 10;},//指令所在元素被插入页面时inserted(el, binding) {},//指令所在的模板被重新解析时update(el, binding) {el.innerText = binding.value * 10;},},fbind: {bind(el, binding) {el.value = binding.valueconsole.log('bind')},inserted(el, binding){el.focus() //有效console.log('inserted')},update(el, binding) {el.value = binding.valueconsole.log('update')}},},},
})
效果
big函数何时会被调用?
1.指令与元素成功绑定时
2.指令所在的模板被重新解析时
- 全局指令
//方法一
Vue.directive(指令名,配置对象)
//方法二
Vue.directive(指令名,回调函数)
Vue.directive('big',function(el, binding){console.log(el, binding,this) //注意,此处的this是windowel.innerText = binding.value * 10;
})
Vue.directive('fbind',{//指令与元素成功绑定时(一上来)bind(el, binding) {el.value = binding.valueconsole.log('bind')},//指令所在元素被插入页面时inserted(el, binding){el.focus()console.log('inserted')},//指令所在的模板被重新解析时update(el, binding) {el.value = binding.valueconsole.log('update')}})
- 钩子函数
a. 自定义指令也像组件那样存在钩子函数。
- bind: 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
- inserted: 被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)
- update: 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
- componentupdated: 指令所在组件的 VNode 及其子VNode 全部更新后调用
- unbind: 只调用一次,指令与元素解绑时调用
b. 所有的钩子函数的参数都有以下
- el: 指令所绑定的元素,可以用来直接操作 DOM
- binding:一个对象,包含以下 property:
- name: 指令名,不包括 v- 前缀
- value: 指令的绑定值,例如:
v-my-directive="1 + 1”
中,绑定值为 2。 - oldvalue: 指令绑定的前一个值,仅在 update 和componentupdated 钩子中可用。无论值是否改变都可用。
- expression: 字符串形式的指令表达式。例如 v-0my-directive=“1 + 1”中,表达式为“1 + 1”。
- arg: 传给指令的参数,可选。例如 v-my-directive:foo 中,参数为“foo”
- modifiers:一个包含修饰符的对象。例如: v-my-directive.foo.bar 中,修饰符对象为
{ foo:true, bar: true }
- vnode: Vue 编译生成的虚拟节点。
- oldVnode: 上一个虚拟节点,仅在 update 和componentUpdated 子中可用
<div v-demo="{ color: "white',text: "hello!' }">div>
<script>Vue.directive('demo', function (el, binding) {console.log(binding.value.color) // whiteconsole.log(binding.value.text) // "hello!"
</script>
- 应用场景
使用自定义组件组件可以满足我们日常一些场景,这里给出几个自定义组件的案例:
- 防抖
- 图片懒加载
- 一键 Copy的功能
输入框防抖防抖这种情况设置一个v-debounce
自定义指令来实现
关于自定义组件还有很多应用场景,如: 拖拽指令、页面水印、权限校验等等应用场景
二、配值对象中常用的3个回调
- bind:指令与元素成功绑定时调用
- inserted:指令所在元素被插入页面时调用
- update:指令所在模板结构被重新解析时调用
三、备注:
指令定义时不加v-,但使用时要加v-;
指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。写法如下:
<span v-big-number='n'></span>
directives:{'big-number'(el, binding){……}}
4.3 属性绑定 v-bind
插值{{}}
只能用在模板内容中,用于动态内容绑定
如果希望元素的属性也可以动态绑定,需要通过v-bind
指令
<!-- 完整语法 -->
<a v-bind:href="url"> ... </a><!-- 缩写 -->
<a :href="url"> ... </a><!-- 动态参数的缩写 -->
<a :[key]="url"> ... </a>
- 绑定有意义元素中的属性
<template>
<h2 title="this is a test">{{msg}}</h2><h2 v-bind:title="msg">{{msg}}</h2>
<!--等价于 -->
<h2 :title="info">{{info}}</h2><img :src="imgsrc" width="100" height="100" alt="">
<a :href="url">百度</a>
</template><script>
const data = {msg: 'this is a test',info: 'new info',imgsrc: 'https://v3.vuejs.org/logo.png',title: '<h1 style="color: red">Title</h1>',url: 'http://www.baidu.com'
}
export default {name: 'App',data() {return data}
}
</script>
4.3.1 绑定class属性
class 样式有四种用法(字符串,数组,对象,方法)
- 字符串写法适用于:类名不确定,要动态获取
- 数组写法适用于:要绑定多个样式,个数不确定,名字也不确定
- 对象写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用
<template>
<!-- 数组方法 -->
<div :class="[one,two]">box4</div>
<!-- 等价于(字符串用法) -->
<div :class="active">box5</div><!-- 对象方法(常用) -->
<!-- isOne和isTwo为布尔值,真则加该类(one/two),假则不加-->
<div :class="{one:isOne, two:isTwo}">box6</div><!-- 若键值对相同,则简写一个即可 -->
<div :class="{demo:demo}">box6</div>
<!-- 等价于 -->
<div :class="{demo}">box6</div> <!-- 若样式太多,可采用方法 -->
<div :class="getStyleArr()">box7</div>
<div :class="getStyleObject()">box8</div>
</template><script>
const data = {one: 'one',two: 'two',active: ['one','two'],isOne: true,isTwo: false,demo: true
}
export default {name: 'App',data() {return data},methods() {getStyleArr() {return [this.one,this.two];},getStyleObject() {return {one: this.isOne,two: this.isTwo}
}
</script>
<style scoped>
.one {background-color: rebeccapurple;font-weight: bold;
}
.two {background-color: #42b983;
}
.demo {background-color: #333;
}
</style>
4.3.2 绑定style属性
有种方法,一种数组语法、一种是对象语法
<template>
<!-- 数组方法-->
<div :style="['font-size:100px','background:red']">box1</div>
<!-- 等价于 -->
<div :style="[fontSize, bgColor]">box2</div>
<div :style="['font-size:'+size+'px','background:'+color]">box3</div><!-- 对象方法-->
<div :style="{fontSize: '15px', 'background-color':'yellow'}">box9</div>
<div :style="{'font-size': '15px', 'background-color':'yellow'}">box9</div>
</template><script>
const data = {fontSize: 'font-size:50px',bgColor: 'background-color:green',size: 90,color: 'yellow'
}
export default {name: 'App',data() {return data}
</script>
4.4 计算属性
**使用:**在computed属性对象中定义计算属性的方法,在页面中使用{{方法名}}
来显示计算的结果。
原理:底层借助了Objcet.defineproperty()方法提供的getter
和setter
。
get有什么作用?
当读取computed中的方法时,get就会被调用,且返回值就作为该方法的值
get函数什么时候执行?
(1) 初次读取时会执行一次。
(2) 当依赖的数据发生改变时会被再次调用。
优势: computed计算属性有缓存的功能,计算属性在处理一些复杂逻辑时是很有用的。
<template>
<div><h3>{{name}} - {{slogen}}</h3><h3>{{name +' - ' + slogen}}</h3><h3>{{getTitle()}}</h3><h3>{{title}}</h3>
</div>
</template><script>
const data = {name: '张三',slogen: '新的世界'
}
export default {name: 'App',data() {return data},computed: {title: {get() {console.log('get computed')return this.name+ ' - '+this.slogen;}}},methods: {getTitle() {console.log('get methods')return this.name+ ' - '+this.slogen;}}
}
</script>
4.4.1 methods VS computed
如果有多个数据
<h3>{{getTitle()}}</h3><h3>{{getTitle()}}</h3><h3>{{getTitle()}}</h3><h3>{{title}}</h3><h3>{{title}}</h3><h3>{{title}}</h3>
运行查看控制台
methods里的getTitle()是使用多少次方法就调用多少次。
而computed有缓存的作用,只计算一次,computed里的title依赖于name和sologen,只要name和slogen没有变化,这个两个属性值就一直保存在缓存中,若更改,则相应title绑定也会更新。
计算属性默认只有getter,需要时也提供一个setter
计算属性完整写法
// ...
computed: {fullName: {// getter 可以省略,//当fullName所依赖的firstNameh和lastName发生改变时会被再次调用get() {return this.firstName + ' ' + this.lastName},// setterset(newValue) {const names = newValue.split(' ')this.firstName = names[0]this.lastName = names[names.length - 1]}}
}
// ...
现在在运行 vm.fullName = 'John Doe'
时, setter
会被调用, vm.firstName
和 vm.lastName
也会被对应更新。
计算属性常用简写(只考虑读取,不考虑修改的情况下)
computed: {fullName() {return this.firstName + '-' + this.lastName;}}
例子
总价:<small>¥</small>{{totalPrice}}
.....
const data = {books: [{id:1, name:'JS大红本第一版',price:120},{id:1, name:'JS大红本第二版',price:130},{id:1, name:'JS大红本第三版',price:150},{id:1, name:'JS大红本第四版',price:190}]
}
export default {name: 'App',data() {return data},//计算属性computed: {totalPrice: {get() {//汇合return this.books.reduce((s,n)=> s+=n.price, 0)}}}
}
4.4.2 监听属性watch及computed VS watch
Vue.js提供了一个方法 $watch
, 它用于观察 Vue 实例上的数据变动。当一些数据需要根据其它数据变化时。
监听属性watch: 监听具体数据变化,当数据属性变化时, 回调函数handler自动调用, 在函数内部进行计算
写法:
(1)在vue实例vm中传入watch配置来监视指定的属性
(2)通过vm对象的 $watch()
应用场景: 数据变化时执行异步或开销较大(比较耗时)的操作
注意: 监听的属性必须在vm中存在,才能进行监听
思考下面例子:
<div id="demo">{{ fullName }}</div>
var vm = new Vue({el: '#demo',data: {firstName: 'Foo',lastName: 'Bar',fullName: 'Foo Bar'},watch: {//完整写法//xxx为vm实例中存在且被监听的属性/* xxx: {immediate: true, //初始化时让handler调用一下//handler(固定函数) 什么时候调用?当函数中的数据发生改变时handler(newValue, oldValue) {....},},*///简写 (当只需要handler属性时)firstName(val) {this.fullName = val + ' ' + this.lastName},lastName(val) {this.fullName = this.firstName + ' ' + val}}
})//还有另外一种写法,但是需要保证vm实例已创建
// vm.$watch 正常写法
vm.$watch('fistName', {immediate: true,deep: true,handler(newValue ,oldVelue) {this.fullName = val + ' ' + this.lastName}
})
//vm.$watch 简写
vm.$watch('fistName', function(newValue ,oldVelue){this.fullName = val + ' ' + this.lastName}
})
上面代码是命令式的和重复的。跟计算属性对比:
var vm = new Vue({el: '#demo',data: {firstName: 'Foo',lastName: 'Bar'},computed: {fullName() {return this.firstName + ' ' + this.lastName}}
})
计算属性的方法更好点。
深度监听:
(1) Vue中的watch默认不监测对象内部值的改变,只检测第一层。
(2) 配置deep:true
可以监测对象内部值改变,可以检测多层。
备注:
(1). Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
(2). 使用watch
时根据数据的具体结构,决定是否采用深度监视。
var vm = new Vue({el: '#demo',data: {numbers:{a:1,b:2} },watch: {//监视多级结构中某个属性的变化'numbers.a':{handler() {……}},//监视多级结构中所有属性的变化numbers: {deep: true,handler() {……}}}
})
4.4.3 computed与watch、methods的区别
computed
:计算属性,依赖其他属性,当其他属性改变的时候,下一次获取computed值时也会改变,computed
的值会有缓存
watch
:监听属性,监听具体数据变化,当数据属性变化时, 回调函数handler
自动调用, 在函数内部进行计算
methods
: 该属性用于在Vue对象中定义方法。
computed
与watch
区别:
computed
能完成的功能,watch
都可以完成。watch能完成的功能,computed
不一定能完成,例如:watch
可以进行异步操作。- 当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为
computed
- 如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化
计算属性computed
在大多数情况下更合适,但当需要在数据变化时执行异步或开销较大的操作时,使用watch
更适用。
computed
与methods
区别:
计算属性是基于它们的依赖进行缓存,如果多次使用时,计算属性只会调用一次,性能上计算属性明显比methods
好,如果依赖改变则重新缓存,而方法不缓存
4.3 事件监听 v-on
在前端开发中,需要经常和用户交互
绑定事件监听器指令:v-on
缩写: @ (语法糖)
参数: $event
(获取事件对象)
注意:
- 事件的回调需要配置在methods对象中,最终会在vm上;
- methods中配置的函数,不要用箭头函数!否则this就不是vm
- methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象;
- 事件函数的调用方式:
@click="demo”
和@click="demo($event)"
效果一致,但后者可以传参
<!-- 完整语法 -->
<a v-on:click="doSomething"> ... </a><!-- 缩写 -->
<a @click="doSomething"> ... </a><!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
<template><div>msg = {{msg}}<br><input type="text" v-model="msg"><br><br>num = {{num}}<br>//<button @click="num--">-</button><button @click="sub">-</button><input type="text" size="3" v-model="num">//<button @click="num++">+</button><button @click="add">+</button></div>
</template><script>
const data = {msg: 'this is a test',num: 0,max: 10,min: 0
}
export default {name: 'App',data() {return data},methods: {add() {if (this.num >= this.max) {this.num = this.max;} else {this.num++;}},sub() {if (this.num <= this.min) {this.num = this.min;}else {this.num--;}}}
}
</script><style>
.....
</style>
效果
4.3.1 v-on事件修饰符号
.stop
阻止事件冒泡.self
当事件在该元素本身触发时才触发事件.capture
添加事件侦听器是,使用事件捕获模式.prevent
阻止默认事件.once
事件只触发一次.enter
只有在key
是Enter
时调用.passive
滚动事件的默认行为 (即滚动行为) 将会立即触发- 修饰符可串联
<a @click.stop.prevent="doThat"></a>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
4.3.2 v-on按键修饰符号
.enter
只有在key
是Enter
时调用.delte
(捕获“删除”和“退格”键).esc
退出.space
空格.tab
换行 (特殊,必须配合keydown去使用).up
上.down
下.left
左.right
右
系统修饰键(用法特殊):ctrl、alt、shift、meta
(1). 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。比如ctrl+s 然后释放s
(2). 配合keydown使用:正常触发事件。
也可以使用keyCode去指定具体的按键(不推荐),但注意要转为kebab-case(短横线命名)
Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名
//keyup 按键松开触发
<!-- enter回车 -->
<input @keyup.enter='submit'>
<!-- delete删除键 -->
<input @keyup.delete='handle'>
<div id="app"><form action=""><div>用户名: <input type="text" @keyup.delete='clearContent' v-model='uname'></div><div>密码:<input type="text" @keyup.enter='handleSubmit' v-model='pwd'></div><div><input type="button" @click='handleSubmit' value="提交"></div></form></div>//……<script type="text/javascript">var vm = new Vue({el: '#app',data: {uname: '',pwd: '',age: 0},methods: {clearContent(){// 按delete键的时候,清空用户名this.uname = '';},handleSubmit(){console.log(this.uname,this.pwd)}}});</script>
//……
除了系统的修饰符,还有自定义按键修饰符
规则:自定义按键修饰符名字是自定义的,但是对应的值必须是按键对应event.keyCode值
<div id="app"><input type="text" @keyup.f1='handle' v-model='msg'></div><script type='text/javascript'>//a的ACSII值为65Vue.config.keyCodes.f1 = 65const app = new Vue({el: "#app",data: {msg: ''},methods: {handle: function (event) {console.log(event.keyCode);}}})</script>
4.3.3 获取事件对象
<button @click="sub('sub',$event)">-</button>
<input type="text" size="3" v-model="num">
<button @click="add">+</button>
add(e) {console.log(e); //没传参,获取得到事件对象if (this.num >= this.max) {this.num = this.max;} else {this.num++;}},
sub(p) {console.log(p,e); //传参了,一个为’sub',一个为事件对象if (this.num <= this.min) {this.num = this.min;}else {this.num--;}}
<div @click="one()" class="box1"><div @click="two()" class="box2"><button @click="three()">按钮</button></div>
</div><script>
.....
export default {name: 'App',data() {return data},methods: {one() {console.log('one');},two() {console.log('two');},three() {console.log('three');}}
}
</script>
<style scoped>
.box1 {width: 150px;height: 150px;background-color: #42b983;
}
.box2 {width: 100px;height: 100px;background-color: rebeccapurple;
}
</style>
点击按钮,事件冒泡
若要停止事件冒泡,则<button @click.stop="three()">按钮</button>
可串行使用
<div @click.self.stop="two()" class="box2"><button @click="three()">按钮</button>
</div>
4.4 条件渲染 v-if、v-show
v-if
和 v-show
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-show
就简单得多——不管初始条件是什么,元素总是会被渲染并保留在 DOM 中,并且只是简单地基于 CSS 进行切换(display)
v-if和v-show的区别
v-if
指令是直接销毁和重建DOM达到让元素显示和隐藏的效果
v-show
指令是通过修改元素的display属性让其显示或者隐藏
v-if
有更高的切换开销,而v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show
较好;如果在运行时条件很少改变,则使用v-if
较好。
条件分支 v-if v-else
多条件分支 v-if v-else-if v-else
注意:v-if
可以和v-else-if v-else
一起使用,但要求结构不能被打断
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no
Vue全家桶(一):Vue基础+Vue-Cli+Vue组件化+过渡动画相关推荐
- vue全家桶学多久能上手项目,vue全家桶插件有哪些
VUE中文教程 . 火星的中文基础教程不知道你是初学还是已经入门了入门了就去verycd下.高级场景设计教程].W3D源我就不贴了搜一下就能有gnomon的教程都还算不错但是是英文你可以看操作加自己理 ...
- Vue全家桶(一)之基础指令
- Vue全家桶 + webpack 构建单页应用初体验
文章指南 主题 承接这上一篇Vue + Webpack 构建模块化开发框架详解,我们知道了如何使用webpack对vue进行打包,从而开始我们的前端模块化开发之路,这一篇在上一篇的基础上讲解 Vu ...
- 【 Vue全家桶 · Vue CLI(四)】Vue项目的详细目录结构解析
文章目录 前言 -- 一级目录解析 一. dist 二. node_modules 三. public 四. src(基础版) 4.1 main.js 4.2 App.vue 4.3 src / as ...
- elemenetui 布局_2020 零基础到快速开发 Vue全家桶开发电商管理系统(Element-UI)主页布局开发-Go语言中文社区...
1.引言 寒假是用来反超的!一起来学习Vue把,这篇博客是关于项目主页布局,请多指教~ 2.整体布局 3 .主页 3.1 实现基本的主页布局 3.2 美化主页的header区域 3.3 实现导航菜单的 ...
- 2020 零基础到快速开发 Vue全家桶开发电商管理系统(Element-UI)商品分类篇
文章目录 1.引言 2.商品分类篇 2.1 通过路由加载商品分类组件 2. 2 绘制商品分类组件的基本页面布局 2.3 调用API获取商品分类列表数据 2.4 初步使用vue-table-with-t ...
- 【Vue】Vue全家桶(一)Vue基础
文章目录 1 Vue概述 1.1 vue简介 1.2 vue特点 1.3 Vue 扩展插件 2 Vue的基本使用 2.1 传统开发模式对比 2.2 引入Vue.js的方法 2.3 Vue.js案例分析 ...
- Vue开发入门(二) | 说说Vue全家桶有哪些~
全家桶,顾名思义,就是一个系列,可以组合开发成完整强大的Vue项目 前言: *Vue两大核心思想:组件化和数据驱动. 组件化:把整体拆分为各个可以复用的个体 数据驱动:通过数据变化直接影响bom展示, ...
- vue全家桶+koa2+mongoDB打造全栈社区博客
背景 一直以来都想自己编写一个自己的社区博客,后来在网上找了一下,最后决定参考慕课网的一个社区项目,决定改用vue2.6+AntdForVue+koa2+mongoose实现一套社区博客. 简介 这是 ...
最新文章
- 软件文本框横线_免费开源剪辑软件Shotcut推荐和使用教程
- Python eval函数用法简介
- 【javascript】数据结构-链表
- 如何在Appscale下发布自己的应用(一)
- 浅谈C# Socket编程及C#如何使用多线程
- 建模师分类:选择游戏还是工业?哪个发展前景更好?
- sqrt()平方根计算函数的实现1——二分法
- C语言汇编-函数调用堆栈的过程
- 2023年CFA一级notesbook1+quicksheet(高清)
- Web前端基础CSS初识学习笔记(8)行高对齐和首行缩进间距
- qt文件逐行读取_QT平台文件逐行读取和字符串规律输出练习
- 英语cymophanite猫眼石cymophanite单词
- IP-guard 双机热备使用说明
- 2021年科技园区规划设计方案
- 数据库 | MySQL 5.7 安装教程及卸载教程【附安装包】
- WPF 4 开发Windows 7 任务栏(Overlay Icon、Thumbnail Toolbar、Progress Bar)
- 胜博发公益:只要用手机就能随手做公益 苹果与许多公益团体合作
- 使用 JSTL SQL 标签的JSP CRUD增删改查
- word中水印无法显示
- 浅析:2019高教社杯全国大学生数学建模竞赛题目---B题 “同心协力”策略研究
热门文章
- 如何使用OCR编辑器检查和识别文本
- MapReduce计数器实验
- 百度云显示服务器返回错误,网站加入百度云加速后,出现Error520源站返回未知错误怎么办?...
- 计算机网络安全本科大学排名,2021网络工程专业大学排名 最好大学排行榜
- Windows 黑科技工具推荐
- 微信小程序调用腾讯地图,点击选择并返回选择位置数据!
- c# 实现顺序栈(winform程序)
- python怎么找出列表中的重复数据_python – 如何在列表中找到重复项并使用它......
- 华为无线wifi设备连接到服务器,wifi模块如何连接云服务器
- vue调用微信qpi