1.vue简介
vue是一个渐进式的前端框架,渐进式意味着你可以将vue作为你应用的一部分嵌入其中,或者如果你希望将更多的业务逻辑使用vue实现,那么vue的核心库以及其生态系统。比如Core+vue-router+VUex+axios,也可以满足你各种各样的需求。
vue的特点和web开发中常用的高级功能:
- 解耦视图和数据
- 双向数据绑定
- 可复用的组件
- 前端路由技术
- 状态管理
- 虚拟DOM
2.VUE的安装使用
方式一:直接CND引入
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
方式二: 下载和引入
// 开发环境 https://vuejs.org/js/vue.js
// 生产环境 https://vuejs.org/js/vue.min.js
方式三:NPM安装
3.VUE体验
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
{{ str1 }}
</div>
</body>
<script>
var vm = new Vue({ //这个Vue对象用来控制某一个标签里面的数据
el:"#app", //要控制的标签
data:{
str1:"hello vue", //定义一个数据,在id为app的标签内部去使用
}
})
</script>
</html>
4.VUE常见语法格式
4.1 模板语法
<div id="app">
<p>{{ str1 }}</p>
<p>{{ str1.split("").reverse().join("") }}</p>
<p>{{num+1}}</p>
<p>num1和numn2的最大值是:{{ num1>num2 ? num1 : num2 }}</p>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
str1:"hello",
num:20,
num1:40,
num2:80
}
})
</script>
4.2 v-bind控制标签属性
<div id="app">
<a v-bind:href="bd">百度</a>
<a :href="tb">淘宝</a>
<a :href="tb">淘宝</a>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
bd:"https://www.baidu.com",
tb:"https://www.taobao.com"
}
})
</script>
4.3、v-on事件格式
<div id="app">
<p>{{num}}</p>
<button v-on:click="num+=1">点我数字增加</button>
<button v-on:click="add">点我数字加5</button>
<button @click="add2(10)">点我数字加10</button>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
num: 20
},
methods:{
add:function(){
this.num += 5
},
add2(){
this.num += 10
}
}
})
</script>
5. VUE中的MVVM
-
view层 视图层,在前端里就是我们常说的DOM层,主要作用是给用户展示各种信息;
-
Model层 数据层,数据可能是我们自定定义的数据,或者是从网络请求下来的数据;
3.ViewModel层:
视图模型层,是View层和Model层沟通的桥梁;一方面它实现了数据绑定(Data Binding),将Model的改变实时反应到View中;另一方面它实现了DOM监听,当DOM发生改变可以对应改变数据(Data)
6.reduce方法的使用
利用reduce方法遍历数组的每一个元素,reduce()调用结果最后返回一个最终值(最后一次return值)。
var arr = [
{name: 'Vuejs入门', price: 99, count: 3},
{name: 'Vuejs底层', price: 89, count: 1},
{name: 'Vuejs从入门到放弃', price: 19, count: 5},
]
//数组名.reduce(回调函数,pre的初始值)
arr.reduce(function(pre, current){
// reduce这个方法被调用时,会遍历arr这个数组的每一个元素,每遍历一个元素,就执行一次这里的代码
// current表示当前正在遍历的这个元素
// pre 是上一次的这个函数return的值
// !!!因为第一次遍历没有上一个return值,所以,交给了第二个参数,设置pre的初始值
console.log(pre, current)
return 10
},0)
//!!!并且reduce方法最终会返回最后一次的return值
7.自定义指令
// 注册一个全局自定义指令 v-demo
Vue.directive('demo', {
inserted: function (el, binding) {
console.log(el, binding);
},
update(el, binding){}
})
局部自定义指令格式:
// 组件中注册局部指令
new Vue({
el: '#app',
data: {},
directives: {
demo: {
inserted: function (el, binding) {
cosnole.log(el, binding);
}
}
}
})
自定义指令的使用:
// 在模板中使用自定义指令
<div v-demo>
</div>
函数:
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。
参数:
el:指令所绑定的元素,可以用来直接操作 DOM 。binding:一个对象,包含以下属性:name:指令名,不包括v-前缀。value:指令的绑定值,例如:v-demo="1 + 1"中,绑定值为2。oldValue:指令绑定的前一个值expression:字符串形式的指令表达式。例如v--demo="1 + 1"中,表达式为"1 + 1"。modifiers:一个包含修饰符的对象。例如:v-demo.foo.bar中,修饰符对象为{ foo: true, bar: true }。
实现类似v-show的自定义指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p v-demo="status">12</p>
<button @click="status = !status">取反</button>
</div>
</body>
<script>
const vm = new Vue({
el: '#app',
data: {
status: true
},
directives: {
demo: {
inserted(el, binding) {
console.log(el, binding)
if (binding.value) {
el.style.display = 'block'
} else {
el.style.display = 'none'
}
},
update(el, binding){
console.log(el, binding)
if (binding.value) {
el.style.display = 'block'
} else {
el.style.display = 'none'
}
}
}
}
})
</script>
</html>
8.双向数据绑定原理
Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。Vue里面是怎么做到的的呢?其实就是使用了
Object.defineProperty把Vue内的属性全部转成getter/setter。Object.defineProperty是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
Object.defineProperty 实现了对象劫持这个功能
vue双向数据绑定原理:
借助Object.defineProperty()对数据进行劫持,并结合发布-订阅者模式,来实现双向数据绑定
语法:
Object.defineProperty(obj, prop, desc)
obj需要定义属性的当前对象prop当前需要定义的属性名desc属性描述符
数据属性:
通过Object.defineProperty()为对象定义属性,有两种形式,分别为数据描述符,存取描述符,下面分别描述两者的区别:
value表示它的默认值writable如果为true标识可以被修改,如果为false标识不能被修改(默认值为false)configurable描述属性是否配置,以及可否删除,可以认为是总开关 默认值 false(不可删除)enumerable描述属性是否出现在for in 或者 Object.keys()的遍历中 默认值false(不能遍历)
let obj = {};
Object.defineProperty(obj, 'name', {
value: '张三'
})
obj.name = '李四'
console.log(obj.name) // 张三
let obj = {};
Object.defineProperty(obj, 'name', {
value: '张三',
writable: true
})
obj.name = '李四'
console.log(obj.name)
let obj = {};
Object.defineProperty(obj, 'name', {
value: '张三',
writable: true,
configurable: true,
enumerable: true
})
obj.name = '李四'
// delete obj.name
console.log(obj.name) // 李四
console.log(Object.keys(obj)) // ['name']
存取属性:
let obj = {};
let temp = null;
Object.defineProperty(obj, 'name', {
get() {
return temp
},
set(val) {
temp = val
}
})
obj.name = '李四'
console.log(obj.name)
面试题回答:
vue的双向数据绑定原理是什么?
vue数据双向绑定是通过数据劫持结合“发布者-订阅者模式”的方式来实现的。 vue是通过Object.defineProperty()来实现数据劫持,其中会有getter()和setter方法;当读取属性值时,就会触发getter()方法,在view中如果数据发生了变化,就会通过Object.defineProperty()对属性设置一个setter函数,当数据改变了就会来触发这个函数;
9.过滤器的使用
Vue的过滤器用来对数据展示之前做一定的处理
<div id="app">
<!-- {{ 变量名 | 过滤器名 }} -->
<p>{{ num | formatNum }}</p>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
num:10
},
filters:{
formatNum(val){ // 这个形参接收 | 符号前面的变量数据
return val + 50 //return后面的值就是将来展示在页面上的值(即过滤之后的值)
}
}
})
</script>
过滤一个时间戳:
<div id="app">
<!-- {{ 变量名 | 过滤器名 }} -->
<p>{{ timestamp | formatDate }}</p>
</div>
<script>
// var timestamp = new Date().getTime() // 获取时间戳
// console.log("日期是:",timestamp)
var vm = new Vue({
el:"#app",
data:{
timestamp:new Date().getTime()
},
filters:{
formatDate(val){ // 这个形参接收 | 符号前面的变量数据
var now = new Date(val)
var year=now.getFullYear();
var month=now.getMonth()+1;
var date=now.getDate();
var hour=now.getHours();
var minute=now.getMinutes();
var second=now.getSeconds();
return year+"-"+month+"-"+date+" "+hour+":"+minute+":"+second;
}
}
})
</script>
9.2、全局过滤器
多个app共用的过滤器可以作为全局过滤器来书写
<div id="app">
<!-- {{ 变量名 | 过滤器名 }} -->
<p>{{ timestamp | formatDate }}</p>
</div>
<div id="app2">
<!-- {{ 变量名 | 过滤器名 }} -->
<p>第二个: {{ timestamp | formatDate }}</p>
</div>
<script>
//全局过滤器
// Vue.filter("过滤器名字",(val)=>{})
Vue.filter("formatDate",(val)=>{
var now = new Date(val)
var year=now.getFullYear();
var month=now.getMonth()+1;
var date=now.getDate();
var hour=now.getHours();
var minute=now.getMinutes();
var second=now.getSeconds();
return year+"-"+month+"-"+date+" "+hour+":"+minute+":"+second;
})
var vm2 = new Vue({
el:"#app2",
data:{
timestamp:new Date().getTime()
}
})
// var timestamp = new Date().getTime() // 获取时间戳
// console.log("日期是:",timestamp)
var vm = new Vue({
el:"#app",
data:{
timestamp:new Date().getTime()
},
// filters:{
// formatDate(val){ // 这个形参接收 | 符号前面的变量数据
// var now = new Date(val)
// var year=now.getFullYear();
// var month=now.getMonth()+1;
// var date=now.getDate();
// var hour=now.getHours();
// var minute=now.getMinutes();
// var second=now.getSeconds();
// return year+"-"+month+"-"+date+" "+hour+":"+minute+":"+second;
// }
// }
})
</script>