1.起步
引入:
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> -->
创建Vue实例
var vm = new Vue({
el:"#app"
data:{},//存放数据
methods:{}//方法
});
/*
el:用于获取需要的元素,一定是HTML中根容器元素
data:存储数据
methods:方法
*/
2.在dom结构中渲染Vue
<!--1.插值表达式-->
<p>名字:{{name}}</p>
<P>工作:{{job}}</p>
<!--2.调用greet()方法-->
<p>{{greet(morning)}}</p>
3.Vue指令
3-1 v-bind
绑定属性,可以用" : "代替
<a v-bind:href="website">百度</a>
可以简略的写为:
<a :href="website">百度</a>
3-2 v-on
- 绑定事件,可以简写为" @ "
<button v-on:click="add">加1</button>
- 鼠标移动事件v-on:mousemove
<div id="canvas" v-on:mousemove="updateXY">
{{x}},{{y}}
</div>
methods:{
updateXY:function(event){
this.x=event.offsetX;
this.y=event.offsetY;
}
}
- 使用v-on:click绑定点击事件,使用v-on:dblclick绑定双击事件
3-3 v-html
插入HTML内容
<p v-html="websiteTag"></p>
<script>
new Vue({
el:'#app',
data:{
websiteTag:'<a href="http://baidu.com">跳转百度</a>'
}
})
</script>
3-4 v-clock
防止页面加载时出现vue.js变量名,比如"<p>{{message}}</p>",在初始化页面时,没能很快的拿到message在vue实例中的值,则页面会直接显示"{{message}}",知道message的值被渲染进来
3-5.条件渲染
3-5-1.v-if
<h1 v-if="awesome">Vue is awesome!</h1>
v-if判断awesome是否为true,若为true则
若为false则不显示,html显示
3-5-2 v-else
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
tips:v-else
元素必须紧跟在带 v-if
或者 v-else-if
的元素的后面,否则它将不会被识别。
3-5-3 v-else-if
3-6 v-show
v-show与v-if的区别:
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
3-7 v-for
3-7-1遍历数组charcter
new Vue({
el:"#vueEvent",
data:{
character:['Mario','jack',"lucky"],
}
});
<div id="vueEvent">
<div v-for="c in character">
{{c}}
</div>
</div>
3-7-2遍历复合数组useres
用".属性"的方法来获取复合数组的具体值
new Vue({
el:"#vueEvent",
data:{
useres:[
{name:'Mario',job:'java',age:30},
{name:'jack',job:'c++',age:18},
{name:'lucky',job:'php',age:20}
]
}
});
<div id="vueEvent">
<div v-for="u in useres">
{{u.name}}-{{u.job}}-{{u.age}}
</div>
</div>
3-7-3 二次遍历
<div v-for="u in useres">
<div v-for="(val,key) in u">
{{key}}-{{val}}
</div>
</div>
问题提出,如此遍历下的代码产生很多空标签
解决方法,用<tempelate></tempelate>代替div来做代码的优化
<div v-for="u in useres">
<template v-for="(val,key) in u">
{{key}}-{{val}}
</template>
</div>
3-7 v-model
4.在vue中使用样式
使用class样式
- 对象语法:
<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
data: {
isActive: true,
hasError: false
}
- 数组语法:
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div> data: { activeClass: 'active', errorClass: 'text-danger' }
使用内联样式
-
直接在元素上通过
:style
的形式,书写样式对象<h1 :style="{color: 'red', 'font-size': '40px'}">这是一个善良的H1</h1>
-
将样式对象,定义到
data
中,并直接引用到:style
中<h1 :style="h1StyleObj">这是一个善良的H1</h1> data:{ h1StyleObj:{ color:'red', 'font-size':'24px' } }
-
在
:style
中通过数组,引用多个data
上的样式对象<h1 :style="[h1StyleObj, h1StyleObj2]">这是一个善良的H1</h1> data: { h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' }, h1StyleObj2: { fontStyle: 'italic' } }
5.事件修饰符
<!--stop:停止冒泡事件-->
<span v-on:mousemove.stop="">停止move</span>
<!--once:只能执行一次-->
<button v-on:click.once="">只能执行一次</button>
<!--prevent:阻止默认事件-->
<a v-on:click.prevent="" href="">点击不跳转到相应页面而是只执行click方法</a>
.stop
阻止单击事件继续传播.prevent
提交事件不再重载页面.capture 与事件冒泡的方向相反,事件捕获从内到外
.self
只会触发自己范围内的事件,不包含子元素.once
只触发一次.passive
6.键盘事件及键值修饰符
<input type="text" v-on:keyup="methods()">
<!--键入enter键之后才执行keyup事件-->
<input type="text" v-on:keyup.enter="methods()">
<!--键入enter键以及alt键之后才执行keyup事件-->
<input type="text" v-on:keyup.alt.enter="methods()">
7.双向数据绑定
7-1 通过ref属性
<div id="vueEvent">
<input type="text" ref="inputName" v-on:keyup="sysName">
<p>输出数据:{{name}}</p>
</div>
new Vue({
el:"#vueEvent",
data:{
name:""
},
methods:{
sysName:function(){
this.name=this.$refs.inputName.value;
}
}
});
7-2 通过v-model
<div id="vueEvent">
<input type="text" v-model="name">
<p>输出数据:{{name}}</p>
</div>
8.计算属性computed
问题:使用计算方法时,若在methods中写入方法,则存在每次触发事件都会从头到尾执行一遍所有方法的问题,如此特别耗费计算机的性能,由此引入computed,
new Vue({
el:"#elName",
data:{
a:0,
b:0
},
methods:{},
computed:{
addA:function(){
a++
}
addB:function(){
b++
}
}
});
9.vue动态绑定属性
通过给class名赋true/false值来实现
<p v-bind:class="test:false"></p>
绑定多个属性,可以通过computed方法里面返回多个属性值来实现
<button v-on:click="changeColor = !changeColor">改变颜色</button>
<div v-bind:class="compClass">
<span>测试样式</span>
</div>
span{
background:red;
display: inline-block;
padding:10px;
color:#fff;
margin:10px 0px;
}
.changeColor span{
background:green;
}
.changeLength span:after{
content:"length";
margin-left:10px;
}
new Vue({
el:"#vueEvent",
data:{
changeColor:false,
changeLength:false
},
methods:{
},
computed:{
compClass:function(){
return {
changeColor:this.changeColor
}
}
}
});
10.vue组件
Vue.component('my-component-name', { /* ... */ })
11.vue搭建脚手架CLI
11-1 简介
- 脚手架是通过webpack搭建的开发环境
- 使用ES6语法
- 打包和压缩js文件为一个文件bundle.js
- 项目文件在环境中编译,而不是浏览器->速度快
- 实现页面自动刷新
11-2 环境搭建node.js
11-2-1.npm安装
npm安装教程:https://www.cnblogs.com/goldlong/p/8027997.html
补充:
出现警告:npm WARN ajv-keywords@3.4.0 requires a peer of ajv@^6.9.1 but none is installed.you must installed peer dependencies youselfs.
解决方法:安装ajv@^6.9.1(根据警告内容) ,输入 npm install ajv@^6.9.1.
12.属性传值
12-1 使用props从父组件到子组件传值
12-1-1.父组件定义数据employee
export default {
name: 'App',
components:{
'Home':Home
},
data(){
return {
employee:[
{name:"henrry",job:"web engineer"},
{name:"henrry",job:"web engineer"},
{name:"henrry",job:"web engineer"},
{name:"henrry",job:"web engineer"},
{name:"henrry",job:"web engineer"},
{name:"henrry",job:"web engineer"}
],
title:"这是标题"
}
}
}
12-1-2.父组件在引用子组件标签处通过v-bind绑定数据
<Home v-bind:test="employee"></Home>
12-1-3.子组件定义props
export default {
name: 'home',
props:{
test:{
type:Array,
require:true
}
}
}
12-2 子组件向父组件传值
或者说调用父组件的方法
<div id="app">
<!--1. 父组件引用子组件的标签处绑定一个func方法 -->
<mycom @func="show"></mycom>
</div>
<template id="temp1">
<div>
<h3>子组件文本</h3>
<!-- 2.子组件绑定一个click事件 -->
<input type="button" value="触发父组件方法" v-on:click="clickEvent">
</div>
</template>
<script>
var mycom = {
template:'#temp1',
data:function(){
return{
msg:'子组件传递的信息'
}
},
methods:{
clickEvent(){
<!-- 3.用$emit调用父组件的方法并且传递参数 -->
this.$emit('func',this.msg);
}
}
};
new Vue({
el:'#app',
data:{},
methods:{
show(msg){
console.log('父组件show方法调用---打印子组件数据:'+msg);
}
},
components:{
mycom
}
});
</script>
在调用组件是用func绑定父组件的show方法,之后在子组件中用this.$emit调用show方法
13.生命周期
new vue({
el:"#app",
data:{},
methods:{
},
beforeCreate:function(){
//组件实例化前执行的函数
},
created:function(){
//组件实例化完毕,但页面还未显示
},
beforeMount:function(){
//组件挂载前,页面仍未展示,但虚拟DOM已经配置
},
mounted:function(){
//组件挂载后,此方法执行后,页面显示
},
beforeUpdate:function(){
//组件更新前,页面仍未更新,但虚拟DOM已经配置
},
updated:function(){
//组件更新,此方法执行后,页面显示
},
beforeDestory:function(){
//组件销毁前
},
destoryed:function(){
//组件销毁
}
});
14.vue路由与HTTP
14-1 vue路由
14-1-1 安装路由
npm install vue-router --save
14-1-2 代码
main.js
//1.引入路由
import VueRouter from 'vue-router'
//2.使用路由
Vue.use(VueRouter)
//3.配置路由
const router = new VueRouter({
routes:[
{path:"/",component:Home},
{path:"/helloworld",component:HelloWorld}
],
mode:"history"//区别在于localhost:8080与localhost:8080/#/的页面是否一致
})
//4.使用路由
new Vue({
router,
el: '#app',
...
})
App.vue
<div id="App">
<router-view></router-view>
</div>
使用<router-link>标签实现无刷新页面,区别于a标签实现的刷新跳转
<div id="app">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/helloworld">HelloWorld</a></li>
</ul>
<ul>
<li><router-link to="/">Home</router-link></li>
<li><router-link to="/helloworld">HelloWorld</router-link></li>
</ul>
<router-view></router-view>
</div>
14-2 vue与http
14-2-1 安装resource
npm install vue-resource --save
14-2-2 代码
main.js
//1.引入resource
import VueResource from 'vue-resource'
//2.使用resource
Vue.use(VueResource)
HelloWorld.vue
//3.遍历获取的employee
<template>
<div id="home">
<h1 v-for="u in employee">{{u.name}}</h1>
</div>
</template
//1.定义获取数据的一个空数组employee
<script>
export default {
name: 'home',
data(){
return {
employee:[
]
}
},
//2.从http://jsonplaceholder.typicode.com/users获取数据
created(){
this.$http.get("http://jsonplaceholder.typicode.com/users")
.then((data)=>{
// console.log(data)
this.employee=data.body;
})
}
</script>
tips:获取到的data
15.二级路由、三级路由
15-1 二级路由
1.main.js引入路由路径
2.找到一级路由并配置children数组
export const routes=[
{path:'/about',component:About ,children:[
{path:'/about/contack',name:"contackLink",component:Contack},
{path:'/history',name:"historyLink",component:History},
{path:'/deliver',name:"deliverLink",component:Deliver},
{path:'/orderGuide',name:"orderGuideLink",component:OrderGuide}
] }
]
15-2 三级路由同理
16.导航守卫
16-1 全局前置守卫
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。
main.js
//全局守卫
router.beforeEach((to,from,next) => {
//console.log(to);
if(to.path ==="/login"||to.path==="/register"){
next();
}else{
alert("还没有登录,请先登录");
next("/login");
}
});
next: Function
: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next
方法的调用参数。
next()
: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。next(false)
: 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from
路由对应的地址。next('/')
或者next({ path: '/' })
: 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向next
传递任意位置对象,且允许设置诸如replace: true
、name: 'home'
之类的选项以及任何用在router-link
的to
prop 或router.push
中的选项。next(error)
: (2.4.0+) 如果传入next
的参数是一个Error
实例,则导航会被终止且该错误会被传递给router.onError()
注册过的回调。
16-2 全局后置钩子
和守卫不同的是,这些钩子不会接受 next
函数也不会改变导航本身
router.afterEach((to, from) => {
// ...
})
16-3 路由独享的守卫
1.通过配置
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
2.直接写在path中
const routes=[
{path:'/login',component:Login,beforeEnter:(to,from,next) =>{
alert("路由独享守卫");
}
}
]
16-4 组件内的守卫
<template>
<h1>Login</h1>
</template>
<script>
export default{
data(){
return{
name:'Henry'
}
},
beforeRouteEnter:(to,from,next) =>{
alert("Hello,"+this.name);
}
}
</script>
问题:this.name无法获取data里面的name值。原因是beforeRouteEnter守卫在导航确认前被调用,因此即将登场的新组件还没被创建。
因此,通过传一个回调给 next
来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数.
<template>
<h1>Login</h1>
</template>
<script>
export default{
data(){
return{
name:'Henry'
}
},
beforeRouteEnter:(to,from,next) =>{
next(vm => {
alert("Hello,"+vm.name);
});
}
}
</script>