vue是采用自底向上增量开发设计的一套构建用户界面的渐进式框架,它不仅易上手且方便。
vue的安装有三种方式,官网直接进行下载;使用在线的CND(https://unpkg.com/vue@2.6.11/dist/vue.js);使用npm install vue 命令进行下载。获取后直接在script标签中引入就可。
对于vue最简单的应用将其当成是一个模板引擎,采用模板语法把数据渲染进DOM.如下:
<div id="app">
{{message}}
</div>
每个vue.js应用都是通过构造函数Vue创建一个Vue的根实例来进行的,常使用vm(vue model)这个变量名表示实例。在实例vue时,要传入一个选项对象,它可以包含数据,模板,元素,方法,生命周期等等。下面为Vue()构造函数传入了一个对象,对象中包含了el和data这两个参数。el参数,用于提供一个在页面上已存在的DOM元素作为Vue实例挂载目标。而data则表示Vue实例的数据对象。
let vm = new Vue({
//选项
el:"#app",
data:{
message:'davina'
}
})
一、vue模板的内容
对于{{}}它主要的作用是进行数据绑定,最常见的是使用Mustache语法({{}}语法)的文本插值。上文中的message相当于一个变量或者是占位符,最终它会表示为真正的文本内容。Mustache标签将会被数据对象上(data中的message)的值进行替代。当massage上的内容发生改变时,插值处的内容也会进行更新。
表达式插值。下面的这些表达式会在所属的vue实例的数据作用域下作为js被解析。每个绑定只能包含单个表达式,需要注意的是不能是语句,它包括定义变量,定义函数,赋值等待。
{{number +1}}
{{value?'yes':'no'}}
{{ 对象 }}
{{ 数组 }}
{{函数的返回值}}
示例:
<div id="app">
{{msg}}<br>
{{[1,2,3].map((item)=>{return item*2})}}<br>
{{arr}}<br>
{{obj}}
</div>
<!-- 导入vue.js -->
<script src="./vue.js"></script>
<script>
// vm是vue的实例
let vm = new Vue({
el: '#app',//指定vue替换元素
data: {
msg: 'test',
obj: { age: 20 },
arr: [1, 2, { name: "ph" }],
}
});
</script>
二、指令
在模板的元素中,那个v-xxx行内属性就是Vue的指令,它有常用即有指令和自定义指令。
1、即有指令(13)
v-model="xxx": 一般用于表单元素上,创建双向数据绑定。input框内容改变 ,所有用到这个变量的地方都会自动进行更新。像下面的例子中,在input框中输入其它的内容,上面msg的内容也会被修改。
<div id="app">
<!-- textarea -->
<textarea v-model='text'></textarea><br>
<!-- select -->
<h2>{{selectValue}}</h2>
<!-- 多个选择都是数组 -->
<select v-model='selectValue' multiple>
<option value="" disabled>请选择</option>
<option v-for='i of selectOptions' :value="i.id">{{i.value}}</option>
</select><br>
<!-- radio 分组互斥-->
<input type="radio" value="男" v-model="radioValue">
<input type="radio" value="女" v-model="radioValue"><br>
<!-- checkbox 默认值是不选择 true false -->
爱好:{{checkValue}}
<input type="checkbox" value="吃饭" v-model="checkValue">
<input type="checkbox" value="睡觉" v-model="checkValue">
<input type="checkbox" value="打豆豆" v-model="checkValue"><br>
<!-- 修饰符 -->
<!-- trim是前去除前后的空格,但中间的不能去,number限制只能输入数字 -->
<input type="text" v-model.trim="text">
<input type="text" v-model.number="text">
</div>
<script src="./vue.min.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
text: 'davina',
selectValue: [],
selectOptions: [
{ value: 'js', id: 1 },
{ value: 'react', id: 2 },
{ value: 'vue', id: 3 }
],
radioValue: '女',
checkValue: ['吃饭', '睡觉', '打豆豆'],
}
})
</script>
v-text="xxx": 这个不太常用。主要用于更新textContent,可以等价于js中的text属性
v-html=“xxx”: 双大括号的方式会将数据解析为纯文本,而不是html。如果是真正的要输出html标签要用到这个v-html指令,它等价于js中的innerHTML。
<div id="app">
<h4 v-text="str"></h4>
<!-- <h4>{{str}}</h4> -->
<h4 v-html="str"></h4>
</div>
<script>
let vm = new Vue({
el:'#app',
data:{
str:'<i>test</i>'
}
});
</script>
v-if="xxx": Vue会根据表达式的值真假条件来渲染元素,它可以实现条件渲染,用来控制元素或者组件是否进行加载,它有比较大的切换开销;
v-else: 搭配v-if来进行使用的,它必须紧跟在v-if/v-else-if后面,不然是不起作用的;
v-else-if: 它充当v-if中的else-if块,可以链式使用多次
<div id="app">
<h2 >{{msg}}</h2>
<input type="text" v-if="msg.length < 10 " v-model="msg">
<h2 v-else>内容太长,不再显示</h2>
</div>
<script>
let vm = new Vue({
el:'#app',
data:{
msg:'msg'
}
});
</script>
v-show="xxx": 用来控制元素或者组件是否显示,和v-if不同的是如果v-if的值是false那么这个元素将销毁,不在DOM中,但v-show的元素会始终被渲染保存在DOM中,它只是简单的切换了css中的display属性,有比较大的初始化加载开销。
v-for="xxx": 用来循环展示标签的,可以循环数组,数字,字符串,对象(基本上都是数组);需要注意的是v-for和v-if同时使用时,for的优先级高(不建议一起使用),还用一般要带一个:key,对于vue来说是元素的一个身份证明,有利于Vue中的DOM DIFF计算。j理想的key是数据的唯一ID,如果没我们可以用索引,但这时有可能会导致元素不更新复用了老的元素。有以下两种形式。
<div v-for="item of items"></div> //使用of
<div v-for="(item,index) in items"></div> //使用in index表示当前项的索引 item 数组中的每一项
<div id="app">
<h3 v-for="(index,item) in ary" :key="index">{{item}}:{{index}}</h3>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
ary: [1, 2, 3, 4]
}
});
</script>
v-bind="xxx": 用来动态绑定一个或者多个特性,处理行内属性。没有参数时,可以绑定到一个包含键值对的对象。可以简写用冒号(:)来表示。常用于绑定style,class所以Vue对其进行了专门的强化:class="{类名1:值,类名2:值,......}",:style="{属性名:属性值,......}"。
<style>
.box {
color: lightblue
}
</style>
<div id="app">
<a :href="url" :class="cln">click me</a>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
url: 'https://www.baidu.com/img/flexible/logo/pc/result@2.png',
cln: 'box'
}
});
</script>
v-cloak: 保持在元素上直到关联实例结束时进行编译。Vue专门用来提供解决小胡子显示问题的,它需要配合css来使用,当vue编译完成后,会把这个属性删掉,这时css属性就不起作用了。
<style>
[v-cloak]{
opacity: 0;
}
</style>
<div id="app" v-cloak>
<h5>{{msg}}</h5>
</div>
<script>
let vm = new Vue({
el:'#app',
data:{
msg:'message'
}
});
</script>
v-once: v-once关联的实例,只能编译一次。实例及所有的了节点将被视为静态内容进行跳过,可以用于优化更新性能。
<div id="app" v-once>
<h5>{{msg}}</h5>
<p>{{ary}}</p>
</div>
<script>
let vm = new Vue({
el:'#app',
data:{
msg:'message',
ary:[1,2,3]
}
});
</script>
v-pre: 有这个指令的标签及其后代元素,vue都不在编译,主要用来跳过这个元素和它的子元素编译过程,用来提升编译效率的。
<div id="app">
<ul v-pre>
<!-- 里面的内容不用vue来操作,可以提升效率 -->
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
<script>
let vm = new Vue({
el:'#app'
});
</script>
v-on: 专门用来绑定事件的指令,可以简写成@。
<div id="app">
<h2>{{count}}</h2>
<button @click="add"> + </button>
<button @click="minus"> - </button><br>
<!-- 在函数名后面加上()不是为了执行,而是为了传参 -->
<button @click="add(10,$event)"> +10 </button>
<button @click="minus(-10)"> -10 </button><br>
<!--
@click='fn' 这种情况默认把事件对象传过去
@click="fn()" 一个参数都没有那就是把函数执行
@click="fn(10,20,...)" 这种情况 写什么参数就传递什么参数
@click="fn(10,$event,20,$event)" 这种情况是即需要事件对象(编写$event),也需要自己传递的参数
-->
</div>
<script src="./vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: { count: 0 },
methods: {
//这里放的是各种函数,函数当前实例都是this
//这里的属性会被挂载到实例上,所以与data中的属性名不能重复
add(n) {
typeof n == "object" ? this.count++ : this.count += n;
},
minus(n) {
typeof n == 'object' ? this.count-- : this.count -= n;
}
}
});
</script>
还有事件修饰符:.stop:阻止事件继续传播 / .prevent:事件不再重载页面 / .capture: 使用事件捕获模式 / .self:只当在event.target是当前元素时触发 / .once:事件将只会触发一次 / .passive:告诉浏览器不想阻止事件的默认行为
需要强调一点的是,使用修饰符顺序很关键,相应的代码会以同样的顺序产生。在大部分事件中,先执行绑定的函数,再执行默认的函数,默认的函数也有执行的顺序。但在onscroll,touchmove这类高频触发的事件是先执行默认函数函数,再执行绑定函数。
<body>
<div id="app">
<h2>{{count}}</h2>
<div class="outer" @click.once='add'>
outer
<div class="inner" @click.stop="stop">
inner
<div class="center">
center
</div>
</div>
</div>
<!-- 当然还有按钮修饰符 -->
<input type="text" @keydown.enter="enter">
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: { count: 0 },
methods: {
add(n) {
typeof n == "object" ? this.count++ : this.count += n;
},
minus(n) {
typeof n == 'object' ? this.count-- : this.count -= n;
},
prevent(e) {
// e.preventDefault();
},
stop(e) { e.stopPropagation() },
enter(e) { console.log(e) }
}
});
</script>
2、自定义指令
Vue除了提供默认的内置指令以外,还可以让开发者根据实际情况来自定义指令。通过它我们可以DOM元素进行更多的底层操作。它存在着全局注册和局部注册两种方式。
通过Vue.directive(id,[definintion])方式来进行注册,第一个参数为自定义指令的名称,第二个参数可以是对象数据也可以是一个函数。需要注意的一点是指令名称不需要加v-,默认是自动加上的,但在使用时要加上v-前缀。
<body>
<div id="app">
<h3 v-col='"lightblue"'>{{msg}}</h3>
<h5 v-col>{{msg}}</h5>
</div>
</body>
<script>
Vue.directive('col', function (el, obj) {
//对函数中的this为window 不在是当前的实例了
console.log(this);
//el 使用这个指令的那个元素标签
//obj中有一个value值,它对应的是指令后面跟的值。如果没有则不存在
console.log(el, obj);
el.style.color = obj.value || 'lightpink';
})
let vm = new Vue({
el: '#app',
data: {
msg: "自定义指令之全局注册"
}
});
</script>
局部注册我们可以通过在Vue实例中添加directives对象数据来进行注册。在工作中如果有多个自己定义的指令,一般会单独新建一个文件,用import或者script进行引入。先执行局部再用全局指令。
<body>
<div id="app">
<h5 v-col>{{msg}}</h5>
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
msg: "自定义指令之全局注册"
},
directives: {
col(el, obj) {
el.style.color = 'lightskyblue'
}
}
});
</script>
一个指令定义对象可以提供如下几个钩子函数,一般用的比较多的时insert,bind和unbind。
bind: 只调用一次,指令第一次绑定到元素时进行调用;
unbind: 只调用一次,指令与元素解绑时调用;
insert: 被绑定元素插入父节点时调用;
update: 所在组件的VNode更新时调用,但也可能是发生在其子元素的VNode更新之前;
componentUpdated: 所在组件的VNode及其子元素的VNode全部更新时调用
它们中的每一个都以el,binding,VNode参数:
el: 指令所绑定的DOM元素,可以直接用来操作DOM
binding: 一个对象。包含了以下属性name,value,oldValue,expression,arg,modifiers.
VNode:Vue编译生成的虚拟节点
oldVnode: 上一个虚拟节点,用来区分传递的旧值和新值,仅在update和componentUpdated钩子中可用。
下面这个例子可用于多个权限的设置,需要注意的是inserted函数的使用。
<body>
<div id="app">
<h3 v-premission='"张三"'>{{msg}}</h3>
</div>
</body>
<script>
let ary = ["张三", "赵二", "王五", "李六"];
Vue.directive('premission', {
//inserted是钩子函数它是固定的
inserted(el, { value }) {
//这个函数执行的时候 代表 编译好的元素已经插入到了父结点中
let bol = ary.indexOf(value) == -1 ? false : true;
if (!bol) {
el.parentNode.removeChild(el);
}
}
})
let vm = new Vue({
el: '#app',
data: {
msg: "权限"
}
});
<div id="box">
<input type="text" v-focus.color='color'>
</div>
<script>
// 需求:让输入框自动获取焦点
//全局指令:所以组件,实例都可以使用
Vue.directive('focus', {
//指令元素插入到页面时执行
inserted(el, obj, vnode) {
el.focus();
//el 当前指令元素 obj 绑定属性 vnode虚拟节点 contex上下文,当前指令所在的上下文
// console.log(el, obj, vnode);
obj.modifiers.color ? el.style.background = obj.value : lightblue;
},
//绑定时执行
// bind(el, obj, vnode) {
// Vue.nextTick(() => {
// el.focus();
// })
// }
//指令销毁时会触发这个函数
// unbind(){}
})
let vm = new Vue({
el: '#box',
data: {
color: 'lightgreen',
}
})
</script>
<style>.content {height:30px;width: 120px;background-color: lightblue}</style>
<div id="app">
//弹层功能
<div v-click-outside>
<button>click </button>
<input type="text">
<div class="content" v-if="isShow">xxxx年xx月xx日
</div>
</div>
</div>
<script>
//判断是否存在当前的dom中
let vm = new Vue({
el: '#app',
directives: {
clickOutside: {
bind(el, bindings, vnode) {
el.fn = (e) => {
if (el.contains(e.target)) {
vnode.context['focus']()
} else {
vnode.context['blur']()
}
}
document.addEventListener('click', el.fn)
},
unbind(el) {
document.removeEventListener('click', el.fn)
}
}
},
data: {
isShow: false
},
methods: {
blur() {
this.isShow = false;
},
focus() {
this.isShow = true;
}
}
});
</script>