Vue框架学习笔记
Vue.js是目前最火的一个前端框架,React是最流行的前端框架(React除了开发网站,还可以开发手机App。Vue需要借助于Weex)
前端三大主流框架
- Angular.js
- React.js
- Vue.js
开发思想
- 后端MVC
- 前端MVVM(数据的双向数据绑定由VM提供)
- M:保存每个页面中单独的数据
- VM:调度者,分割了M和V
- V:就是每个页面中的HTML结构
var vm = new Vue({
el: '#app',
data: {
},
methods: {
},
filters: {},
directives: {},
components: {},
//生命周期钩子函数
beforeCreate() {
},
created() {
},
beforeMount() {
},
mounted() {
},
beforeUpdate() {
},
updated() {
},
beforeDestroy() {
},
destroyed() {
},
});
- component
- template
- transition
- transitionGroup
v-cloak
网速过慢时防止页面显示未编译的 Mustache 标签,即闪烁问题
<!-- CSS --> [v-cloak] { display: none; }
<!-- HTML --> <div v-cloak> {{ message }} </div>
v-text
与{{ msg }}效果相同,区别是没有闪烁问题,且会覆盖元素中内容
v-html
可以输入html,v-text与{{ msg }}(插值表达式)则会将内容转意输出
v-bind:
提供属性绑定的功能,也可以简写成 :要绑定的属性
<!-- HTML --> <img v-bind:src="imageSrc"> <button v-bind:[key]="value"></button>
v-on:
提供事件绑定功能,也可以简写成 @c
例如: v-on:click="show" or #click="show" 或者 v-on:mouseover="show" methods: { show: function () { alert('Hello') } }
跑马灯效果
<input type="button" value="浪起来" @click="lang"> <input type="button" value="低调" @click="stop"> data: { msg: '猥琐发育,别浪~~!', intervalId: null, }, methods: { lang(){ // console.log(this.msg); if (this.intervalId != null) return; this.intervalId= setInterval(() => { var start = this.msg.substring(0, 1); var end = this.msg.substring(1); this.msg = end + start; }, 400) }, stop(){ clearInterval(this.intervalId); this.msg = '猥琐发育,别浪~~!'; this.intervalId = null; } }
.stop
阻止事件冒泡@click.stop
<div class="inner" @click="div1Handler"> <input type="button" value="戳他" @click.stop="btnHandler"> </div>
.prevent
阻止默认事件
<a href="http://www.baidu.com" @click.prevent="linkClick">有问题,找百度</a>
.capture
使用事件捕获模式
<!-- 顺序改变为div->input --> <div class="inner" @click.capture="div1Handler"> <input type="button" value="戳他" @click="btnHandler"> </div>
.self
只当事件在该元素本身触发时才触发回调
<div class="inner" @click.self="div1Handler"> <input type="button" value="戳他" @click="btnHandler"> </div>
.once
事件只触发一次
<!-- 第二次点击时还是会跳转 --> <a href="http://www.baidu.com" @click.prevent.once="linkClick">有问题,找百度</a>
v-model
Vue中唯一的一个双向数据绑定的指定,只能运用在表单元素中
<input type="text" v-model="msg" style="width: 100%">
class样式
数组
<h1 :class="['thin', 'italic', 'red']">这是一个很大很大的H1,大到你无法想象!!!</h1>
数组中使用三元表达式
<h1 :class="['thin', 'italic', flag?'active':'']">这是一个很大很大的H1,大到你无法想象!!!</h1>
在数组中使用对象
<h1 :class="['thin', 'italic', {'active':flag}]">这是一个很大很大的H1,大到你无法想象!!!</h1>
直接使用对象
<h1 :class="{red:true, thin:false, italic:false, active:false}">这是一个很大很大的H1,大到你无法想象!!!</h1>
或者
<h1 :class="classObj">这是一个很大很大的H1,大到你无法想象!!!</h1> data: { classObj: {red:true, thin:false, italic:false, active:false}, },
```
使用内联样式style
通过对象
<h1 :style="styleObj">这是一个H1</h1> data: { styleObj: {color: 'red', 'font-weight': 200}, }
通过数组,引用多个对象
<h1 :style="[styleObj, styleObj2]">这是一个H1</h1> data: { styleObj: {color: 'red'}, styleObj2: {'font-weight': 200}, }
v-for指令
使用v-for循环是最好加入:key属性。(只接受string/number)它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用:
- 完整地触发组件的生命周期钩子
- 触发过渡
循环普通数组
<p v-for="(item, i) in list">{{ item}}-{{i}}</p> data: { list: ['a', 'b', 'c', 'b', 'e', 'f'] }
循环对象数组
<p v-for="(user, i) in list">{{ user.id}} --- {{user.name}} ---索引: {{i}}</p> data: { list: [ {id:1, name: 'zs1'}, {id:2, name: 'zs2'}, {id:3, name: 'zs3'}, {id:4, name: 'zs4'}, ] }
循环对象(也可以第三项加上索引)
<p v-for="(val, key) in user">{{ val }} --- {{ key }}</p> data: { user: { id: 1, name: '托尼·诗达克', gender: '男' } }
迭代数次(v-for中迭代从1开始)
<p v-for="count in 10">这是第 {{count}} 次循环</p>
<input type="button" value="toggle" @click="flag= !flag">
<h3 v-if="flag">这是用v-if控制的元素</h3>
<h3 v-show="flag">这是用v-show控制的元素</h3>
- v-if的特点,每次都会重新删除或创建元素。切换性能消耗较高。
- v-show的特点,每次不会重新进行DOM的删除和创建操作,只影响display:none样式。初始渲染性能消耗较高。
{{ name | 过滤器的名称 }}
Vue.filter('过滤器的名称', function(data){
return data + '123';
})
调用过滤器的时候,采用就近原则,名称一样,优先调用局部
- 全局过滤器
<p>{{ msg | msgFormat('疯狂')}}</p>
Vue.filter('msgFormat', function (data, arg) {
return data.replace(/单纯/g, arg);
});
- 局部过滤器
methods: {}
filters: { ... }
自定义全局按键修饰符
Vue.config.keyCodes.f2 = 113
绑定键盘事件
<input type="text" class="form-control" id="inputPassword2" v-model="name" @keyup.f2="add">
全局用单数,局部用复数
定义一个v-focus指令
<input type="text" class="form-control" id="inputPassword3" v-model="keywords" v-focus>
Vue.directive('focus', {
bind: function (el) {
},
inserted: function (el) {
el.focus()
},
updated: function (el) {
}
});
创建阶段
有四个生命周期函数
beforeCreate()
create()
beforeMount()
mounted()
beforeCreate(){ console.log('beforeCreate,现在还不能调用data和methods'); }, created(){ console.log('created,现在可以调用data和methods:'); console.log(this.msg); this.show() }, beforeMount(){ console.log(document.getElementById('h3').innerText); console.log('beforeMount,现在模板已经在内存中编译好了,尚未挂载到页面中去'); }, mounted(){ console.log('mounted,现在模板已经真实的挂载到页面中去'); }
运行阶段
此阶段只有2个生命周期函数
beforeUpdate
updated
beforeUpdate(){ console.log('beforeUpdate,修改才会触发'); console.log('界面上元素的内容:'+document.getElementById('h3').innerText);//此时页面数据是旧的 console.log('data中的msg数据是:'+this.msg);//data中的数据已被更新 }, updated(){ console.log('updated,修改才会触发'); console.log('界面上元素的内容:'+document.getElementById('h3').innerText);//此时页面数据已被更新 console.log('data中的msg数据是:'+this.msg);//data中的数据已被更新 }
销毁阶段
此阶段有两个生命周期函数
- beforeDestroy(此时data和methods以及过滤器、指令都处于可用状态)
- destroyed(此时组件已被完全销毁,data和methods以及过滤器、指令都不可用)
引入Vue-resource文件
实例:
<div id="app">
<input type="button" value="get请求" @click="getinfo">
<input type="button" value="post请求" @click="postinfo">
</div>
methods: {
getinfo(){
this.$http.get('user.php').then(function (result) {
console.log(result);
})
},
postinfo(){
this.$http.post('user.php', {}, {emulateJson:true}).then(result=>{
console.log(result.body);
})
}
}
Vue 提供了
transition
的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡
- 条件渲染 (使用
v-if
)- 条件展示 (使用
v-show
)- 动态组件
- 组件根节点
v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。v-enter-to
: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时v-enter
被移除),在过渡/动画完成之后移除。v-leave
: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。v-leave-to
: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时v-leave
被删除),在过渡/动画完成之后移除。
通过style实现动画
<style>
.v-enter, .v-leave-to {
opacity: 0;
transform: translateX(150px);
}
.v-enter-active, .v-leave-active{
transition: all 0.8s ease;
}
.my-enter, .my-leave-to {
opacity: 0;
transform: translateY(150px);
}
.my-enter-active, .my-leave-active{
transition: all 0.8s ease;
}
</style>
<div id="app">
<input type="button" value="toggle" @click="flag=!flag">
<transition>
<h3 v-if="flag">这是一个H3</h3>
</transition>
<hr>
<input type="button" value="toggle" @click="flag2=!flag2">
<transition name="my">
<h6 v-if="flag2">这是一个H6</h6>
</transition>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
flag: false,
flag2: false
}
})
</script>
通过第三方库Animate实现动画
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.2/animate.min.css">
<div id="app">
<input type="button" value="toggle" @click="flag=!flag">
<transition enter-active-class="animated bounceIn" leave-active-class="animated bounceOut" :duration="1000">
<h3 v-if="flag">这是一个H3</h3>
</transition>
</div>
JavaScript 钩子
<transition
v-on:before-enter="beforeEnter" //动画开始之前的起始位置
v-on:enter="enter" //动画开始之后的结束位置
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
<!-- ... -->
</transition>
<div id="app">
<input type="button" value="快到碗里来" @click="flag=!flag">
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
<div class="ball" v-show="flag"></div>
</transition>
</div>
methods: {
beforeEnter(el){
el.style.transform = "translate(0, 0)"
},
enter(el, done){
el.offsetWidth;//强制浏览器刷新
el.style.transform = "translate(150px, 450px)";
el.style.transition = 'all 1s ease';
done();//这个done其实就是afterEnter函数,如果不调用会产生延迟
},
afterEnter(el){
this.flag = !this.flag;
}
}
在列表过度时,需使用
包裹
<style>
li {
border: 1px dashed #999;
margin: 5px;
line-height: 35px;
padding-left: 5px;
font-size: 12px;
}
li:hover {
background-color: hotpink;
transition: all 0.8s ease;
}
.v-enter, .v-leave-to {
opacity: 0;
transform: translateY(80px);
}
.v-enter-active, .v-leave-active {
transition: all 0.6s ease;
}
</style>
<ul>
<transition-group>
<li v-for="item in list" :key="item.id">
{{item.id}} --- {{ item.name}}
</li>
</transition-group>
</ul>
methods: {
add() {
this.list.push({id: this.id, name: this.name});
this.id = this.name = '';
}
}
列表的排序过度
.v-move {
transition: all 0.8s ease;
}
.v-leave-active {
position: absolute;
}
给transition-group添加appear属性,实现入场效果。 tag属性则是指定transition-group渲染成什么标签,默认为
<transition-group appear tag="ul">
<li v-for="(item, i) in list" :key="item.id" @click="del(i)">
{{item.id}} --- {{ item.name}}
</li>
</transition-group>
什么是组件,组件的出现就是为了拆分Vue实例,减少代码量,划分不同的功能模块。注意:组件的template属性指向的模板内容,必须有且只能有唯一的一个根元素
- 通过Vue.extend()定义一个组件
<div id="app">
<my-com1></my-com1>
</div>
<script>
var com1 = Vue.extend({
template: '<h3>这是使用Vue.extend创建的组件</h3>',
});
Vue.component('myCom1', com1);
var vm = new Vue({
el: '#app',
data: {
},
methods: {
}
});
</script>
直接使用Vue.component创建组件
Vue.component('myCom2', { template: '<h3>直接使用Vue.component创建出来的组件</h3>' });
在被控制的#app外面。使用template元素
<template id="tmp1"> <div> <h1>这是通过template元素,在外部定义的组件结构</h1> <h4>好用</h4> </div> </template> Vue.component('myCom3', { // template: '#tmp1' });
组件中的data
组件可以有data数据,使用方式和实例data完全一样,但实例中的data可以为一个对象,组件中的data必须为一个方法,且返回对象。
Vue.component('mycom1', { template: '<h1>这是全局组件</h1>', data: function () { return { msg: '这是组件中data定义的数据' }; } });
通过v-if和v-else
<login v-if="flag"></login> <register v-else="flag"></register> <script> // var dataObj = { count: 0}; Vue.component('login', { template: '<h3>登录组件</h3>' }); Vue.component('register', { template: '<h3>注册组件</h3>' }); var vm = new Vue({ el: '#app', data: { flag: false, }, methods: {} }); </script>
通过Vue提供的
来展示对应名称的组件 component是一个占位符, :is属性可以用来指定要展示组件的名称
<div id="app"> <a href="" @click.prevent="comName='login'">登录</a> <a href="" @click.prevent="comName='register'">注册</a> <component :is="comName"></component> </div> <script> // var dataObj = { count: 0}; Vue.component('login', { template: '<h3>登录组件</h3>' }); Vue.component('register', { template: '<h3>注册组件</h3>' }); var vm = new Vue({ el: '#app', data: { comName: 'login', }, methods: {} }); </script>
在
外包裹 即可
<style>
.v-enter, .v-leave-to {
opacity: 0;
transform: translateX(150px);
}
.v-enter-active, .v-leave-active {
transition: all 0.5s ease;
}
</style>
<transition mode="out-in">
<component :is="comName"></component>
</transition>
- 父组件向子组件传值
首先父组件通过v-bind:传递属性的方式传递给子组件,然后在子组件中定义一个props数组,定义次属性,才能使用这个数据。(props里的数据是只读的,data中的数据才可写)
<div id="app">
<com1 v-bind:parentmsg="msg"></com1>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: '123 啊-父组件的数据'
},
methods: {},
components: {
com1: {
template: '<h1>这是子组件---{{parentmsg}}</h1>',
props: ['parentmsg'],
}
}
});
</script>
父组件向子组件传递方法
首先父组件通过v-on:向子组件传递一个事件,子组件自定义一个方法,并在方法中通过this.$emit('方法名称')接收父组件的方法
<div id="app"> <com2 @func="show"></com2> </div> <template id="tmp1"> <div> <h1>这是子组件</h1> <input type="button" value="触发" @click="myclick"> </div> </template> var com2 = { template: '#tmp1', methods: { myclick(){ this.$emit('func'); } } };
<div id="app">
<input type="button" value="获取元素" @click="getElement">
<h3 id="myh3" ref="myh3">哈哈哈,今天天气太好了!!!</h3>
<hr>
<login ref="mylogin"></login>
</div>
<script>
var login = {
template: '<h1>登录组件</h1>',
data() {
return {
msg: 'son msg'
}
},
methods: {
show() {
console.log('调用了子组件的方法');
}
}
};
var vm = new Vue({
el: '#app',
data: {},
methods: {
getElement() {
console.log(this.$refs.mylogin.show());
}
},
components: {
login
}
});
</script>
- 后端路由: 通过URL地址来请求服务器上对应的资源。
- 前端路由: 通过URL中的hash(#号)来实现不同页面之间的切换。这种通过hash改变来切换页面的方式,称作前端路由。
Laravel项目中导入vue-router
//在项目根目录安装vue-router yarn add vue-router //在resources/js/app.js中导入vue-router require('./bootstrap'); window.Vue = require('vue'); import VueRouter from 'vue-router'//新加 Vue.use(VueRouter);//新加 var router = new VueRouter({ //每个路由规则,都是一个对象。属性1是path,表示监听哪个路由链接地址、属性2是component,表示展示哪个组件 routes: [ {path: '/', component: require('./components/FirstPage').default}, {path: '/coreadvantages', component: require('./components/CoreAdvantages').default}, ], linkActiveClass: 'jingjiu-home-active' //选中时增加的类名 }); const app = new Vue({ el: '#app', data: { }, methods: {}, router, //相当于router: router });
在laravel中引入elementui
//安装 yarn add element-ui -S //在resources/js/app.js文件中加入: import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI); //然后在组件模板中就可以使用了
基本实例
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.js"></script> <div id="app"> <a href="#/login">登录</a> <a href="#/register">注册</a> <!-- 这是vue-router提供的元素,当做路由规则占位符--> <router-view></router-view> </div> <script> //组件的模板对象 var login = { template: '<h1>登录组件</h1>' }; var register = { template: '<h1>注册组件</h1>' }; //创建一个路由对象,可以为VueRouter构造函数传递一个配置对象 var routerObj = new VueRouter({ //每个路由规则,都是一个对象。属性1是path,表示监听哪个路由链接地址、属性2是component,表示展示哪个组件 routes: [ {path: '/login', component: login}, {path: '/register', component: register}, ] }); var vm = new Vue({ el: '#app', data: { }, methods: {}, router: routerObj,//将路由规则对象注册到vm实例上 }); </script>
使用
代替a标签 <router-link to="/login" tag="span">登录</router-link> <router-link to="/register">注册</router-link> <router-view></router-view>
选中路由设置样式
在路由构造函数设置linkActiveClass的值,改变选中时的类名
<style> .router-link-active, .myactive { color: red; font-weight: 800; font-style: italic; font-size: 80px; text-decoration: underline; background-color: green; } </style> var routerObj = new VueRouter({ //每个路由规则,都是一个对象。属性1是path,表示监听哪个路由链接地址、属性2是component,表示展示哪个组件 routes: [ {path: '/', redirect: '/login'}, {path: '/login', component: login}, {path: '/register', component: register}, ], linkActiveClass: 'myactive',//激活时的类 });
为路由组件添加动画
<style> v-enter, .v-leave-to { opacity: 0; transform: translateX(140px); } .v-enter-active, .v-leave-active { transition: all 0.5s ease; } </style> <div id="app"> <router-link to="/login" tag="span">登录</router-link> <router-link to="/register">注册</router-link> <transition mode="out-in"> <router-view></router-view> </transition> </div>
路由传参-使用query方式
<div id="app"> <router-link to="/login?id=10&name=zhangsan">登录</router-link> <router-view></router-view> </div> var login = { template: '<h1>登录 --- {{ $route.query.id}} --- {{ $route.query.name}}</h1>', data(){ return { msg: '123' } }, created() { console.log(this.$route.query.id) } }; var router = new VueRouter({ routes: [ {path: '/login', component: login}, ] });
路由传参-使用params方式
<div id="app"> <router-link to="/login/12/zhao">登录</router-link> <router-link to="/register">注册</router-link> <router-view></router-view> </div> var login = { template: '<h1>登录 --- {{ $route.params.id}} --- {{ $route.params.name}}</h1>', data(){ return { msg: '123' } }, created() { console.log(this.$route) } }; var router = new VueRouter({ routes: [ {path: '/login/:id/:name', component: login}, ] });
用children属性实现路由嵌套
<template id="tmp1"> <div> <h1>这是Account组件</h1> <router-link to="/account/login">登录</router-link> <router-link to="/account/register">注册</router-link> <router-view></router-view> </div> </template> <script> var account = { template: '#tmp1' }; var login = { template: '<h3>登录 </h3>', }; var register = { template: '<h3>注册</h3>' }; var router = new VueRouter({ routes: [ { path: '/account', component: account, children: [ {path: 'login', component: login}, {path: 'register', component: register}, ] }, ] }); var vm = new Vue({ el: '#app', data: {}, methods: {}, router, }); </script>
实现路由经典布局
通过
的name属性来控制 <style> .header { background-color: orange; height: 80px; } .container { display: flex; height: 400px; } h1 { margin: 0; padding: 0; font-size: 16px; } .left { background-color: lightgreen; flex: 2; } .main { background-color: lightpink; flex: 8; } </style> <div id="app"> <router-view></router-view> <div class="container"> <router-view name="left"></router-view> <router-view name="main"></router-view> </div> </div> <script> var header = { template: '<h1 class="header">Header头部区域</h1>' }; var leftBox = { template: '<h1 class="left">Left侧边栏区域</h1>' }; var mainBox = { template: '<h1 class="main">main主体区域</h1>' }; var router = new VueRouter({ routes: [ { path: '/', components: { default: header, left: leftBox, main: mainBox, } }, ] }); var vm = new Vue({ el: '#app', data: {}, methods: {} , router }); </script>
使用watch监听数据的改变
<div id="app"> <input type="text" v-model="firstname"> + <input type="text" v-model="lastname"> = <input type="text" v-model="fullname"> </div> <script> var vm = new Vue({ el: '#app', data: { firstname: '', lastname: '', fullname: '', }, methods: { }, watch: { firstname: function (newVal, oldVal) { // this.fullname = this.firstname + '-' + this.lastname; this.fullname = newVal + '-' + this.lastname; }, lastname: function (newVal, oldVal) { // this.fullname = this.firstname + '-' + this.lastname; this.fullname = this.firstname + '-' + newVal; }, } }); </script>
使用computed计算属性监听数据(会缓存,当做属性来使用)
只要计算属性在这个function的内部,只要其中的任何data中的数据发生了变化,就会重新计算这个值。
<div id="app"> <input type="text" v-model="firstname"> + <input type="text" v-model="middlename"> + <input type="text" v-model="lastname"> = <input type="text" v-model="fullname"> </div> computed: { 'fullname': function () { console.log('ok'); return this.firstname + '-' + this.middlename+'-' + this.lastname; } }
相关文章
- Vue框架学习笔记
Vue.js是目前最火的一个前端框架,React是最流行的前端框架(React除了开发网站,还可以开发手机App。Vue需要借助于Weex) 前端三大主流框架 Angular.js Reac
- vue-postcss-px2rem实现px转re
安装 lib-flexible postcss-px2rem postcss postcss-loader webpack.base.conf.js以下配置 const webpack = req
- Vue中解决v-html事件无效问题
1.Vue 项目中解决 V-html 中事件无效问题 html <template> <div ref="htmlCode"> </div> </te
- Vue单元测试踩坑
单元测试的重要性,在这里就不过多阐述了。 这篇文章主要记录在vue项目中引入单元测试遇到的一些问题以及解决方案。 项目背景: 引入一些第三方库,如: element-ui组件库 echarts图表库
随机推荐
- Vue框架学习笔记
Vue.js是目前最火的一个前端框架,React是最流行的前端框架(React除了开发网站,还可以开发手机App。Vue需要借助于Weex) 前端三大主流框架 Angular.js Reac
- vue-postcss-px2rem实现px转re
安装 lib-flexible postcss-px2rem postcss postcss-loader webpack.base.conf.js以下配置 const webpack = req
- Vue中解决v-html事件无效问题
1.Vue 项目中解决 V-html 中事件无效问题 html <template> <div ref="htmlCode"> </div> </te
- Vue单元测试踩坑
单元测试的重要性,在这里就不过多阐述了。 这篇文章主要记录在vue项目中引入单元测试遇到的一些问题以及解决方案。 项目背景: 引入一些第三方库,如: element-ui组件库 echarts图表库