6.Vue
6.1.Vue介绍
- Vue.js—— 渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计。Vue 的核心库只关注视图层,并且非常容易学习,非常容易与其它库或已有项目整合。另一方面,Vue 完全有能力驱动采用单文件组件和Vue生态系统支持开发复杂单页应用。
- 渐进式:从核心到完备的全家桶
- 增量:从少到多,从一页到多页,从简单到复杂
- 单文件组件:一个文件描述一个组件
- 单页应用:经过打包生成一个单页的html文件和一些js文件
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>快速入门</title> <!-- 不下载或创建js文件,直接引用,为防止url更改或失效,个人觉得尽量避免使用这种方式 --> <!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> --> <!-- 引用Vue的js文件(文件中的代码已经提前编译好),注意路径问题 --> <script src="vue.js"></script> </head> <body> <div id="app"> {{message}} </div> <script> new Vue({ el:'#app', //表示当前vue对象接管了div区域 data:{ message:'hello world' //注意不要写分号结尾 } }); </script> </body> </html> <!-- 页面显示的是hello world,把原本的内容替换掉了,div中的字符串形式我们称为插值表达式 -->
使用Vue的js文件之前,记得先引用
6.2.插值表达式
- 数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值,Mustache 标签将会被替代为对应数据对象上属性的值。无论何时,绑定的数据对象上属性发生了改变,插值处的内容都会更新。
- Vue.js 都提供了完全的 JavaScript 表达式支持。这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式
//下面的两个表达式都可以 {{ number + 1 }} {{ ok ? 'YES' : 'NO' }} //下面的不会生效 <!-- 这是语句,不是表达式 --> {{ var a = 1 }} <!-- 流控制也不会生效,请使用三元表达式 --> {{ if (ok) { return message } }}
6.3.VueJS 常用系统指令(V指令)
6.3.1.V-bind: 单向绑定
- v-bind: 单向绑定, 在html中使用v-bind: 给一个html属性绑定一个参数, 这个参数是对应vue对象中自定义的参数
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>v-bind</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app">
<font size="5" v-bind:color="ys1">Java</font>
<font size="5" :color="ys2">C++</font>
<hr>
<a v-bind={href:"http://www.baidu.com/s/wd=" + id}>itcast</a>
</div>
<script>
new Vue({
el:'#app', //表示当前vue对象接管了div区域
data:{
ys1:"red",
ys2:"green",
id:1
}
});
</script>
</body>
</html>
对于上述Vue代码,过程可以解析如下:
- 创建了一个Vue对象(根据Vue语法)
- 这个Vue对象一旦创建, 会立即检查 它的el属性,
- 他会根据el属性找到一个对应id的html代码
- 如果找到了, 把找到的html代码所对应的作用域 和 这个Vue对象’绑定起来’
- 这个html代码所对应的作用域 就不在仅仅是html代码作用域, 还是这个Vue对象作用域
- 这个作用域代码 会重新, 按照Vue语法再解析一边
- Vue固有属性
- el
- data
- computed
6.3.2.V-model: 双向绑定
- v- model: 双相绑定,在html中表单的value上使用,一个表单的value属性绑定一个参数,这个参数是对应vue对象中自定义的参数。
- 如果绑定之后, 表单元素的vulue发生了改变, 那么, 对应自定义属性也会发生改变。
- v-model绑定的是data的key值,也就是属性里的数据,表单元素的输入影响了数据,进而影响了div里的插值表达式。
只能用于表单元素的value上
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>v-model</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app">
姓名:<input type="text" id="username" v-model="user.username"><br>
密码:<input type="password" id="password" v-model="user.password"><br>
<input type="button" @click="fun" value="获取">
</div>
<script>
new Vue({
el:'#app', //表示当前vue对象接管了div区域
data:{
user:{username:"",password:""}
},
methods:{
fun:function(){
alert(this.user.username+" "+this.user.password);
this.user.username="tom";
this.user.password="11111111";
}
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
</head>
<body>
<div id="root">
{{num}}
<input v-bind:value="num">
<select v-model="num">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<textarea v-model="num"></textarea>
<input v-model:value="num">
<!-- value可以省略不写 -->
<input v-model="num">
</div>
<script>
new Vue({
el: "#root",
data: {
num: 2
}
})
</script>
</body>
</html>
6.3.3.v-text、v-html
- 和innerText innerHTML 几乎一样
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
</head>
<body>
<div id="root">
<div v-text="obj.name">
<!-- {{obj.name}}-->
</div>
<div v-text="obj.age">
<!-- {{obj.age}}-->
</div>
<div v-html="obj.name">
<!-- {{obj.name}}-->
</div>
<div v-html="obj.age">
<!-- {{obj.age}}-->
</div>
</div>
<script>
new Vue({
el: "#root",
data: {
obj:{
name: "<b>zs</b>",
age: 18
}
}
})
</script>
</body>
</html>
6.3.4.v-show
- 隐藏和显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
</head>
<body>
<div id="root">
<div v-show="bool">
<img src="https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3363295869,2467511306&fm=26&gp=0.jpg">
</div>
<!-- 触发Vue对象里的点击事件,其中@是v-on的简写 -->
<button @click="changeimg">改变</button
<!-- 触发js里的点击事件 -->
<button onclick="f()">另一种改变</button>
</div>
<script>
new Vue({
el: "#root",
data: {
bool: false
},
methods: {
changeimg: function () {
this.bool = ! this.bool
}
}
})
//无法访问到Vue对象的bool值
function f(){
alert("非Vue对象的方法")
}
</script>
</body>
</html>
6.3.5.v-if、v-else-if、v-else
- 分支结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
</head>
<body>
<div id="root">
<div v-if="bool1">
v-if
</div>
<div v-else-if="bool2">
v-else-if
</div>
<div v-else>
v-else
</div>
<div v-if="1==2">
表达式判断1==2
</div>
<div v-if="1==1">
表达式判断1==1
</div>
</div>
<script>
new Vue({
el: "#root",
data: {
bool1: true,
bool2: true
}
})
</script>
</body>
</html>
6.3.6.v-on事件监听
- 可以用v-on指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码, 监听到的时间要触发到vue对象中去: methods里面
- v-on:click
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
</head>
<body>
<div id="root">
<div v-show="bool">
<img src="https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3363295869,2467511306&fm=26&gp=0.jpg">
</div>
<!-- v-on: 可以简写为@ -->
<button v-on:click="f">改变</button>
<button @click="f"> 改变</button>
</div>
<script>
new Vue({
el: "#root",
data: {
bool: false
},
methods: {
f: function () {
// 一定要加this
this.bool = !this.bool
}
}
})
function f() {
alert('?')
}
</script>
</body>
</html>
- v-on:keydown
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>事件处理</title>
<script src="vue,js"></script>
</head>
<body>
<div id="app">
<input type="text"v-on:keydown="fun('good',$event)">
</div>
<script>
new Vue({
el:'#app', //表示当前vue对象接管了div区域
methods:{
fun:function(msg,event){
if(!((event.keyCode>=48&&event.keyCode<=57)||event.keyCode==8||event.keyCode==46)){
event.preventDefault();
}
}
}
});
</script>
</body>
</html>
- v-on:mouseover
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>事件处理</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app">
<div v-on:mouseover="fun1" id="div">
<textarea v-on:mouseover="fun2($event)">这是一个文件域</textarea>
</div>
</div>
<script>
new Vue({
el:'#app', //表示当前vue对象接管了div区域
methods:{
fun1:function(){
alert("div");
},
fun2:function(event){
alert("textarea");
event.stopPropagation();//阻止冒泡
}
}
});
</script>
</body>
</html>
- 事件修饰符
- Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或event.stopPropagation()。
- Vue.js通过由点(.)表示的指令后缀来调用修饰符。
- .stop
- .prevent
- .capture
- .self
- .once
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>v-on 事件修饰符</title> <script src="vue.js"></script> </head> <body> <div id="app"> <form @submit.prevent action="http://www.itcast.cn" method="get"> <input type="submit" value="提交"> </form> <div @click="fun"> <a @click.stop href="http://www.itcast.cn">itcast</a> </div> </div> <script> new Vue({ el:'#app', //表示当前vue对象接管了div区域 methods:{ fun:function(){ alert("hello itcast"); } } }); </script> </body> </html>
- 按键修饰符
- Vue 允许为 v-on 在监听键盘事件时添加按键修饰符
- .enter
- .tab
- .delete (捕获 “删除” 和 “退格” 键)
- .esc
- .space
- .up
- .down
- .left
- .right
- .ctrl
- .alt
- .shift
- .meta
- Vue 允许为 v-on 在监听键盘事件时添加按键修饰符
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>v-on 按钮修饰符</title> <script src="vue.js"></script> </head> <body> <div id="app"> <input type="text" v-on:keyup.enter="fun"> </div> <script> new Vue({ el:'#app', //表示当前vue对象接管了div区域 methods:{ fun:function(){ alert("你按了回车"); } } }); </script> </body> </html> <p><!-- Alt + C --> <input @keyup.alt.67="clear"> <!-- Ctrl + Click --> <div @click.ctrl="doSomething">Do something</div>
6.3.7.v-for: 循环结构
- v-for:写在哪个标签上, 循环遍历的就是哪个标签
- 对于v-for遍历语法采用 in/of 都可以, 没有什么区别
- 在vue中如果使用v-for这个指令, 那么必须给每一个v-for指令所遍历出的元素/标签, 加一个key=”唯一值” ,注意key不可重复
- Key是一个底层标记是给底层代码用的: 不是给程序员用的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="root">
<!-- 名称可以任意,但是顺序不能变,前面是遍历出来的项目,后面是索引 -->
<div v-for="(item, index) of arr" :key="index" @click="deletediv(xxx)">
{{item}}--{{index}}
</div>
<input v-model="inputstr">
<button @click="add">添加</button>
</div>
<script>
new Vue({
el: "#root",
data: {
inputstr: '',
arr: ["zs", "ls", "wu", "zl"]
},
methods: {
//添加列表项目
add: function () {
this.arr.push(this.inputstr)
},
//点击某一项即可删除
deletediv: function (index) {
this.arr.splice(index, 1)
}
}
})
</script>
</body>
</html>
6.3.8.v-pre:阻止预编译
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="root">
<!-- 不会替换为zs字符串 -->
<div v-pre>
{{msg}}
</div>
</div>
<script>
new Vue({
el: "#root",
data: {
msg: "zs"
}
})
</script>
</body>
</html>
6.3.9.v-once:只加载一次
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="root">
<div v-once>
{{msg}}
</div>
{{msg}}
<!-- 不管输入什么都不会改变v-once绑定内的插值表达式 -->
<input v-model="msg">
</div>
<script>
new Vue({
el: "#root",
data: {
msg: "zs"
}
})
</script>
</body>
</html>
6.3.10.v-cloak:延迟加载
- Vue对象一旦创建,就会绑定并查看绑定作用域,代码要重新按照vue语法解释一遍, 在这个解释的过程中, 一旦发现V-cloak属性, 会立刻清除。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
<style>
/*属性选择器*/
[v-cloak]{
/*display: none;*/
font-size: 100px;
}
</style>
</head>
<body>
<div id="root">
<!-- v-cloak属性在秒后被清除,属性选择器随之失效 -->
<div v-cloak>
{{msg}}
</div>
</div>
<script>
//10秒之后执行方法f()
setTimeout('f()', 10000)
function f() {
new Vue({
el: "#root",
data: {
msg: "zs"
}
})
}
</script>
</body>
</html>
6.3.11.v-slot
6.4.Vue属性
- el属性:绑定某个标签的id值,写法如上。
- data属性:数据属性,一般用于替换插值表达式,key:value写法。
- method属性:方法属性,用于触发某个事件。
- computed属性:计算属性,用于实时计算,显示结果。
- component属性:组件,下一节介绍
把Vue对象里的可以作为
字符串:{代码块}
写法的均看做属性(key-value性质),不是属性的在这里作为属性统一看待<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="vue.js"></script> </head> <body> <div id="root"> <!--插值表达式: 找自定义属性,先找data,如果找不到再找计算属性 --> {{sum}} <br> <input v-model="num1" ><br> <input v-model="num2" > <hr> {{sum2}} </div> <script> new Vue({ el: "#root", data: { num1: 0, num2: 0 }, computed: { // 不是方法, 外在表现是一个属性 sum: function () { // 计算属性, 是通过别的属性计算而来, 他是依赖于别的属性的 return parseInt(this.num1) + parseInt(this.num2) }, sum2: function () { return parseInt(this.num1) + parseInt(this.num2) + this.sum } } }) </script> </body> </html>
- watch属性:监听器,监听一个属性改变, 触发一个事件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="vue.js"></script> </head> <body> <div id="root"> {{sum}}<br> <input v-model="num1"> <input v-model="num2"> </div> <script> new Vue({ el: "#root", data: { sum: 0, num1: 0, num2: 0 }, watch: {// 侦听器: 侦听一个属性的改变, 然后触发一个方法 // 方法名, 就是要侦听的属性 num1: function () { this.sum = parseInt(this.num1) + parseInt(this.num2) }, num2: function () { this.sum = parseInt(this.num1) + parseInt(this.num2) } } }) </script> </body> </html>
- template属性:模板属性,一个字符串模板作为 Vue 实例的标识使用。模板将会 替换 挂载的元素。挂载元素的内容都将被忽略。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="vue.js"></script> </head> <body> <div id="root"></div> <script> // 以后html写代码, html只需要提供一个入口, // html js 都可以在一个vue对象中实现 new Vue({ el: "#root", data: { msg: "123" }, template: //语法强制要求,template外层必须要有div标签包裹 "<div> <div @click='clickdiv'> {{msg}} </div>" + "<p @click='clickp'> {{msg}} </p> </div>", methods: { clickdiv: function () { this.msg = "div" }, clickp: function () { this.msg = "p" } } }) </script> </body> </html>
- Example:使用Vue的v指令来实现汇率转换器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../vue.js"></script> <style> td { width: 200px; height: 30px; text-align: center; } [colspan] { background: red; } div { margin: 0 0 5px 0; } select { height: 35px; text-align: center; } button { height: 33px; } input { height: 30px; } </style> </head> <body> <div id="root"> <div> <select v-model="currency1" @change="getrate"> <option value="0">美元</option> <option value="1">人民币</option> <option value="2">欧元</option> <option value="3">日元</option> <option value="4">韩币</option> <option value="5">港币</option> </select> <button @click="changeselected">互换</button> <select v-model="currency2" @change="getrate"> <option value="0">美元</option> <option value="1">人民币</option> <option value="2">欧元</option> <option value="3">日元</option> <option value="4">韩币</option> <option value="5">港币</option> </select> 数额: <input v-model="num" @change="getrate"> 保留小数: <select v-model="point" @change="getrate"> <option value="0">0</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> <option value="6">6</option> </select> </div> <table border="1"> <tr> <td colspan="3">按当前汇率换算结果</td> </tr> <tr> <td>{{td11}}</td> <td>汇率</td> <td>{{td13}}</td> </tr> <tr> <td id="td21">{{td21}}</td> <td id="td22">{{td22}}</td> <td id="td23">{{td23}}</td> </tr> </table> </div> <script> new Vue({ el: "#root", data: { arrRate: [1, 6, 0.9, 100, 1000, 7], currencies: ['美元', '人民币', '欧元', '日元', '韩币', '港币'], currency1: 1, currency2: 0, num: 0, td11: "人民币", td13: "美元", td21: 0, td22: 0.1667, td23: 0, point:4 }, methods: { changeselected: function () { var mid = this.currency1; this.currency1 = this.currency2; this.currency2 = mid; this.getrate(); }, getrate: function () { this.td21 = this.num; var num = this.num * this.arrRate[this.currency2] / this.arrRate[this.currency1]; this.td23 = num.toFixed(this.point); this.td11 = this.currencies[this.currency1]; this.td13 = this.currencies[this.currency2]; var num = this.arrRate[this.currency2] / this.arrRate[this.currency1]; this.td22 = num.toFixed(this.point); } }, }) </script> </body> </html>
6.5.Vue组件
- Vue: 一个Vue对象, 就是一个组件,一个页面可以拆分成多个组件, 一个页面可以拆分成多个vue对象
- 好处:
- 模板不至于过于复杂
- 组件可以复用, vue代码可以复用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
</head>
<body>
<div id="root">
</div>
<script>
var son1 = {
template:"<div><div @click='f'>son1</div></div>",
methods: {
f: function () {
alert(123)
}
}
}
var son2 = {
template:"<div>son2</div>"
}
var son3 = {
template:"<div>son3</div>"
}
new Vue({
el: "#root",
data: {},
///Vue组件
components:{
//son1对象替换x标签
x:son1,
//son2对象替换y标签
y:son2,
//son3对象替换z标签
z:son3,
},
template:"<div><x></x><y></y><z></z></div>",
methods: {
f: function () {
alert(123)
}
}
})
</script>
</body>
</html>
6.6.Vue的生命周期(钩子)
- Vue在实例化的过程中,会调用这些生命周期的钩子,给我们提供了执行自定义逻辑的机会。
- vue在生命周期中有这些状态:
- beforeCreate(创建之前):数据还没有监听,没有绑定到vue对象实例,同时也没有挂载对象
- created(创建,较为常用):数据已经绑定到了对象实例,但是还没有挂载对象
- beforeMount(挂载之前):模板已经编译好了,根据数据和模板已经生成了对应的元素对象,将数据对象关联到了对象的el属性,el属性是一个HTMLElement对象,也就是这个阶段,vue实例通过原生的createElement等方法来创建这个html片段,准备注入到我们vue实例指明的el属性所对应的挂载点
- mounted(挂载,较为常用):将el的内容挂载到了el,相当于我们在jquery执行了(el).html(el),生成页面上真正的dom,上面我们就会发现dom的元素和我们el的元素是一致的。在此之后,我们能够用方法来获取到el元素下的dom对象,并进行各种操作
- beforeUpdate(修改之前):data发生改变时,会调用beforeUpdate和updated钩子,数据更新到dom之前,可以看到$el对象已经修改,但是页面上dom的数据还没有发生改变
- updated(修改):dom结构会通过虚拟dom的原则,找到需要更新页面dom结构的最小路径,将改变更新到dom上面,完成更新
- active(存储的时候使用,不做介绍)
- deactived(存储的时候使用,不做介绍)
- beforeDestroy(消亡之前)
- destroyed(消亡):实例的销毁,vue实例还是存在的,只是解绑了事件的监听还有watcher对象数据与view的绑定,即数据驱动
- errorCaptured(异常捕捉,不做介绍)
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>生命周期</title> <script src="js/vuejs-2.5.16.js"></script> </head> <body> <div id="app"> {{message}} </div> <script> var vm = new Vue({ el: "#app", data: { message: 'hello world' }, beforeCreate: function() { console.log(this); showData('创建vue实例前', this); }, created: function() { showData('创建vue实例后', this); }, beforeMount: function() { showData('挂载到dom前', this); }, mounted: function() { showData('挂载到dom后', this); }, beforeUpdate: function() { showData('数据变化更新前', this); }, updated: function() { showData('数据变化更新后', this); }, beforeDestroy: function() { vm.test = "3333"; showData('vue实例销毁前', this); }, destroyed: function() { showData('vue实例销毁后', this); } }); function realDom() { console.log('真实dom结构:' + document.getElementById('app').innerHTML); } function showData(process, obj) { console.log(process); console.log('data 数据:' + obj.message) console.log('挂载的对象:') console.log(obj.$el) realDom(); console.log('------------------') console.log('------------------') } vm.message="good..."; vm.$destroy(); </script> </body> </html>
6.7.创建Vue项目
http://www.nodejs.cn/
下载node.js安装包,打开msi安装包,会自动安装node.js和npm,- 测试是否安装成功:打开cmd,输入
node -v
,npm -v
。查看是否出现版本号。
- 测试是否安装成功:打开cmd,输入
- 打开cmd,输入
npm install -g cnpm --registry=https://registry.npm.taobao.org
,安装cnpm,- 测试是否安装成功:打开cmd,输入
cnpm -v
,查看是否出现版本号。
- 测试是否安装成功:打开cmd,输入
- 打开cmd,输入
cnpm install -g @vue/cli
,安装cli脚手架工具,卡住了则按ctrl+c,终止批处理操作,重新键入命令安装。- 测试是否安装成功: 打开cmd,输入
vue -V
(注意V大写) 出现版本号
- 测试是否安装成功: 打开cmd,输入
- 打开cmd,输入
cnpm install -g @vue/cli-init
,安装cli桥接工具,等待即可 - 打开cmd,输入
cnpm install -g webpack
,安装webpack, - 创建一个vue项目:
- 创建一个vue项目,通过cd命令找到要创建的项目的所在目录,输入命令
vue init webpack vuetest
,其中vuetest是项目名称 - 回车选择默认项目,然后输入n选择no,最后一项的时候选择稍后处理(即最后一个选项)
- 下载Vue项目依赖资源,找到vuetest的目录(第一步以后输入cd vuetest即可),输入命令
cnpm install -g
- 下载完毕后,使用cmd定位到项目所在目录,输入命令
npm run dev
后,浏览器里键入地址localhost://8080即可
- 创建一个vue项目,通过cd命令找到要创建的项目的所在目录,输入命令
- 如果已有一个Vue项目,如何拷贝并运行:
- 将所有除了.idea文件夹和node_modules文件夹的内容全部拷贝
- cmd定位到当前文件夹,输入cnpm install,下载node_modules依赖资源。
- 在idea中打开工程
也可以使用npm,配置国内镜像源
npm config set registry https://registry.npm.taobao.org
6.8.Vue项目结构
- .idea文件夹:idea运行环境
- build:js编译后的文件
- config:配置文件
- index.js:项目的整体配置
proxyTable{}
语句里可以配置代理- 对于linux系统,
assetsPublicPath: '/'
语句里的/要修改为./
- index.js:项目的整体配置
- node_modules:Vue项目依赖资源
- src:代码目录,我们写的代码基本都在这里
- components文件夹:自己定义组件,在这里添加或修改vue的组件
- main.js
- App.vue
- 其他自建相关文件
- static:
- index.html:项目的入口
- package.json:资源包的配置,启动打包配置,基础配置信息
对于一个新创建的Vue项目,加载顺序为:
- 首先加载index.html项目入口文件,主要内容仅有一句代码<div id=“app”></div>
- 进入src目录下寻找main.js文件,找到了一个vue对象,id是与index.html的div标签绑定的
- main.js文件中,vue对象里找到了App标签,替换掉index.html中的div标签
- 接下来,继续加载App标签是由自己的子组件定义的,而子组件是路径导入的
- 找到App.vue文件及它的默认对象,它的模板继续替换掉main.js中的components: { App }组件,只不过模板是定义在顶部的
- 显示的内容就是template中的内容,其中的style标签就是他的css样式(id选择器)
6.8.1.index.html
- 仅有一行语句,<div id=“app”></div>,主要是用于Vue的对象绑定以及模板替换
6.8.2.main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
//在同级目录的某个文件夹下,实际上导出的是App.vue的默认导出的对象
import App from './App'
//项目开发的主配置
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
//绑定了index.html入口文件的div标签
el: '#app',
//App子组件,该语句相当于 components:{App:App}, 前者App是标签,后者App是vue对象(文件),真正加载的实际上就是App.vue文件
components: { App },
//替换App标签
template: '<App/>'
})
6.8.3.App.vue
<!-- 加载的内容就是模板的内容,修改里边的内容,localhost的8080端口就会展示不同的内容 -->
<!-- 对于单个vue文件,template是默认写在这里的,但同样是下面的默认导出的vue对象的模板 -->
<!-- template标签下,要有一个唯一的div标签包裹,即使id不重复也是错误的 -->
<template>
<div id="app">
<img src="./assets/logo.png">
<HelloWorld/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld'
//默认导出,App.vue向外界暴露的就是这个默认导出的js对象
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<!-- CSS样式 -->
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
6.8.4.vue项目实例
- 模仿淘宝结构,简单的划分淘宝首页的区域
- component文件夹下文件结构:
- body1文件夹
- BodyLeft.vue
- BodyCenter.vue
- BodyRight.vue
- Body1
- Body2
- Top1
- Top2
- Top3
- body1文件夹
- App.vue
一定要记得在cmd里运行项目,才能在浏览器里localhost://8080查看到页面样式
- component文件夹下文件结构:
对于这个简单的项目,vue组件树有如下的结构
app.vue
|
---------------------------------------------------------------
| | | | |
top1 top2 top3 body1 body2
|
--------------------------------
| | |
BodyLeft BodyCenter BodyRight
<!-- Top1.vue文件 -->
<template>
<div>top1</div>
</template>
<script>
export default {
created() {
// TODO: 加载数据: 后端
}
}
</script>
<style scoped>
</style>
<!-- Top2.vue文件 -->
<template>
<div>top2</div>
</template>
<script>
export default {
created() {
// TODO: 加载数据: 后端
}
}
</script>
<style scoped>
</style>
<!-- Top3.vue文件 -->
<template>
<div>top3</div>
</template>
<script>
export default {
created() {
// TODO: 加载数据: 后端
}
}
</script>
<style scoped>
</style>
<!-- Body1.vue文件 -->
<template>
<div>
<body-left class="bodyleft"></body-left>
<body-center class="bodycenter"></body-center>
<body-right class="bodyright"></body-right>
</div>
</template>
<script>
import BodyLeft from "./body/BodyLeft";
import BodyCenter from "./body/BodyCenter";
import BodyRight from "./body/BodyRight";
export default {
components: {
BodyLeft,
BodyRight,
BodyCenter
},
created() {
// TODO: 加载数据: 后端
}
}
</script>
<style scoped>
.bodyleft{
width: 200px;
height: 500px;
background: #16c050;
float: left;
}
.bodycenter{
width: 700px;
height: 500px;
margin-left: 50px;
background: #c0b446;
float: left;
}
.bodyright{
width: 200px;
height: 500px;
margin-left: 50px;
background: #c0323c;
float: left;
}
</style>
<!-- BodyLeft.vue文件 -->
<template>
<div>BodyLeft</div>
</template>
<script>
export default {
name: "BodyLeft"
}
</script>
<style scoped>
</style>
<!-- BodyCenter.vue文件 -->
<template>
<div>BodyCenter</div>
</template>
<script>
export default {
name: "BodyCenter"
}
</script>
<style scoped>
</style>
<!-- BodyRight.vue文件 -->
<template>
<div>BodyRight</div>
</template>
<script>
export default {
name: "BodyRight"
}
</script>
<style scoped>
</style>
<!-- Body2.vue文件 -->
<template>
<div>body2</div>
</template>
<script>
export default {
created() {
// TODO: 加载数据: 后端
}
}
</script>
<style scoped>
</style>
<!-- App.vue文件 -->
<template>
<div class="app">
<!-- 只有在这里使用,才能构成父子关系,仅仅导入和注册是不够的 -->
<!-- 这里,标签是小写的,为什么?个人认为,原因是,html标签不区分大小写 -->
<top1 class="top1"></top1>
<top2 class="top2"></top2>
<top3 class="top3"></top3>
<body1 class="body1"></body1>
<body2 class="body2"></body2>
</div>
</template>
<script>
//导入
import Top1 from './components/Top1'
import Top2 from './components/Top2'
import Top3 from './components/Top3'
import Body1 from './components/Body1'
import Body2 from './components/Body2'
export default {
name: 'App',
//注册组件
components: {
Top1: Top1,
Top2,
Top3,
Body1,
Body2
},
created() {
// TODO 请求参数比较合适
}
}
</script>
<style>
.app{
width: 100%;
height: 1000px;
/*background: red;*/
}
.top1{
width: 100%;
height: 45px;
background: silver;
border-bottom: 1px solid;
}
.top2{
width: 100%;
height: 160px;
background: #c0323c;
}
.top3{
width: 100%;
height: 30px;
background: #16c050;
}
.body1{
width: 1200px;
height: 500px;
background: antiquewhite;
margin: 0 auto;
}
.body2{
width: 1200px;
height: 300px;
background: #1735fa;
margin: 0 auto;
}
</style>
6.9.父子组件传值
- 父子组件传值的步骤
- 子组件向上抛出一个方法,通知父组件,接收一个方法,
this.$emit("方法名",this.参数名)
- 另外,这个方法携带一个参数
- 子组件向上抛出一个方法,通知父组件,接收一个方法,
- 父组件向子组件传值
- 父传递: <right: url=“url”></right>
- 子接收: props: [‘url’]
- Example:父组件向子组件传值
- component文件结构
- Son1.vue
- Son2.vue
- App.vue
- component文件结构
<!-- Son1.vue文件 -->
<template>
<!-- 显示父组件传来的值 -->
<div>{{sonname}}</div>
</template>
<script>
export default {
name: "Son1",
//接收父组件传来的值
props: ['sonname']
}
</script>
<style scoped>
</style>
<!-- Son2.vue -->
<template>
<!-- 显示父组件传来的值 -->
<div>{{sonage}}</div>
</template>
<script>
export default {
name: "Son2",
//接收父组件传来的值
props: ['sonage']
}
</script>
<style scoped>
</style>
<!-- App.vue文件 -->
<template>
<div id="app">
<!-- 绑定要传给子组件的值,:后面的是名称,可以任意取名 -->
<son1 class="son1" v-bind:sonname="list[0].name"></son1>
<!-- v-bind的简写形式,只需要写一个:即可 -->
<son2 class="son2" :sonage="list[0].age"></son2>
</div>
</template>
<script>
import Son1 from "./components/Son1";
import Son2 from "./components/Son2";
export default {
name: 'App',
data() {
return{
list: [{
name: "zs",
age: 18
},
{
name: "ls",
age: 20
}]
}
},
components: {
Son1,
Son2
}
}
</script>
<style>
.son1{
width: 400px;
height: 400px;
border: 1px solid;
float: left;
}
.son2{
width: 500px;
height: 400px;
margin-left: 100px;
border: 1px solid;
float: left;
}
</style>
- 子组件向父组件传值
- 父接收: <left @changeurl=“changeurl”></left>
- 子抛出: this.$emit(‘changeurl’, url)
- Example:父组件向子组件传值
- component文件结构
- Son1.vue
- Son2.vue
- App.vue
这个例子,Son1抛出了参数给父组件App.vue,父组件App.vue再传值给子组件Son2
$属性的用途:为了说明这是个方法,而不是属性。目的是为了和data的属性区分开
- component文件结构
<!-- Son1.vue文件 -->
<template>
<div>
<!-- 双向绑定,通过表单元素input来修改inputstr属性的值 -->
<input v-model="inputstr"><button @click="add">添加</button>
</div>
</template>
<script>
export default {
name: "Son1",
data(){
return{
//初始状态,inputstr为空
inputstr: ''
}
},
methods: {
add: function () {
// 子组件向上抛出一个方法
// 通知父组件, 接受一个方法:inputmsg
// 另外, 这个方法携带一个参数: this.inputstr
this.$emit("inputmsg", this.inputstr)
}
}
}
</script>
<style scoped>
</style>
<!-- Son2.vue -->
<template>
<div>
<ul>
<li v-for=" (item, index) in list" :key="index">
{{item}}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "Son2",
//Son2接收父组件传来的msg参数,msg参数是子组件抛出的inputstr字符串,而inputstr字符串是我们所输入的
props:['msg'],
data(){
return{
list: ["zs", "ls", "wu"]
}
},
//监听msg属性的变化,只要父组件的msg发生变化,就给列表添加值
watch: {
msg: function () {
this.list.push(this.msg)
}
}
}
</script>
<style scoped>
</style>
<!-- App.vue文件 -->
<template>
<div id="app">
<!-- 同理,在这里形成了组件间的父子关系,即,使用才能构成父子关系 -->
<!-- 单向绑定,接收Son1抛出的inputmsg方法,同时触发一个方法appinputmsg -->
<son1 class="son1" v-on:inputmsg="appinputmsg"></son1>
<son2 class="son2" v-bind:msg="msg"></son2>
</div>
</template>
<script>
import Son1 from "./components/Son1";
import Son2 from "./components/Son2";
export default {
name: 'App',
data() {
return{
msg: ''
}
},
methods: {
//接收到子组件Son1抛出的方法以后,触发这个方法,parame就是Son1抛出的参数
appinputmsg: function (parame) {
// alert("Son1抛出的" + parame)
//把Son1抛出的参数赋值给自己的msg属性,使用data的msg属性做一个中转存储
this.msg = parame
}
},
components: {
Son1,
Son2
}
}
</script>
<style>
.son1{
width: 400px;
height: 400px;
border: 1px solid;
float: left;
}
.son2{
width: 500px;
height: 400px;
margin-left: 100px;
border: 1px solid;
float: left;
}
</style>
6.10.VueBus
- 中央总线事物,类似计算机组成原理
- 对于某个复杂的结构,我们想实现子组件之间的传值,只能通过公共的父组件来做中转,而VueBus则像是计算机中的总线一样,开辟了一条通路,所有组件连接至VueBus即可,这样子组件之间的传值只需通过总线即可
可以用生活中的地铁车站来理解,从某个车站(子组件)到另一个车站(子组件),坐一条线路的地铁即可
- Example:VueBus通信
- src文件结构:
- assets文件夹(项目自带)
- bus(自建,用于配置总线)
- index.js
- components文件夹
- body1文件夹
- BodyLeft.vue
- BodyCenter.vue
- BodyRight.vue
- Body1.vue
- Body2.vue
- Top1.vue
- Top2.vue
- Top3.vue
- body1文件夹
- App.vue
- main.js
- 一般来说,我们在修改项目的相关配置时,一般都会在main.js中修改
- 假设此项目,我们要在Top1和BodyCenter之间传值(如果不配置总线,只能Top1传值给App,然后App传值给Body1,Body1再传给BodyCenter)
- src文件结构:
<!-- 首先创建一个配置文件,用于配置总线 -->
<!-- index.js文件 -->
import Vue from 'vue' // 导入Vue语法
const vue = new Vue() // 创建一个Vue对象
export default vue // 默认导出这个vue对象
<!-- 修改main.js配置文件 -->
<!-- main.js文件 -->
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
// 从bus文件夹下的index.js 导过来一个Vue对象, 给这个对象起个名字叫vuebus
import vuebus from './bus/index.js' //由于index.js是默认代表首页写入底层语法中的,所以也可以不加
// 项目全局配置: $bus,可以是任何名称,但是习惯为$bus,也就是说,在项目里,所有Vue对象都有$bus这个属性
Vue.prototype.$bus = vuebus
//原有的vue配置语句
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>'
})
<!-- Top3.vue文件(这里与其没有太大关系) -->
<template>
<div>top3</div>
</template>
<script>
export default {
created() {
// TODO: 加载数据: 后端
}
}
</script>
<style scoped>
</style>
<!-- Top2.vue文件(这里与其没有太大关系) -->
<template>
<div>top2</div>
</template>
<script>
export default {
created() {
// TODO: 加载数据: 后端
}
}
</script>
<style scoped>
</style>
<!-- Body2.vue文件(这里与其没有太大关系) -->
<template>
<div>body2</div>
</template>
<script>
export default {
created() {
// TODO: 加载数据: 后端
}
}
</script>
<style scoped>
</style>
<!-- Body1.vue文件(这里与其没有太大关系) -->
<template>
<div>
<body-left class="bodyleft"></body-left>
<body-center class="bodycenter"></body-center>
<body-right class="bodyright"></body-right>
</div>
</template>
<script>
import BodyLeft from "./body/BodyLeft";
import BodyCenter from "./body/BodyCenter";
import BodyRight from "./body/BodyRight";
export default {
components: {
BodyLeft,
BodyRight,
BodyCenter
},
created() {
// TODO: 加载数据: 后端
}
}
</script>
<style scoped>
.bodyleft{
width: 200px;
height: 500px;
background: #16c050;
float: left;
}
.bodycenter{
width: 700px;
height: 500px;
margin-left: 50px;
background: #c0b446;
float: left;
}
.bodyright{
width: 200px;
height: 500px;
margin-left: 50px;
background: #c0323c;
float: left;
}
</style>
<!-- Top1.vue文件 -->
<template>
<div>
<input v-model="inputstr">
<button @click="add">添加</button>
</div>
</template>
<script>
export default {
data(){
return{
inputstr: ''
}
},
methods: {
add: function () {
// 抛出方法addmsg,方法携带参数inputstr
// this: 值得是本对象
this.$bus.$emit("addmsg", this.inputstr)
}
}
}
</script>
<style scoped>
</style>
<!-- BodyCenter.vue文件 -->
<template>
<div>
<ul>
<li v-for="(item, index) in list" :key="index">
{{item}}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "BodyCenter",
data(){
return {
list: ["zs", "ls", "wu"]
}
},
//生命周期函数
created() {
// 监听一个bus事件: 这个事件的名称为addmsg
// $on: 监听一个事件
// res : 监听到的方法携带的参数
// =>: 箭头函数(ES6): 如下作用 把res当做一个参数传到匿名方法里,类似lambda表达式
this.$bus.$on("addmsg" , res => {
this.list.push(res)
})
}
}
</script>
<style scoped>
</style>
<!-- BodyLeft.vue文件(这里与其没有太大关系) -->
<template>
<div>BodyLeft</div>
</template>
<script>
export default {
name: "BodyLeft"
}
</script>
<style scoped>
</style>
<!-- BodyRight.vue文件(这里与其没有太大关系) -->
<template>
<div>BodyRight</div>
</template>
<script>
export default {
name: "BodyRight"
}
</script>
<style scoped>
</style>
个人理解,如何看待VueBus?
- $bus这个对象/属性就可以看做一列地铁,因为它被配置为全局对象,每个vue文件都可以使用它,那么就相当于开辟了一个VueBus总线
- 在这列地铁上,某个vue文件抛出了某个方法并携带某个参数,相当于某位乘客上车了,直到另一个vue文件监听到了前面抛出的方法和参数,相当于这位乘客下车了。
6.11.axios
- Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中
- 引入axios
- 首先就是引入axios,如果你使用es6,只需要安装axios模块之后
import axios from 'axios'; //安装方法 npm install axios //或 bower install axios
- 当然也可以用script引入
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
- get请求
//通过给定的ID来发送请求 axios.get('/user?ID=12345') .then(function(response){ console.log(response); }) .catch(function(err){ console.log(err); }); //以上请求也可以通过这种方式来发送 axios.get('/user',{ params:{ ID:12345 } }) .then(function(response){ console.log(response); }) .catch(function(err){ console.log(err); });
- post请求
axios.post('/user',{ firstName:'Fred', lastName:'Flintstone' }) .then(function(res){ console.log(res); }) .catch(function(err){ console.log(err); });
- 为方便起见,为所有支持的请求方法提供了别名
- axios.request(config)
- axios.get(url[, config])
- axios.delete(url[, config])
- axios.head(url[, config])
- axios.post(url[, data[, config]])
- axios.put(url[, data[, config]])
- axios.patch(url[, data[, config]])
- 为方便起见,为所有支持的请求方法提供了别名
- 关于Vue前端请求后端数据的例子
<template> <div id="app"> <img :src="imgurl"> </div> </template> <script> export default { data(){ return{ imgurl: '' } }, created() { //请求后端数据 this.$axios.get("http://115.29.141.32:8084/api/mall/getGoodsByType?typeId=1") //.then是专门用于处理返回参数的,res就是返回参数 .then(res => { console.log(res) console.log(res.data) console.log(res.data.data) this.imgurl = res.data.data[0].img }) } } </script> <style> </style>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/181061.html