Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。
特点: 易用,灵活,高效
渐进式框架
逐一递增 vue + components + vue-router + vuex + vue-cli
框架是库的升级版
new Vue({
el:'#app',
template:'<div>我是姜文~~</div>', // 优先使用template
data:{}
});
在传统的mvc中除了model和view以外的逻辑都放在了controller中,导致controller逻辑复杂难以维护,在mvvm中view和model没有直接的关系,全部通过viewModel进行交互
允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。在使用数据前需要先声明
<div id="app">
{{ 1+1 }}
{{ msg == 'hello'?'yes':'no' }}
{{ {name:1} }}
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
msg:'hello'
}
})
</script>
function notify(){
console.log('视图更新')
}
let data = {
name:'jw',
age:18,
arr:[]
}
// 重写数组的方法
let oldProtoMehtods = Array.prototype;
let proto = Object.create(oldProtoMehtods);
['push','pop','shift','unshift'].forEach(method=>{
proto[method] = function(){
notify();
oldProtoMehtods[method].call(this,...arguments)
}
})
function observer(obj){
if(Array.isArray(obj)){
obj.__proto__ = proto
return;
}
if(typeof obj === 'object'){
for(let key in obj){
defineReactive(obj,key,obj[key]);
}
}
}
function defineReactive(obj,key,value){
observer(value); // 再一次循环value
Object.defineProperty(obj,key,{ // 不支持数组
get(){
return value;
},
set(val){
notify();
observer(val);
value = val;
}
});
}
observer(data);
data.arr.push(1);
let obj = {
name:{name:'jw'},
arr:['吃','喝','玩']
}
let handler = {
get(target,key,receiver){
if(typeof target[key] === 'object' && target[key] !== null){
return new Proxy(target[key],handler);
}
return Reflect.get(target,key,receiver);
},
set(target,key,value,receiver){
if(key === 'length') return true;
console.log('update')
return Reflect.set(target,key,value,receiver);
}
}
let proxy = new Proxy(obj,handler);
proxy.name.name = 'zf';
数组的变异方法(不能通过通过长度,索引改变数组)
<div id="app">
{{hobbies}}
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
hobbies:['洗澡','吃饭','睡觉']
}
});
vm.hobbies[0] = '喝水';// 数据变化视图不刷新
vm.hobbies.length--;// 数据变化视图不会刷新
</script>
vm.hobbies = ['喝水']; // 替换的方式
vm.hobbies.push('吃饭'); // push slice pop ...变异方法
不能给对象新增属性
<div id="app">
{{state.a}}
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
state:{count:0}
}
});
//vm.state.a = 100; // 新增熟悉不会响应到视图上
</script>
使用vm.$set方法强制添加响应式数据
function $set(data,key,val){
if(Array.isArray(data)){
return data.splice(key,1,val);
}
defineReactive(data,key,val);
}
$set(data.arr,0,1);
vm.$set(vm.state,'a','100');
vm.$set();
vm.$set(vm.state,'a','100');
vm.$watch();
vm.$watch('state.count',function(newValue,oldValue){
console.log(newValue,oldValue);
});
vm.$mount();
let vm = new Vue({
data:{state:{count:0}}
});
vm.$mount('#app');
vm.$nextTick();
vm.state.count = 100; // 更高数据后会将更改的内容缓存起来
// 在下一个事件循环tick中 刷新队列
vm.$nextTick(function(){
console.log(vm.$el.innerHTML);
});
vm.$data
vm.$el
在vue中 指令 (Directives) 是带有 v- 前缀的特殊特性,主要的功能就是操作DOM
v-once
<div v-once>{{state.count}} </div>
v-html (不要对用户输入使用v-html显示)
<div v-html="text"></div>
v-for遍历数组
fruits:['香蕉','苹果','桃子']
<div v-for="(fruit,index) in fruits" :key="index">
{{fruit}}
</div>
v-for遍历对象
info:{name:'jiang',location:'回龙观',phone:18310349227}
<div v-for="(item,key) in info" :key="key">
{{item}} {{key}}
</div>
template的使用
<template v-for="(item,key) in fruits">
<p v-if="key%2">hello</p>
<span v-else>world</span>
</template>
key属性的应用
<div v-if="flag">
<span>珠峰</span>
<input key="2"/>
</div>
<div v-else>
<span>架构</span>
<input key="1"/>
</div>
key尽量不要使用索引
<ul>
<li key="0">🍌</li>
<li key="1">🍎</li>
<li key="2">🍊</l>
</ul>
<ul>
<li key="0">🍊</li>
<li key="1">🍎</li>
<li key="2">🍌</li>
</ul>
Class 与 Style 绑定
数组的绑定
<div :class="['apple','banana']" ></div>
<div :class="{banana:true}"></div>
对象类型的绑定
<div :class="['apple','banana']" ></div>
<div :class="{banana:true}"></div>
<div :style="[{background:'red'},{color:'red'}]"></div>
<div :style="{color:'red'}"></div>
<input type="text" :value="value" @input="input">
<input type="text" v-model="value">
select
<select v-model="select">
<option
v-for="fruit in fruits"
:value="fruit">
{{fruit}}
</option>
</select>
radio
<input type="radio" v-model="value" value="男">
<input type="radio" v-model="value" value="女">
checkbox
<input type="checkbox" v-model="checks" value="游泳" >
<input type="checkbox" v-model="checks" value="健身">
修饰符应用 .number .lazy .trim
<input type="text" v-model.number="value">
<input type="text" v-model.trim="value">
Vue.config.keyCodes = {
'f1':112
}
计算属性和watch的区别 (异步)
let vm = new Vue({
el:'#app',
data:{
firstName:'姜',
lastName:'文',
fullName:''
},
mounted(){
this.getFullName();
},
methods:{
getFullName(){
this.fullName = this.firstName + this.lastName
}
},
watch:{
firstName(){
setTimeout(()=>{
this.getFullName();
},1000)
},
lastName(){
this.getFullName();
}
}
// 计算属性不支持异步
// computed:{
// fullName(){
// return this.firstName + this.lastName;
// }
// }
});
计算属性和 method的区别 (缓存)
<div>{{'hello' | capitalize(3)}}</div>
Vue.filter('capitalize',(value,count=1)=>{
return value.slice(0,count).toUpperCase() + value.slice(count);
});
编写一个自定义指令
钩子函数bind,inserted,update
<input type="text" v-focus.color="'red'">
Vue.directive('focus',{
inserted:(el,bindings)=>{
let color = bindings.modifiers.color;
if(color){
console.log('color')
el.style.boxShadow = `1px 1px 2px ${bindings.value}`
}
el.focus();
}
});
clickoutside指令
<div v-click-outside="change">
<input type="text" @focus="flag=true" >
<div v-show="flag">
contenter
</div>
</div>
let vm = new Vue({
el:'#app',
data:{
flag:false
},
methods:{
change(){
this.flag = false
}
},
directives:{
'click-outside'(el,bindings,vnode){
document.addEventListener('click',(e)=>{
if(!el.contains(e.target,vnode)){
let eventName = bindings.expression;
vnode.context[eventName]()
}
})
}
}
})
vue中的动画就是从无到有或者从有到无产生的。有以下几个状态 transition组件的应用
.v-enter-active,.v-leave-active {
transition: opacity 0.25s ease-out;
}
.v-enter, .v-leave-to {
opacity: 0;
}
切换isShow的显示或者隐藏就显示出效果啦~
<button @click="toggle">toggle</button>
<transition>
<span v-show="isShow">珠峰架构</span>
</transition>
默认的name是以v-开头,当然你可以自己指定name属性来修改前缀
.v-enter-active {
animation:zoomIn 2s linear
}
.v-leave-avitve{
animation:zoomOut 2s linear
}
直接修改激活时的样式
<transition
enter-active-class="zoomIn"
leave-active-class="zoomOut"
>
<span class="animated" v-show="isShow">珠峰架构</span>
</transition>
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
<span class="animated" v-show="isShow">珠峰架构</span>
</transition>
对应的钩子有before-leave,leave,after-leave钩子函数,函数的参数为当前元素
beforeEnter(el){
el.style.color="red"
},
enter(el,done){
setTimeout(()=>{
el.style.color = 'green'
},1000);
setTimeout(() => {
done();
}, 2000);
},
afterEnter(el){
el.style.color = 'blue';
}
<script src="node_modules/velocity-animate/velocity.js"></script>
beforeEnter(el){
el.style.opacity = 0;
},
enter(el,done){
Velocity(el, {opacity: 1}, {duration: 2000, complete: done})
},
afterEnter(el){
el.style.color = 'blue';
},
leave(el,done){
Velocity(el, {opacity: 0}, {duration: 2000, complete: done})
}
<div id="app">
<input type="text" v-model="filterData">
<transition-group
enter-active-class="zoomInLeft"
leave-active-class="zoomOutRight"
>
<div v-for="(l,index) in computedData" :key="l.title" class="animated">
{{l.title}}
</div>
</transition-group>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
filterData:'',
dataList:[
{title:'标题1'},
{title:'标题2'},
{title:'标题4'},
{title:'标题3'}
]
},
computed:{
computedData(){
return this.dataList.filter((item)=>{
return item.title.includes(this.filterData);
})
}
},
})
</script>
slot v-for i in 5