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代码,过程可以解析如下:

  1. 创建了一个Vue对象(根据Vue语法)
  2. 这个Vue对象一旦创建, 会立即检查 它的el属性,
  3. 他会根据el属性找到一个对应id的html代码
  4. 如果找到了, 把找到的html代码所对应的作用域 和 这个Vue对象’绑定起来’
  5. 这个html代码所对应的作用域 就不在仅仅是html代码作用域, 还是这个Vue对象作用域
  6. 这个作用域代码 会重新, 按照Vue语法再解析一边
  7. 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
    <!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项目
  1. http://www.nodejs.cn/ 下载node.js安装包,打开msi安装包,会自动安装node.js和npm,
    • 测试是否安装成功:打开cmd,输入node -vnpm -v。查看是否出现版本号。
  2. 打开cmd,输入 npm install -g cnpm --registry=https://registry.npm.taobao.org ,安装cnpm,
    • 测试是否安装成功:打开cmd,输入 cnpm -v,查看是否出现版本号。
  3. 打开cmd,输入 cnpm install -g @vue/cli ,安装cli脚手架工具,卡住了则按ctrl+c,终止批处理操作,重新键入命令安装。
    • 测试是否安装成功: 打开cmd,输入 vue -V (注意V大写) 出现版本号
  4. 打开cmd,输入 cnpm install -g @vue/cli-init ,安装cli桥接工具,等待即可
  5. 打开cmd,输入 cnpm install -g webpack ,安装webpack,
  6. 创建一个vue项目:
    1. 创建一个vue项目,通过cd命令找到要创建的项目的所在目录,输入命令vue init webpack vuetest ,其中vuetest是项目名称
    2. 回车选择默认项目,然后输入n选择no,最后一项的时候选择稍后处理(即最后一个选项)
    3. 下载Vue项目依赖资源,找到vuetest的目录(第一步以后输入cd vuetest即可),输入命令cnpm install -g
    4. 下载完毕后,使用cmd定位到项目所在目录,输入命令 npm run dev 后,浏览器里键入地址localhost://8080即可
  7. 如果已有一个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: '/' 语句里的/要修改为./
  • node_modules:Vue项目依赖资源
  • src:代码目录,我们写的代码基本都在这里
    • components文件夹:自己定义组件,在这里添加或修改vue的组件
    • main.js
    • App.vue
    • 其他自建相关文件
  • static:
  • index.html:项目的入口
  • package.json:资源包的配置,启动打包配置,基础配置信息

对于一个新创建的Vue项目,加载顺序为:

  1. 首先加载index.html项目入口文件,主要内容仅有一句代码<div id=“app”></div>
  2. 进入src目录下寻找main.js文件,找到了一个vue对象,id是与index.html的div标签绑定的
  3. main.js文件中,vue对象里找到了App标签,替换掉index.html中的div标签
  4. 接下来,继续加载App标签是由自己的子组件定义的,而子组件是路径导入的
  5. 找到App.vue文件及它的默认对象,它的模板继续替换掉main.js中的components: { App }组件,只不过模板是定义在顶部的
  6. 显示的内容就是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
    • App.vue

    一定要记得在cmd里运行项目,才能在浏览器里localhost://8080查看到页面样式

对于这个简单的项目,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
<!-- 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的属性区分开

<!-- 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
      • App.vue
      • main.js
    • 一般来说,我们在修改项目的相关配置时,一般都会在main.js中修改
    • 假设此项目,我们要在Top1和BodyCenter之间传值(如果不配置总线,只能Top1传值给App,然后App传值给Body1,Body1再传给BodyCenter)
<!-- 首先创建一个配置文件,用于配置总线 -->
<!-- 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>