VUE2.0详解

vue

基础

1. Vue概述

渐进式JavaScript框架
声明式渲染→组件系统→客户端路由→集中式状态管理→项目构建
官网
特点:

易用:熟悉HTML、CSS、JavaScript知识后,可快速上手Vue
灵活:在一个库和一套完整框架之间自如伸缩
高效:20kB运行大小,超快虚拟 DOM

2. Vue基本使用

<div id="app">
<div>{{msg}}</div>
</div>
<script type="text/javascript" src="js/vue.js"></script> 
<script type="text/javascript">
new Vue({
el: '#app',
data: {
msg: 'HelloWorld' }
})
</script>

2.3 Vue.js之HelloWorld细节分析

  1. 实例参数分析

el: 元素的挂载位置(值可以是CSS选择器或者DOM元素)
data:模型数据(值是一个对象)

  1. 插值表达式用法

将数据填充到HTML标签中
插值表达式支持基本的计算操作

  1. Vue代码运行原理分析

概述编译过程的概念(Vue代码→Vue框架编译→原生js代码)

3. Vue模板语法

3.1插值表达式

数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:

<span>Message: {{ msg }}</span>

迄今为止,在我们的模板中,我们一直都只绑定简单的 property 键值。但实际上,对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>

这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。

<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}

<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}

3.2 指令

指令的本质就是自定义属性
指令的格式:以v-开始(比如:v-cloak)
标签中涉及到data属性的判断== 字符串加不加引号都行 ===必须一致

  deld: '23'
----------------------插值-----------------------
  <div id="app">
    <div>{{deld===23?2:1}}</div>
  </div>
  1
  
  <div id="app">
    <div>{{deld=='23'?2:1}}</div>
  </div>
  2

 <div id="app">
   <div>{{deld==23?2:1}}</div>
 </div>
  2
 -----------------------指令-------------------------
 <div v-if='deld==="23"'>是否显示</div>  显示
 <div v-if='deld===23'>是否显示</div>  不显示
 <div v-if='deld==23'>是否显示</div>  显示
 <div v-if='deld=="23"'>是否显示</div>  显示
v-cloak指令防止页面加载时出现闪烁问题

插值表达式存在的问题:“闪动”(多次刷新可能会先显示插值表达式的代码之后才会显示赋值)
如何解决该问题:使用v-cloak指令
解决该问题的原理:先隐藏,替换好值之后再显示最终的值

 <style type="text/css">
  /* 
    1、通过属性选择器 选择到 带有属性 v-cloak的标签  让他隐藏
 */
  [v-cloak]{
    /* 元素隐藏    */
    display: none;
  }
  </style>
<body>
  <div id="app">
    <!-- 2、 让带有插值 语法的   添加 v-cloak 属性 
         在 数据渲染完场之后,v-cloak 属性会被自动去除,
         v-cloak一旦移除也就是没有这个属性了  属性选择器就选择不到该标签
		 也就是对应的标签会变为可见
    -->
    <div  v-cloak  >{{msg}}</div>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    var vm = new Vue({
      //  el   指定元素 id 是 app 的元素  
      el: '#app',
      //  data  里面存储的是数据
      data: {
        msg: 'Hello Vue'
      }
    });
</script>
</body>
</html>
v-text填充数据没有闪动问题

v-text指令用于将数据填充到标签中,作用于插值表达式类似,但是没有闪动问题
如果数据中有HTML标签会将html标签一并输出
注意:此处为单向绑定,数据对象上的值改变,插值会发生变化;但是当插值发生变化并不会影响数据对象的值

<div id="app">
    <!--  
		注意:在指令中不要写插值语法  直接写对应的变量名称 
        在 v-text 中 赋值的时候不要在写 插值语法
		一般属性中不加 {{}}  直接写 对应 的数据名 
	-->
    <p v-text="msg"></p>
    <p>
        <!-- Vue  中只有在标签的 内容中 才用插值语法 -->
        {{msg}}
    </p>
</div>

<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'Hello Vue.js'
        }
    });

</script>
v-html将HTML片段填充到标签中

用法和v-text 相似 但是他可以将HTML片段填充到标签中
可能有安全问题, 一般只在可信任内容上使用 v-html永不用在用户提交的内容上
它与v-text区别在于v-text输出的是纯文本,浏览器不会对其再进行html解析,但v-html会将其当html标签解析后输出。

<div id="app">
  <p v-html="html"></p> <!-- 输出:html标签在渲染的时候被解析 -->
    
    <p>{{message}}</p> <!-- 输出:<span>通过双括号绑定</span> -->
    
  <p v-text="text"></p> <!-- 输出:<span>html标签在渲染的时候被源码输出</span> -->
</div>
<script>
  let app = new Vue({
  el: "#app",
  data: {
    message: "<span>通过双括号绑定</span>",
    html: "<span>html标签在渲染的时候被解析</span>",
    text: "<span>html标签在渲染的时候被源码输出</span>",
  }
 });
</script>
v-pre显示原始信息跳过编译过程

跳过这个元素和它的子元素的编译过程。
一些静态的内容不需要编译加这个指令可以加快渲染

  <span v-pre>{{ this will not be compiled }}</span>    
	<!--  显示的是{{ this will not be compiled }}  -->
	<span v-pre>{{msg}}</span>  
     <!--   即使data里面定义了msg这里仍然是显示的{{msg}}  -->
<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'Hello Vue.js'
        }
    });

</script>
v-once

执行一次性的插值【当数据改变时,插值处的内容不会继续更新】

v-model双向数据绑定(重点)

当数据发生变化的时候,视图也就发生变化
当视图发生变化的时候,数据也会跟着同步变化
v-model是一个指令,限制在 <input>、<select>、<textarea>、components中使用
在这里插入图片描述
注意: 单选值为单个多选值为数组

v-on绑定事件(重点)

用来绑定事件的
形式如:v-on:click 缩写为 @click;

<div id="app">
        <div>{{num}}</div>
        <div>
            <button v-on:click='num++'>点击</button>
            <button @click='num++'>点击1</button>
            <button @click='handle'>点击2</button>
            <button @click='handle()'>点击3</button>
        </div>
    </div>
v-on事件函数中传入参数
<body>
    <div id="app">
        <div>{{num}}</div>
        <div>
            <!-- 如果事件直接绑定函数名称,那么默认会传递事件对象作为事件函数的第一个参数 -->
            <button v-on:click='handle1'>点击1</button>
            <!-- 2、如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递,
                 并且事件对象的名称必须是$event 
            -->
            <button v-on:click='handle2(123, 456, $event)'>点击2</button>
        </div>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el: '#app',
            data: {
                num: 0
            },
            methods: {
                handle1: function(event) {
                    console.log(event.target.innerHTML)
                },
                handle2: function(p, p1, event) {
                    console.log(p, p1)
                    console.log(event.target.innerHTML)
                    this.num++;
                }
            }
        });
    </script>
Vue中实现单击click事件获取html元素和css样式的解决方法

一、通过event获取

                console.log(event.target); // 当前元素点击的子节点
                console.log(event.currentTarget);  // 当前Vue元素
 
 
                var pro = event.currentTarget;   // 当前元素
 
                pro.lastElementChild.style.color = "#DE3E3E"; // 修改最后一个子节点,改变图标和文字颜色
 
                console.log(pro.getAttribute('name'));  // 获取html元素属性值

二、如果click事件传参数,需要设置$event来获取。

<div class="bar_menu" v-on:click="showInfo(1,$event)" name="1"></div>
 
 
<script type="text/javascript">
 
 
    var bottom_bar = new Vue({
        el: '#bottom_bar',
        data: {
            img_1: "images/bar_1_select"
        },
        methods: {
            showInfo(s,event) {
 
                // console.log(event.target); // 当前元素
                console.log(event.currentTarget);  // vue元素
                var pro = event.currentTarget;   // 当前元素
                pro.lastElementChild.style.color = "#DE3E3E";
                event.currentTarget.style.backgroundColor = "rgba(25, 253, 240, 0.7)";//当前选中行高亮
 
            }
 
        }
    })
</script>
事件修饰符

在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。
Vue 不推荐我们操作DOM 为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符
修饰符是由点开头的指令后缀来表示的

<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联   即阻止冒泡也阻止默认事件 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!--阻止鼠标右键弹出信息-->
<div @contextmenu.prevent.capture</div>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
按键修饰符

在做项目中有时会用到键盘事件,在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符

<!-- 只有在 `keyCode`13 时调用 `vm.submit()` -->
<input v-on:keyup.13="submit">

<!-- -当点击enter 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">

<!--当点击enter或者space时  时调用 `vm.alertMe()`   -->
<input type="text" v-on:keyup.enter.space="alertMe" >

常用的按键修饰符
.enter =>    enter键
.tab => tab键
.delete (捕获“删除”和“退格”按键) =>  删除键
.esc => 取消键
.space =>  空格键
.up =>.down =>.left =>.right =><script>
	var vm = new Vue({
        el:"#app",
        methods: {
              submit:function(){},
              alertMe:function(){},
        }
    })

</script>
自定义按键修饰符别名

在Vue中可以通过config.keyCodes自定义按键修饰符别名

<div id="app">
    预先定义了keycode 116(即F5)的别名为f5,因此在文字输入框中按下F5,会触发prompt方法
    <input type="text" v-on:keydown.f5="prompt()">
</div>

<script>
	
    Vue.config.keyCodes.f5 = 116;

    let app = new Vue({
        el: '#app',
        methods: {
            prompt: function() {
                alert('我是 F5!');
            }
        }
    });
</script>
v-bind重点

v-bind 指令被用来响应地更新 HTML 属性
v-bind:href 可以缩写为 :href;

<!-- 绑定一个属性 -->
<img v-bind:src="imageSrc">

<!-- 缩写 -->
<img :src="imageSrc">
绑定对象

我们可以给v-bind:class 一个对象,以动态地切换class。
注意:v-bind:class指令可以与普通的class特性共存
1、 v-bind 中支持绑定一个对象
如果绑定的是一个对象 则 键为 对应的类名 值 为对应data中的数据


<!-- 
	HTML最终渲染为 <ul class="box textColor textSize"></ul>
	注意:
		textColor,textSize  对应的渲染到页面上的CSS类名	
		isColor,isSize  对应vue data中的数据  如果为true 则对应的类名 渲染到页面上 


		当 isColor 和 isSize 变化时,class列表将相应的更新,
		例如,将isSize改成falseclass列表将变为 <ul class="box textColor"></ul>
-->

<ul class="box" v-bind:class="{textColor:isColor, textSize:isSize}">
    <li>学习Vue</li>
    <li>学习Node</li>
    <li>学习React</li>
</ul>
  <div v-bind:style="{color:activeColor,fontSize:activeSize}">对象语法</div>

<sript>
var vm= new Vue({
    el:'.box',
    data:{
        isColor:true,
        isSize:trueactiveColor:"red",
        activeSize:"25px",
    }
})
</sript>
<style>

    .box{
        border:1px dashed #f0f;
    }
    .textColor{
        color:#f00;
        background-color:#eef;
    }
    .textSize{
        font-size:30px;
        font-weight:bold;
    }
</style>
绑定class(重点)

2、 v-bind 中支持绑定一个数组 数组中classA和 classB 对应为data中的数据

这里的classA  对用data 中的  classA
这里的classB  对用data 中的  classB
<ul class="box" :class="[classA, classB]">
    <li>学习Vue</li>
    <li>学习Node</li>
    <li>学习React</li>
</ul>
<script>
var vm= new Vue({
    el:'.box',
    data:{
        classA:‘textColor‘,
        classB:‘textSize‘
    }
})
</script>
<style>
    .box{
        border:1px dashed #f0f;
    }
    .textColor{
        color:#f00;
        background-color:#eef;
    }
    .textSize{
        font-size:30px;
        font-weight:bold;
    }
</style>
class应用情景:
1 <li v-on:click='change(index)' :class='currentIndex==index?"active":""' :key='item.id' v-for='(item,index) in list'>{{item.title}}</li>

2<div :class="{opacity_bhd: organCodes != 0}>是否显示样式</div>
.opacity_bhd {
        opacity: 0.3;

    }
 data(){
 return{
 organCodes : '0'
 }}   

3 <div :class="remoteDeviceClass?'zhlc_screen_navbody_ygsb':'display_flex align_items_center'"></div>

4 <div class="folderItem" :class="{'noFoldersClass':noFoldersClass(item)}">
noFoldersClass(item) {
            if (item.folders == null || item.folders.length == 0) {
                return true
            }
            return false
        }

**绑定对象和绑定数组 的区别 : **

绑定对象的时候 对象的属性 即要渲染的类名 对象的属性值对应的是 data 中的数据
绑定数组的时候数组里面存的是data 中的数据

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style type="text/css">
    .active {
      border: 1px solid red;
      width: 100px;
      height: 100px;
    }
    .error {
      background-color: orange;
    }
    .test {
      color: blue;
    }
    .base {
      font-size: 28px;
    }
  </style>
</head>
<body>
<div id="app">
  <div v-bind:class='[activeClass, errorClass, {test: isTest}]'>测试样式</div>
  <div v-bind:class='arrClasses'></div>
  <div v-bind:class='objClasses'></div>
  <div class="base" v-bind:class='objClasses'></div>

  <button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
  /*
    样式绑定相关语法细节:
    1、对象绑定和数组绑定可以结合使用
    2、class绑定的值可以简化操作
    3、默认的class如何处理?默认的class会保留

  */
  var vm = new Vue({
    el: '#app',
    data: {
      activeClass: 'active',
      errorClass: 'error',
      isTest: true,
      arrClasses: ['active','error'],
      objClasses: {
        active: true,
        error: true
      }
    },
    methods: {
      handle: function(){
        // this.isTest = false;
        this.objClasses.error = false;
      }
    }
  });
</script>
</body>
</html>

绑定style
 <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
<div id="app">
  <div v-bind:style='{border: borderStyle, width: widthStyle, height: "10px"}'>55</div>
  <div v-bind:style='objStyles'></div>
  <div v-bind:style='[objStyles, overrideStyles]'></div>
  <button v-on:click='handle'>切换</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
  /*
    样式绑定之内联样式Style:
  */
  var vm = new Vue({
    el: '#app',
    data: {
      borderStyle: '1px solid blue',
      widthStyle: '100px',
      heightStyle: '200px',
      objStyles: {
        border: '1px solid green',
        width: '200px',
        height: '100px'
      },
      overrideStyles: {
        border: '5px solid orange',
        backgroundColor: 'blue'
      }
    },
    methods: {
      handle: function(){
        this.heightStyle = '100px';
        this.objStyles.width = '100px';
      }
    }
  });
</script>
</body>
</html>

注意:
在标签里直接写样式的,样式结构有-的要变成驼峰格式否则报错

<span class="weather_kqzs_box_blszrbhq" v-bind:style='{backgroundColor: weathers.color}'>{{weathers.airQuality}}</span>
单机列表数据高亮选中
先定义一个属性currentIndex:null
<tr v-for="(item,index) in projectDirectories" @click="flytopoint(item,index)" :class='currentIndex==index?"highlighted":""' >
                                            <td>{{index+1}}</td>
                                            <td style="cursor:pointer" >{{item.zrbhdmc}}</td>
                                            <td>{{item.totalArea}}</td>
                                            <td>{{item.levels}}</td>
                                        </tr>
flytopoint(item,currentIndex) {
                let self = this;
                self.currentIndex=currentIndex;
            },
.highlighted {
        background-color:rgba(25, 253, 240, 0.7)!important;
    }
分支结构
v-if 使用场景

1- 多个元素 通过条件判断展示或者隐藏某个元素。
**v-if v-else v-else-if **
2- 进行两个视图之间的切换

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>

</head>
<body>
<div id="app">
  <div v-if='100>=90'>优秀</div>
  <div v-else-if='score<90&&score>=80'>良好</div>
  <div v-else-if='score<80&&score>60'>一般</div>
  <div v-else>比较差</div>
  <div v-if='flag'>测试v-if</div>
  <div v-show='flag1'>测试v-show</div>
  <button v-on:click='handle'>点击</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
  /*
    分支结构

    v-show的原理:控制元素样式是否显示 display:none
    v-if的原理:控制元素样式是否显示 display:none
  */
  var vm = new Vue({
    el: '#app',
    data: {
      score: 10,
      flag: false,
      flag1: false
    },
    methods: {
      handle: function(){
        this.flag = !this.flag;
      }
    }
  });
</script>
</body>
</html>

v-show 和 v-if的区别

v-show本质就是标签display设置为none,控制隐藏二者都不占位
v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,故v-show性能更好一点。
v-if是动态的向DOM树内添加或者删除DOM元素
v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件
v-if控制元素是否渲染到页面
v-show控制元素是否显示(已经渲染到了页面)

循环结构
v-for

用于循环的数组里面的值可以是对象,也可以是普通元素
v-for遍历数组:

<li v-for='item in list'>{{item}}</li>
<li v-for='(item,index) in list'>{{item}} + '---' +{{index}}</li>
<li :key='item.id' v-for='(item,index) in list'>{{item}} + '---' {{index}}</li>

eg:

<div id="app">
    <div>循环数组</div>
    <ul>
    <!--1、绑定key的作用 提高Vue的性能 2、 key 需要是唯一的标识 所以需要使用id, 也可以使用index , index 也是唯一的 3、 item 是 数组中对应的每一项 4、 index 是 每一项的 索引 -->
      <li v-for='item in fruits'>{{item}}</li>
      <li v-for='(item, index) in fruits'>{{item + '---' + index}}</li>
      <li v-if="item.id==2" :key='item.id' v-for='(item, index) in myFruits'>
        <span>{{item.ename}}</span>
        <span>-----</span>
        <span>{{item.cname}}</span>
      </li>

    </ul>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      循环结构-遍历数组
    */
    var vm = new Vue({
      el: '#app',
      data: {
        fruits: ['apple', 'orange', 'banana'],
        myFruits: [{
          id: 1,
          ename: 'apple',
          cname: '苹果'
        },{
          id: 2,
          ename: 'orange',
          cname: '橘子'
        },{
          id: 3,
          ename: 'banana',
          cname: '香蕉'
        }]
      }
    });
  </script>

key的作用:key来给每个节点做一个唯一标识,帮助Vue区分不同的元素,从而提高性能

v-for遍历对象:

<div v-for='(value, key, index) in object'></div>

v-if和v-for结合使用:

<div v-if='value==12' v-for='(value, key, index) in object'></div>
<body>
  <div id="app">
    <div v-if='v==13' v-for='(v,k,i) in obj'>{{v + '---' + k + '---' + i}}</div>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    // 使用原生js遍历对象
    var obj = {
      uname: 'lisi',
      age: 12,
      gender: 'male'
    }
    for(var key in obj) {
      console.log(key, obj[key])
    }
    /*
      循环结构
    */
    var vm = new Vue({
      el: '#app',
      data: {
        obj: {
          uname: 'zhangsan',
          age: 13,
          gender: 'female'
        }
      }
    });
  </script>

Vue常用特性

computed计算属性 watch监听器属性 filters过滤器 methods方法函数 都可以用与插值表达式和属性绑定

表单基本操作

Input 单行文本

1、不需要绑定value 属性的,通过v-model 双向绑定 一个值

textarea 多行文本

1、textarea 是 一个双标签 不需要绑定value 属性的,通过v-model 双向绑定 一个值

select 下拉多选

1、 需要给select 通过v-model 双向绑定 一个值
2、 每一个option 必须要有value属性 且value 值不能一样
3、 当某一个option选中的时候 v-model 会将当前的 value值 改变 data 中的 数据 occupation 的值就是选中的值,相反data初始化默认的值也就是其默认选中的值
4、如何 multiple 多选则绑定的值为数组

radio 单选框

1、 两个单选框需要同时通过v-model 双向绑定 一个值
2、 每一个单选框必须要有value属性 且value 值不能一样
3、 当某一个单选框选中的时候 v-model 会将当前的 value值 改变 data 中的 数据 gender 的值就是选中的值,,相反data初始化默认的值也就是其默认选中的值

checkbox 多选框

1、 复选框需要同时通过v-model 双向绑定 一个值且值为数组
2、 每一个复选框必须要有value属性 且value 值不能一样
3、 当某一个单选框选中的时候 v-model 会将当前的 value值 改变 data 中的 数据 hobby 的值就是选中的值,,相反data初始化默认的值也就是其默认选中的值

<div id="app">
    <form action="http://itcast.cn">
      <div>
        <span>单行文本框:</span>
        <span>
          <input type="text" v-model='uname'>
        </span>
      </div>
      <div>
        <span>单选框:</span>
        <span>
          <input type="radio" id="male" value="1" v-model='gender'>
          <label for="male"></label>
          <input type="radio" id="female" value="2" v-model='gender'>
          <label for="female"></label>
        </span>
      </div>
      <div>
        <span>多选框:</span>
        <input type="checkbox" id="ball" value="1" v-model='hobby'>
        <label for="ball">篮球</label>
        <input type="checkbox" id="sing" value="2" v-model='hobby'>
        <label for="sing">唱歌</label>
        <input type="checkbox" id="code" value="3" v-model='hobby'>
        <label for="code">写代码</label>
      </div>
      <div>
        <span>下拉框:</span>
        <select v-model='occupation' multiple>
          <option value="0">请选择职业...</option>
          <option value="1">教师</option>
          <option value="2">软件工程师</option>
          <option value="3">律师</option>
        </select>
      </div>
      <div>
        <span>多行文本:</span>
        <textarea v-model='desc'></textarea>
      </div>
      <div>
        <input type="submit" value="提交" @click.prevent='handle'>
      </div>
    </form>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      表单基本操作
    */
    var vm = new Vue({
      el: '#app',
      data: {
        uname: 'lisi',
        gender: 2,
        hobby: ['2','3'],
        // occupation: 3
        occupation: ['2','3'],
        desc: 'nihao'
      },
      methods: {
        handle: function(){
           console.log(this.uname)
           console.log(this.gender)
           console.log(this.hobby[0])
           console.log(this.hobby.toString())
           console.log(this.occupation)
          console.log(this.desc)

        }

![在这里插入图片描述](https://img-blog.csdnimg.cn/37646849d9e74ba2b6470b9c7f18f6c7.png
==注意: 1多个数组用数组表示 2有多个数值的数组可以转为字符串.toString() 以逗号为分隔符 3如果数组为空转成字符串为空 ==

表单域修饰符

number:转化为数值
  • 注意点:
  • 当开始输入非数字的字符串时,因为Vue无法将字符串转换成数值
  • 所以属性值将实时更新成相同的字符串。即使后面输入数字,也将被视作字符串。
trim:去掉开始和结尾的空格
  • 只能去掉首尾的 不能去除中间的空格
lazy : 将input事件切换为change事件
  • lazy 修饰符延迟了同步更新属性值的时机。即将原本绑定在 input 事件的同步逻辑转变为绑定在 change 事件上
<input type="text" v-model.number='age'>
<input type="text" v-model.trim='info'>
<input type="text" v-model.lazy='msg'>

自定义指令

目的:
内置指令不满足需求
Vue允许我们自定义指令

Vue.directive 注册全局指令
<!-- 
  使用自定义的指令,只需在对用的元素中,加上'v-'的前缀形成类似于内部指令'v-if''v-text'的形式。 
-->
<input type="text" v-focus>
<script>
// 注意点: 
//   1、 在自定义指令中  如果以驼峰命名的方式定义 如  Vue.directive('focusA',function(){}) 
//   2、 在HTML中使用的时候 只能通过 v-focus-a 来使用 
    
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
  	// 当绑定元素插入到 DOM 中。 其中 el为dom元素
  	inserted: function (el) {//inserted被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
    		// 聚焦元素
    		el.focus();
 	}
});
new Vue({
  el:'#app'
});
</script>

注意: el表示指令所绑定的元素

Vue.directive 注册全局指令 带参数
 <input type="text" v-color='msg'>
 <script type="text/javascript">
    /*
      自定义指令-带参数
      bind - 只调用一次,在指令第一次绑定到元素上时候调用

    */
    Vue.directive('color', {
      // bind声明周期, 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置 与inserted作用类似可替换使用
      // el 为当前自定义指令的DOM元素  
      // binding 为自定义的函数形参   通过自定义属性传递过来的值 存在 binding.value 里面
      bind: function(el, binding){
        // 根据指令的参数设置背景色
        // console.log(binding.value.color)
        el.style.backgroundColor = binding.value.color;
      }
    });
    var vm = new Vue({
      el: '#app',
      data: {
        msg: {
          color: 'blue'
        }
      }
    });
  </script>
自定义指令局部指令
  • 局部指令,需要定义在 directives 的选项 用法和全局用法一样
  • 局部指令只能在当前组件里面使用
  • 当全局指令和局部指令同名时以局部指令为准
<input type="text" v-color='msg'>
 <input type="text" v-focus>
 <script type="text/javascript">
    /*
      自定义指令-局部指令
    */
    var vm = new Vue({
      el: '#app',
      data: {
        msg: {
          color: 'red'
        }
      },
   	  //局部指令,需要定义在  directives 的选项
      directives: {
        color: {
          bind: function(el, binding){
            el.style.backgroundColor = binding.value.color;
          }
        },
        focus: {
          inserted: function(el) {
            el.focus();
          }
        }
      }
    });
  </script>

计算属性 computed

  • 模板中放入太多的逻辑会让模板过重且难以维护 使用计算属性可以让模板更加的简洁
  • 计算属性是基于它们的响应式依赖进行缓存的
  • computed比较适合对多个变量或者对象进行处理后返回一个结果值,也就是数多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化
  • 计算属性不能传参数只是一个属性
<div id="app">
     <!--  
        当多次调用 reverseString  的时候 
        只要里面的 num 值不改变 他会把第一次计算的结果直接返回
		直到data 中的num值改变 计算属性才会重新发生计算
     -->
    <div>{{reverseString}}</div>
    <div>{{reverseString}}</div>
     <!-- 调用methods中的方法的时候  他每次会重新调用,而且方法调用必须加() -->
    <div>{{reverseMessage()}}</div>
    <div>{{reverseMessage()}}</div>
    <!-- 计算属性与data属性无区别只不过计算属性需要return返回,methods中函数调用需要加() -->
    <input v-model="reverseString" type="text">
    <input v-model="reverseMessage()" type="text">
  </div>
  <script type="text/javascript">
    /*
      计算属性与方法的区别:计算属性是基于依赖进行缓存的,而方法不缓存
    */
    var vm = new Vue({
      el: '#app',
      data: {
        msg: 'Nihao',
        num: 100
      },
      methods: {
        reverseMessage: function(){
          console.log('methods')
          return this.msg.split('').reverse().join('');
        }
      },
      //computed  属性 定义 和 data 已经 methods 平级 
      computed: {
        //  reverseString   这个是我们自己定义的名字 
        reverseString: function(){
          console.log('computed')
          var total = 0;
          //  当data 中的 num 的值改变的时候  reverseString  会自动发生计算  
          for(var i=0;i<=this.num;i++){
            total += i;
          }
          // 这里一定要有return 否则 调用 reverseString 的 时候无法拿到结果    
          return total;
        }
      }
    });
  </script>

注意:
1. computed里面的属性可以看做是data中的属性,在页面展示上没有什么区别
2. 函数一定要有return返回值否则不起作用
3. 方法和计算属性的区别就是方法每次调用都重新计算,而计算属性是基于它们的依赖data中属性值得改变进行缓存的,属性值不变的情况下无论调用多少次查的都是缓存提升效率
4. 计算属性中包含有data中属性值的复杂运算,随着data属性中的改变才会改变
5. 计算属性与data属性无区别只不过计算属性需要return返回,methods中函数调用需要加()
6. computed属性 定义 和 data 已经 methods 平级
7. 计算属性不能传参数只是一个属性

侦听器 watch

  • 使用watch来响应数据的变化
  • 一般用于异步或者开销较大的操作
  • ==watch 中的属性 一定是data 中 已经存在的数据 ==
  • 当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听
  • watch属性 定义 和 data 已经 methods 平级
监听普通属性字段
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <div>
      <span>用户名:</span>
      <span>
        <input type="text" v-model.lazy='uname'>
      </span>
      <span>{{tip}}</span>
    </div>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*      
      侦听器
      1、采用侦听器监听用户名的变化
      2、调用后台接口进行验证
      3、根据验证的结果调整提示信息
    */
    var vm = new Vue({
      el: '#app',
      data: {
        uname: '',
        tip: ''
      },
      methods: {
        checkName: function(uname) {
          // 调用接口,但是可以使用定时任务的方式模拟接口调用
          var that = this;
          setTimeout(function(){
            // 模拟接口调用
            if(uname == 'admin') {
              that.tip = '用户名已经存在,请更换一个';
            }else{
              that.tip = '用户名可以使用';
            }
          }, 2000);
        }
      },
      watch: {
        uname: function(newVal, oldVal){
          // 调用后台接口验证用户名的合法性
          this.checkName(newVal);
          // 修改提示信息
          this.tip = '正在验证...';
        }
      }
    });

  </script>
</body>
</html>
深度监听对象
var vm=new Vue({
    data:{
        a:1,
        b:{
            c:1
        }
    },
    watch:{
        a(val, oldVal){//普通的watch监听
            console.log("a: "+val, oldVal);
        },
        b:{//深度监听,可监听到对象、数组的变化
            handler(val, oldVal){
                console.log("b.c: "+val.c, oldVal.c);//但是这两个值打印出来却都是一样的
            },
            deep:true
        }
    }
})
vm.a=2
vm.b.c=2

a是一个普通的值,当a的值变化时会被监听到,b是一个对象,不能直接像a那么写,需要深度监听才能捕捉到,但是当我想去捕捉b对象中某一个值的变化时却发现,打印出来的两个值是不一样的,如图:
在这里插入图片描述
这样就只能知道对象发生变化却不知道具体哪个值发生了变化,如果想监听对象某一个值得变化可以利用计算属性computed

var vm=new Vue({
    data:{
        b:{
            c:1
        }
    },
    watch:{
        newValue(val, oldVal){
            console.log("b.c: "+val, oldVal);
        }
    },
    computed: {
      newValue() {
        return this.b.c
      }
    }
})

用watch去监听computed计算过的值就可以直接知道是哪个对应的值发生了变化,结果如图:
在这里插入图片描述

过滤器(3.0x已经移除)

  • Vue.js允许自定义过滤器,可被用于一些常见的文本格式化。
  • 过滤器可以用在两个地方:双花括号插值和v-bind表达式。
  • 过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示
  • 支持级联操作
  • 过滤器不改变真正的data,而只是改变渲染的结果,并返回过滤后的版本
  • 全局注册时是filter,没有s的。而局部过滤器是filters,是有s的
  • filters 属性 定义 和 data 已经 methods 平级
  • 定义filters 中的过滤器为局部过滤器
  • 在 3.x 中,过滤器已移除,且不再支持。取而代之的是,我们建议用方法调用或计算属性来替换它们。
全局过滤器
Vue.filter(‘过滤器名称’, function(value){
// 过滤器业务逻辑
})
局部过滤器
filters:{
capitalize: function(){}
}
过滤器的使用
<div>{{msg | upper}}</div> 
<div>{{msg | upper | lower}}</div> 
<div v-bind:id=“id | formatId"></div>
带参数的过滤器
Vue.filter(‘format’, function(value, arg1){
// value就是过滤器传递过来的参数
})

<div>{{date | format(‘yyyy-MM-dd')}}</div>
<div id="app">
    <input type="text" v-model='msg'>
      <!-- upper 被定义为接收单个参数的过滤器函数,表达式  msg  的值将作为参数传入到函数中 -->
    <div>{{msg | upper}}</div>
    <!--  
      支持级联操作
      upper  被定义为接收单个参数的过滤器函数,表达式msg 的值将作为参数传入到函数中。
	  然后继续调用同样被定义为接收单个参数的过滤器 lower ,将upper 的结果传递到lower中
 	-->
    <div>{{msg | upper | lower}}</div>
    <div :abc='msg | upper'>测试数据</div>
  </div>

<script type="text/javascript">
   //  lower  为全局过滤器     
   Vue.filter('lower', function(val) {
      return val.charAt(0).toLowerCase() + val.slice(1);
    });
    var vm = new Vue({
      el: '#app',
      data: {
        msg: ''
      },
       //filters  属性 定义 和 data 已经 methods 平级 
       //  定义filters 中的过滤器为局部过滤器 
      filters: {
        //   upper  自定义的过滤器名字 
        //    upper 被定义为接收单个参数的过滤器函数,表达式  msg  的值将作为参数传入到函数中
        upper: function(val) {
         //  过滤器中一定要有返回值 这样外界使用过滤器的时候才能拿到结果
          return val.charAt(0).toUpperCase() + val.slice(1);
        }
      }
    });
  </script>

常用:
日期格式化

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<div id="app">
    <div>{{msg | formatTime('yyyy/MM/dd')}}</div>
    <div>{{formatTimes(msg,'yyyy/MM/dd')}}</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    /*
      计算属性
    */
    var vm = new Vue({
        el: '#app',
        data: {
            msg: '2021-09-12 05:23:34'
        },
        computed: {
            reverseString: function(date, fmt){
                var date = new Date(date);
                if (/(y+)/.test(fmt)) {
                    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
                }
                var o = {
                    'M+': date.getMonth() + 1,
                    'd+': date.getDate(),
                    'h+': date.getHours(),
                    'm+': date.getMinutes(),
                    's+': date.getSeconds()
                };
                for (var k in o) {
                    if (new RegExp('('+k+')').test(fmt)) {
                        var str = o[k] + '';
                        fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : ('00' + str).substr(str.length));
                    }
                }
                return fmt;
            }
        },
        methods: {
            formatTimes: function(date, fmt){
                var date = new Date(date);
                if (/(y+)/.test(fmt)) {
                    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
                }
                var o = {
                    'M+': date.getMonth() + 1,
                    'd+': date.getDate(),
                    'h+': date.getHours(),
                    'm+': date.getMinutes(),
                    's+': date.getSeconds()
                };
                for (var k in o) {
                    if (new RegExp('('+k+')').test(fmt)) {
                        var str = o[k] + '';
                        fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : ('00' + str).substr(str.length));
                    }
                }
                return fmt;
            }
        },
        filters: {
            formatTime: function (date, fmt) {
                var date = new Date(date);
                if (/(y+)/.test(fmt)) {
                    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
                }
                var o = {
                    'M+': date.getMonth() + 1,
                    'd+': date.getDate(),
                    'h+': date.getHours(),
                    'm+': date.getMinutes(),
                    's+': date.getSeconds()
                };
                for (var k in o) {
                    if (new RegExp('('+k+')').test(fmt)) {
                        var str = o[k] + '';
                        fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : ('00' + str).substr(str.length));
                    }
                }
                return fmt;
            }
        }

    });
</script>
</body>
</html>

生命周期(重点)

  • 事物从出生到死亡的过程
  • Vue实例从创建 到销毁的过程 ,这些过程中会伴随着一些函数的自调用。我们称这些函数为钩子函数
挂载(初始化相关属性)

① beforeCreate
② created
③ beforeMount
④ mounted

更新(元素或组件的变更操作)

① beforeUpdate
② updated

销毁(销毁相关属性)

① beforeDestroy
② destroyed

常用的 钩子函数
beforeCreate在实例初始化之后,数据观测和事件配置之前被调用 此时data 和 methods 以及页面的DOM结构都没有初始化 什么都做不了
created在实例创建完成后被立即调用此时data 和 methods已经可以使用 但是页面还没有渲染出来
beforeMount在挂载开始之前被调用 此时页面上还看不到真实数据 只是一个模板页面而已
mountedel被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。 数据已经真实渲染到页面上 在这个钩子函数里面我们可以使用一些第三方的插件
beforeUpdate数据更新时调用,发生在虚拟DOM打补丁之前。 页面上数据还是旧的
updated由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。 页面上数据已经替换成最新的
beforeDestroy实例销毁之前调用
destroyed实例销毁后调用
Vue实例的产生过程

① beforeCreate 在实例初始化之后,数据观测和事件配置之前被调用。
② created 在实例创建完成后被立即调用。
③ beforeMount 在挂载开始之前被调用。
④ mounted el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。
⑤ beforeUpdate 数据更新时调用,发生在虚拟DOM打补丁之前。
⑥ updated 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。
⑦ beforeDestroy 实例销毁之前调用。
⑧ destroyed 实例销毁后调用。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <div>{{msg}}</div>
    <button @click='update'>更新</button>
    <button @click='destroy'>销毁</button>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      Vue实例的生命周期 
    */
    var vm = new Vue({
      el: '#app',
      data: {
        msg: '生命周期'
      },
      methods: {
        update: function(){
          this.msg = 'hello';
        },
        destroy: function(){
          this.$destroy();
        }
      },
      beforeCreate: function(){
        console.log('beforeCreate');
      },
      created: function(){
        console.log('created');
      },
      beforeMount: function(){
        console.log('beforeMount');
      },
      mounted: function(){
        console.log('mounted');
      },
      beforeUpdate: function(){
        console.log('beforeUpdate');
      },
      updated: function(){
        console.log('updated');
      },
      beforeDestroy: function(){
        console.log('beforeDestroy');
      },
      destroyed: function(){
        console.log('destroyed');
      }
    });
  </script>
</body>
</html>

数组变异方法

  • 在 Vue 中,直接修改对象属性的值无法触发响应式。当你直接修改了对象属性的值,你会发现,只有数据改了,但是页面内容并没有改变
  • 变异数组方法即保持数组方法原有功能不变的前提下对其进行功能拓展
    | push() | 往数组最后面添加一个元素,成功返回当前数组的长度 |
    | ----------- | ------------------------------------------------------------ |
    | pop() | 删除数组的最后一个元素,成功返回删除元素的值 |
    | shift() | 删除数组的第一个元素,成功返回删除元素的值 |
    | unshift() | 往数组最前面添加一个元素,成功返回当前数组的长度 |
    | splice() | 有三个参数,第一个是想要删除的元素的下标(必选),第二个是想要删除的个数(必选),第三个是删除 后想要在原位置替换的值 |
    | sort() | sort() 使数组按照字符编码默认从小到大排序,成功返回排序后的数组 |
    | reverse() | reverse() 将数组倒序,成功返回倒序后的数组 |

替换数组

  • 不会改变原始数组,但总是返回一个新数组
    | filter | filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。 |
    | ------ | ------------------------------------------------------------ |
    | concat | concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组 |
    | slice | slice() 方法可从已有的数组中返回选定的元素。该方法并不会修改数组,而是返回一个子数组 |

动态数组响应式数据

  • 让 触发视图重新更新一遍,数据动态起来
  • Vue.set(vm.items, indexOfItem, newValue)
  • vm.$set(vm.items, indexOfItem, newValue)
    ① 参数一表示要处理的数组名称
    ② 参数二表示要处理的数组的索引
    ③ 参数三表示要处理的数组的值

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <ul>
      <li v-for='item in list'>{{item}}</li>
    </ul>
    <div>
      <div>{{info.name}}</div>
      <div>{{info.age}}</div>
      <div>{{msg}}</div>
      <input type="button" @click="ddd">
    </div>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      动态处理响应式数据
    */
    var vm = new Vue({
      el: '#app',
      data: {
        list: ['apple', 'orange', 'banana'],
        info: {
          name: 'lisi',
          age: 12
        },
        msg: "23"
      },
      methods: {
        //在方法里改变对象数据是没问题的,页面数据能正常显示
        ddd: function (){
          vm.list[1] = 'lemon';
          vm.msg = 'sdfafds';
        }
      }
    });
    vm.msg = 'sdfafds';//修改属性页面内容发生改变
    vm.list[1] = 'lemon';//直接修改对象属性值,虽然对象属性值改变了但是页面内容不会发生变化
    Vue.set(vm.list,0, 'lemon');//全局方式动态响应数据
    vm.$set(vm.list, 1, 'lemon');//局部方式动态响应数据
    vm.info.gender = 'we';
    vm.$set(vm.info, 'name', 'female');
  </script>
</body>
</html>

组件

  • 组件 (Component) 是 Vue.js 最强大的功能之一
  • 组件可以扩展 HTML 元素,封装可重用的代

组件注册

全局注册
Vue.component(组件名称, {
data: 组件数据,
template: 组件模板内容
})

// 注册一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">点击了{{ count }}次.</button>'
})

全局组件注册后,任何vue实例都可以用

  <div id="app">
     <!-- 
		4、  组件可以重复使用多次 
	      因为data中返回的是一个对象所以每个组件中的数据是私有的
		  即每个实例可以维护一份被返回对象的独立的拷贝   
	--> 
    <button-counter></button-counter>
    <button-counter></button-counter>
    <button-counter></button-counter>
      <!-- 8、必须使用短横线的方式使用组件 -->
     <hello-world></hello-world>
  </div>

<script type="text/javascript">
	//5  如果使用驼峰式命名组件,那么在使用组件的时候,只能在字符串模板中用驼峰的方式使用组件,
    // 7、但是在普通的标签模板中,必须使用短横线的方式使用组件
    //全局注册组件
     Vue.component('HelloWorld', {
      data: function(){
        return {
          msg: 'HelloWorld'
        }
      },
      template: '<div>{{msg}}</div>'
    });
    
    
    
    Vue.component('button-counter', {
      // 1、组件参数的data值必须是函数 
      // 同时这个函数要求返回一个对象  
      data: function(){
        return {
          count: 0
        }
      },
      //  2、组件模板必须是单个根元素
      //  3、组件模板的内容可以是模板字符串  
      template: `
        <div>
          <button @click="handle">点击了{{count}}次</button>
          <button>测试123</button>
			#  6 在字符串模板中可以使用驼峰的方式使用组件	
		   <HelloWorld></HelloWorld>
        </div>
      `,
      methods: {
        handle: function(){
          this.count += 2;
        }
      }
    })
    var vm = new Vue({
      el: '#app',
      data: {
        
      }
    });
  </script>
局部注册
<div id="app">
      <my-component></my-component>
  </div>


<script>
    // 定义组件的模板
    var Child = {
      template: '<div>A custom component!</div>'
    }
    new Vue({
      //局部注册组件  
      components: {
        // <my-component> 将只在父模板可用  一定要在实例上注册了才能在html文件中使用
        'my-component': Child
      }
    })
 </script>

组件注意事项

  • 组件参数的data值必须是函数同时这个函数要求返回一个对象
  • 组件模板必须是单个根元素
  • 组件模板的内容可以是模板字符串
  • 局部组件只能在注册他的父组件中使用
组件命名方式

⚫ 短横线方式

Vue.component('my-component', { /* ... */ })

⚫ 驼峰方式

Vue.component('MyComponent', { /* ... */ })

组件命名注意事项

  • 如果使用驼峰式命名组件,那么在使用组件的时候,只能在字符串模板中用驼峰的方式使用组件,但是在普通的标签模板中,必须使用短横线的方式使用组件
<body>
  <!--普通标签模板-->
  <div id="app">
    <button-counter></button-counter>
    <hello-world></hello-world>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      组件注册注意事项
      如果使用驼峰式命名组件,那么在使用组件的时候,只能在字符串模板中用驼峰的方式使用组件,但是
      在普通的标签模板中,必须使用短横线的方式使用组件
    */
    Vue.component('HelloWorld', {
      data: function(){
        return {
          msg: 'HelloWorld'
        }
      },
      template: '<div>{{msg}}</div>'
    });
    Vue.component('button-counter', {
      data: function(){
        return {
          count: 0
        }
      },
      <!--字符串模板-->
      template: `
        <div>
          <button @click="handle">点击了{{count}}次</button>
          <button>测试123</button>
          <HelloWorld></HelloWorld>
        </div>
      `,
      methods: {
        handle: function(){
          this.count += 2;
        }
      }
    })
    var vm = new Vue({
      el: '#app',
      data: {
        
      }
    });
  </script>
</body>

Vue组件之间传值

props属性

用于子组件接收消息传递的

props属性值类型

⚫ 字符串 String
⚫ 数值 Number
⚫ 布尔值 Boolean
⚫ 数组 Array
⚫ 对象 Object

props属性展现形式
以字符串数组形式列出的 prop
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
以对象形式列出prop设置每个属性的类型(也可以设置默认值)常用

简单写法:

props: {
  fieldString: String,
  fieldNumber: Number,
  fieldBoolean: Boolean,
  fieldArray: Array,
  fieldObject: Object,
  fieldFunction: Function
}

带有默认值写法:

  props: {
    fieldString: {
      type: String,
      default: ''
    },
    fieldNumber: {
      type: Number,
      default: 0
    },
    fieldBoolean: {
      type: Boolean,
      default: true
    },
    fieldArray: {
      type: Array,
      default: () => []
    },
    fieldObject: {
      type: Object,
      default: () => ({})
    },
    fieldFunction: {
      type: Function,
      default: function () { }
    }
  }

Prop 验证

我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。
注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的 property (如 data、computed 等) 在 default 或 validator 函数中是不可用的。

父组件向子组件传值
  • 父组件发送的形式是以属性的形式绑定值到子组件身上。
  • 然后子组件用属性props接收
  • 在props中使用驼峰形式,模板中需要使用短横线的形式字符串形式的模板中没有这个限制
<div id="app">
    <!--父组件发送的形式是以title属性的形式绑定值到子组件menu-item身上-->
    <!--绑定属性使用v-bind或者简化形式: title有效的 content无效-->
    <menu-item :title='ptitle' content='hello'></menu-item>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      父组件向子组件传值-基本使用
    */
    Vue.component('menu-item', {
      props: ['title', 'content'],<!--title属性能接收到数据 content接收不到数据-->
      data: function() {
        return {
          msg: '子组件本身的数据'
        }
      },
      template: '<div>{{msg + "----" + title + "-----" + content}}</div>'
    });
    var vm = new Vue({
      el: '#app',
      data: {
        ptitle: '动态绑定属性'
      }
    });
  </script>
</body>
子组件向父组件传值
  • 子组件用$emit()触发事件
  • $emit() 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据参数可以无限个
  • 父组件用v-on 监听子组件的事件
  • 父组件v-on定义方法的时候可以不加参数@enlarge-text=‘handle’ 或者 @enlarge-text=‘handle($event)’ 表示内容一致,methods中的handle方法需要几个参数就写几个参数
    注意:父组件v-on定义方法的时不要加括号和参数这样会导致方法接收参数的时候有问题,定义不加参数 methods方法中带参数就可以!
<body>
  <div id="app">
    <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
    <!--@enlarge-text表示父组件与子组件绑定的方法,子组件调用该方法时,父组件的handle方法自动调用-->
    <menu-item :parr='parr' @enlarge-text='handle'></menu-item>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      子组件向父组件传值-基本用法
      props传递数据原则:单向数据流
    */
    
    Vue.component('menu-item', {
      props: ['parr'],
      template: `
        <div>
          <ul>
            <li :key='index' v-for='(item,index) in parr'>{{item}}</li>
          </ul>
          <button @click='$emit("enlarge-text",1)'>扩大父组件中字体大小</button>
          <button @click='sonFunction()'>扩大父组件中字体大小</button>
        </div>
      `,
      methods: {
        sonFunction : function (){
          this.$emit("enlarge-text",2);//js中需要加this指向
        }
      }
    });
    var vm = new Vue({
      el: '#app',
      data: {
        pmsg: '父组件中内容',
        parr: ['apple','orange','banana'],
        fontSize: 10
      },
      methods: {
        handle: function(str){
          // 扩大字体大小
          this.fontSize += str;
        }
      }
    });
  </script>
</body>
ref 父组件获取子组件中的data和调用子组件中的方法
vue中ref的基本用法,本页面获取dom元素
<template>
  <div id="app">
    <div ref="testDom">11111</div>
    <button @click="getTest">获取test节点</button>
  </div>
</template>

<script>
export default {
  methods: {
    getTest() {
      console.log(this.$refs.testDom)
    }
  }
};
</script>

在这里插入图片描述
其实ref除了可以获取本页面的dom元素,还可以拿到子组件中的data和去调用子组件中的方法

获取子组件中的data

子组件

<template>
  <div>
      {{ msg }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg: "hello world"
    }
  }
}
</script>

父组件

<template>
  <div id="app">
    <HelloWorld ref="hello"/>
    <button @click="getHello">获取helloworld组件中的值</button>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  components: {
    HelloWorld
  },
  data() {
    return {}
  },
  methods: {
    getHello() {
      console.log(this.$refs.hello.msg)
    }
  }
};
</script>

在这里插入图片描述

调用子组件中的方法

子组件

<template>
  <div>
  </div>
</template>

<script>
export default {
  methods: {
    open() {
      console.log("调用到了")
    }
  }
}
</script>

父组件

<template>
  <div id="app">
    <HelloWorld ref="hello"/>
    <button @click="getHello">获取helloworld组件中的值</button>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  components: {
    HelloWorld
  },
  data() {
    return {}
  },
  methods: {
    getHello() {
      this.$refs.hello.open();
    }
  }
};
</script>

在这里插入图片描述

兄弟之间的传递
  • 兄弟之间传递数据需要借助于事件中心,通过事件中心传递数据
    • 提供事件中心 var hub = new Vue()
  • 传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)
  • 接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名
  • 销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据
<body>
  <div id="app">
    <div>父组件</div>
    <div>
      <button @click='handle'>销毁事件</button>
    </div>
    <test-tom></test-tom>
    <test-jerry></test-jerry>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      兄弟组件之间数据传递
    */
    // 提供事件中心
    var hub = new Vue();

    Vue.component('test-tom', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>TOM:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          hub.$emit('jerry-event', 2);
        }
      },
      mounted: function() {
        // 监听事件
        hub.$on('tom-event', (val) => {
          this.num += val;
        });
      }
    });
    Vue.component('test-jerry', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>JERRY:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          // 触发兄弟组件的事件
          hub.$emit('tom-event', 1);
        }
      },
      mounted: function() {
        // 监听事件
        hub.$on('jerry-event', (val) => {
          this.num += val;
        });
      }
    });
    var vm = new Vue({
      el: '#app',
      data: {
        
      },
      methods: {
        handle: function(){
          hub.$off('tom-event');
          hub.$off('jerry-event');
        }
      }
    });
  </script>
</body>

Vue组件之间的跳转

组件中跳转另一个组件

this.$router.push传参

1.params
this.$router.push()方法中path不能与params同用,否则param会失效,所以用name来指定页面,params来传递数据内容

<template>
  <img src="../../static/images/indexTermianal/teacher.png" alt=""  @click ="go()" >  
</template>
<script>
 methods:{
  go:function(){
    this.$router.push({
      name:'indext',//在路由中定义好的
      params:{
        userId:1
        }
       })
  }
  }
</script>

在目标页面通过this.$route.params获取参数:

  <p>{{this.$route.params.userId}}</p>

2.query
页面通过path和query传递参数,该实例中row为某行表格数据

methods:{
go:function(){
this.$router.push({
path:'/indext',
query:{
userId:1
}
})
}
},

目标页面this.$route.query.userId获取数据

<p>{{this.$route.query.userId}}</p>
组件中跳转另一个组件简单跳转
一个页面走方法直接跳转全路径
getToDealWith(){
            window.location.href = webDataService + '/WoodManage?dealStatus=0'
  },
   var tem = MLibVue.getQueryString('dealStatus');
   js中写一个获取url参数的方法
  MLibVue.getQueryString = function (name) {
    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
    var r = window.location.search.substr(1).match(reg);
    if (r != null) {
        return unescape(r[2]);
    }
    return null;
}
获取完整url自定义跳转

有的时候我们需要预览详情单独打开一个新页面展示,这个时候就需要我们获取跳转的url以及查询数据,然后window.open(url,type)跳转
let href = this.$router.resolve({});返回一个完整的路径
发起组件

detail(record) {
                var self = this;
                let {href} = self.$router.resolve({
                    path: '/newsDetailVue',
                    query: {
                        title: record.newsName,
                        author: record.source,
                        releaseDate: self.encode(record.releaseTime),
                        content: self.encode(record.content),
                    }
                });
                window.open(href, '_blank');
                //window.open([URL], [窗口名称], [参数字符串])
            },
            encode(str) {
            let encode = encodeURI(str);
            let base64 = btoa(encode);
            return base64;
        },

跳转的组件

export default {
    name: "newsDetailVue",
    data(){
        return {
            infoData:{},
            title:null,
            author:null,
            releaseDate:null,
            content:null,
            groupId:null,
            attachments:[],
            noticeInfoId:null,
            flag:null,
            fontType:1,//0大1中2小
        }
    },
    async mounted(){
        let self = this;
        if(self.$route.query.title.trim()){
            self.title = decodeURI(self.$route.query.title.trim());
        }
        if(self.$route.query.author.trim()){
            self.author = decodeURI(self.$route.query.author.trim());
        }
        if(self.$route.query.releaseDate.trim()){
            self.releaseDate = self.decode(self.$route.query.releaseDate.trim());
        }
        if(self.$route.query.content.trim()){
            self.content = self.decode(self.$route.query.content.trim());
        }
    },
    methods:{
        decode(base64){
            let decode = atob(base64);
            let str = decodeURI(decode);
            return str;
        },

index.js 路由

{
            path: '/newsDetailVue',
            name: 'newsDetailVue',
            component(){
                return import("@/page/news/newsDetailVue")
            },
            meta: {
                showMap: false,   //需要显示地图
                showMenu: false,   //需要显示顶部菜单栏
                showLeftMenu: false,   //需要显示顶部菜单栏
                hideAll: true//隐藏包括地图在内的所有东西(单独为新闻管理预览展示全屏内容写的)
            }
        },
语法:

window.open([URL], [窗口名称], [参数字符串])

参数说明:

URL:可选参数,在窗口中要显示网页的网址或路径。如果省略这个参数,或者它的值是空字符串,那么窗口就不显示任何文档。
窗口名称:可选参数,被打开窗口的名称。
   1.该名称由字母、数字和下划线字符组成。
   2."_top""_blank""_selft"具有特殊意义的名称。
       _blank:在新窗口显示目标网页
       _self:在当前窗口显示目标网页
       _top:框架网页中在上部窗口中显示目标网页
   3.相同 name 的窗口只能创建一个,要想创建多个窗口则 name 不能相同。
   4.name 不能包含有空格。
参数字符串:可选参数,设置窗口参数,各参数用逗号隔开。

组件插槽

  • 组件的最大特性就是复用性,而用好插槽能大大提高组件的可复用能力
  • Vue 实现了一套内容分发的 API,将 元素作为承载分发内容的出口。
  • 插槽实质是对子组件的扩展,通过插槽向子组件内部指定位置传递内容。
  • 的出现是为了父组件可以堂而皇之地在子组件中加入内容。
  • 插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制。
与 props 的区别

通过props属性,父组件只能向子组件传递属性、方法而插槽还可以传递带标签的内容、甚至是组件:

插槽的使用
(1)匿名插槽(又叫单个插槽、默认插槽)
  • 就是没有设置name属性的插槽。
  • 这是个匿名插槽(没有name属性),这串字符是匿名插槽的默认值。
  • 可以放置在组件的任意位置。
  • 一个组件中只能有一个匿名插槽。
  • 匿名插槽只能作为没有slot属性的元素的插槽。
  • 一个组件中可以有很多具名插槽,出现在不同的位置。
(2)具名插槽
  • 意思就是具有名字的插槽,名字通过属性name来定义。
  • 这是个具名插槽(有name属性),这串字符是具名插槽的默认值。
<div class="child">
    <h1>子组件</h1>
     <slot name="head">头部默认值</slot>
     <slot name="body">主体默认值</slot>
     <slot>这是个匿名插槽(没有name属性),这串字符是匿名插槽的默认值。</slot>
 </div>

<div class="parent">
 <h1>父组件</h1>
 <child>
     <p slot="body">我是主体</p>
     <p>我是其他内容</p>
     <p slot="footer">我是尾巴</p>
 </child>
 </div>

运行结果 :
父组件
子组件
头部默认值 (具名插槽的默认值被渲染,因为父组件没有为此插槽提供内容)
我是主体 (具名插槽的默认值被覆盖)
我是其他内容 (匿名插槽的默认值被覆盖)
注意:1、

我是尾巴

插槽被丢弃了,因为子组件中没有的插槽与之匹配。
2、 如果子组件中的匿名插槽不存在,则

我是其他内容

也会被丢弃。

(3)在 元素上使用 v-slot 指令

除了上面那个例子中,把slot直接用在普通标签或者上,更推荐在 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供插槽名称,这样就可以定义插槽的内容了:

<base-layout>
  <template v-slot:header>
    <h1>我是头header</h1>
  </template>

  <p>我是main的内容111</p>   
  <p>我也是main的内容222</p>

  <template v-slot:footer>
    <p>我是footer</p>
  </template>
</base-layout>

1、带有 v-slot 的 元素中的所有内容都将会被传入相应的插槽。
2、任何没有被包裹在带有 v-slot 的 中的内容都会被视为默认插槽的内容。

如果你希望更明确一些,可以在一个 中包裹默认插槽的内容:

<base-layout>
  <template v-slot:header>
    <h1>我是头header</h1>
  </template>

  <template v-slot:default> 
    <p>我是main的内容111</p>
    <p>我也是main的内容222</p>
  </template>

  <template v-slot:footer>
      <p>我是footer</p>
  </template>
</base-layout>

以上两种写法的渲染效果是一样的:

注意: v-slot 只能添加在 上。 (只有一种例外情况),请继续往下看。

(4)作用域插槽

上面props的例子,可以看到 父组件传给子组件了一个属性和一个方法,子组件可以使用 props 中的属性和方法。那对于插槽来说,父组件想访问子组件的数据,又该怎么做呢?
为了让 childUser 在父级的插槽内容中可用,需要把 childUser 从 子级作用域传递到 父级作用域。
做法就是将 childUser 作为 元素的一个属性绑定上去:

<!-- <Child> 组件: -->
<template>
  <div>
    <h1>hey,我是组件Child的标题</h1>
    <slot v-bind:childData="childUser"></slot>
  </div>
</template>
<script>
export default {
  data() {
     return {
        childUser: { Name:"Tom", Age:23 }
    }
}
</script>

绑定在 元素上的属性childData 被称为插槽 prop。
现在,在父级作用域中,我们可以使用带值的 v-slot 来定义 插槽 prop 的名字:

<!-- 这是父组件<Father>-->
<div>
  <h1>hey,我是父组件Father的标题</h1>
  <Child>
    <template v-slot:default="slotProps">
      {{ slotProps.childData.Name}}
      {{ slotProps.childData.Age}}
    </template>
  </Child>
</div>

v-slot、slot-scope 和 slot

slot 和 slot-scope 已经被废弃,所有的 2.x 版本中 slot 和 slot-scope 属性仍会被支持,但已经被官方废弃且不会出现在 Vue 3 中。
所以更推荐使用vue2.6.0中的 v-slot。
1)v-slot 的使用

1、在一个 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。
2、只有下面这一种情况:当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。 这样我们就可以把 v-slot 直接用在组件标签上。除此之外,v-slot 必须用在 元素上。

<template v-slot:header>
    <h1>Here might be a page title</h1>
 </template>

(2)slot & slot-scope的使用

<template>
  <div>
    <h1>这里是子组件</h1>
    <slot name="mySlot" v-bind:user="childUser"> </slot>
 </div>
</template>
<script>
  export default {
    name: 'Son',
    data() {
      return {
        childUser: { Name: "Tom", Age: 23 }
      }
    }
  }
</script>

<div>
    <h1>hey,我是父组件Father的标题</h1>
    <Son>
      <div slot="mySlot" slot-scope="data">
          {{ data.user.Name }}
          {{ data.user.Age }}
      </div>
    </Son>
  </div>

1、 slot=“default” 可以省略不写,slot可以用在 元素,也可以用在任意的普通元素上。
2、这里的 slot-scope 声明了被接收的 prop 对象会作为 slotProps 变量存在于 作用域中。你可以像命名 JavaScript函数参数一样随意命名 slotProps。同样的,slot-scope可以用在 template元素,也可以用在任意的普通元素上。

前后端交互

VUE HTTP调用方式总结(常用的)

引入vue-resource包 使用Vue.http (少用)

本身不是异步的所以常与promise结合使用

  • 1.引入组件npm i --save vue-resource
  • 2.在main.js中引入并使用
import VueResource from "vue-resource"
Vue.use(VueResource);
Vue.http.options.emulateHTTP = true;
Vue.http.options.emulateJSON = true;

1)get方式

Vue.http.get('url',{
        param1:value1,  
        param2:value2  
    }).then(function(response){  
        // response.data中获取ResponseData实体
    },function(response){  
        // 发生错误
    });

2)post方式

Vue.http.post('url',{  
        param1:value1,  
        param2:value2  
    },{  
        emulateJSON:true  
    }).then(function(response){  
        // response.data中获取ResponseData实体
    },function(response){  
        // 发生错误
    });
引入Jquery.js使用ajax(少用)
  • 1在static文件夹下创建js文件夹把jquery.js导入
  • 2在index.html中引入jquery.js
<script src="static/js/jquery-2.1.3.min.js"></script>
var formData = new FormData();//格式化表单数据
$.ajax({
          url: url,
          type: "post",
          data: formData,
          // ajax传文件 一定要指定两个关键性的参数
          contentType: false,  // 不用任何编码 因为formdata对象自带编码 django能够识别该对象
          processData: false,  // 告诉浏览器不要处理我的数据 直接发就行
          ContentType: 'multipart/form-data',  // 此接口后台需要form表单格式,故加此header
          success(result) {
           
          }, error(err) {
          
          }
        })
axios异步同步(常用)

注意:axios默认是异步请求数据的,如果需要同步获取数据的话,需要进行async 及await 设置。
引入: axios

npm install --save axios
import axios from 'axios'
1get方式
axios.get('url', {
        params: {
            param1: value1,
            param2:value2
        }
    }).then(function (response) {
        // response.data中获取ResponseData实体
    }).catch(function (error) {
        // 发生错误
    });
 2)post方式:默认json格式
 axios.post('/user', {
        firstName: 'Fred',
        lastName: 'Flintstone'
    }).then(function (response) {
        // response.data中获取ResponseData实体
    }).catch(function (error) {
        // 发生错误
    });
fetch vue中替代ajax(看情况)
  • Fetch API是新的ajax解决方案 Fetch会返回Promise
  • fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。
1)post方式
//传统方式拼接
fetch(url,{ // get 请求可以省略不写 默认的是GET 
	method: 'get' //默认可以不写
}
     ).then(result => {
          self.departmentList = result.data ? result.data : [];
          console.log('self.getDepartment2=====', self.departmentList);
        }, function (error) {  //其他http错误
          console.log("error=======", error);
          //self.$router.push('/');
        });
2)post方式
fetch(url, {
          method: 'post', body: formData,
        headers: { 'Content-Type': 'application/json' }
      }).then(result => {
          self.departmentList = result.data ? result.data : [];
          console.log('self.getDepartment2=====', self.departmentList);
        }, function (error) {  //其他http错误
          console.log("error=======", error);
          //self.$router.push('/');
        });

异步

  • JavaScript的执行环境是「单线程」
  • 所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任务。这个任务可称为主线程
  • 异步模式可以一起执行多个任务
  • JS中常见的异步调用
    • 定时任何
    • ajax
    • 事件函数

promise

  • 主要解决异步深层嵌套的问题
  • promise 提供了简洁的API 使得异步操作更加容易
  • Promise基本使用 我们使用new来构建一个Promise Promise的构造函数接收一个参数,是函数,并且传入两个参数: resolve,reject, 分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数
  • axios与fetch以及Vue.http返回的都是promise方面异步处理成功与失败
<script type="text/javascript"> 
/*1. Promise基本使用 我们使用new来构建一个Promise Promise的构造函数接收一个参数,是函数,并且传入两个参数: resolve,reject, 分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数 */
var p = new Promise(function(resolve, reject){ //2. 这里用于实现异步任务 
	setTimeout setTimeout(function(){ var flag = false; if(flag) { //3. 正常情况 
	resolve('hello'); }else{ //4. 异常情况 
	reject('出错了'); } }, 100); }); // 5 Promise实例生成以后,可以用then方法指定resolved状态和reject状态的回调函数
// 在then方法中,你也可以直接return数据而不是Promise对象,在后面的then中就可以接收到数据了 
p.then(function(data){ console.log(data) },function(info){ console.log(info) }); 
</script>	

这几种请求方式在项目中的应用:
第一步:在src下创建文件夹api添加两个js文件名字随意,其中api.js是整个组件公共调用方法,request.js是一些最基础的调用请求,给api.js使用的
![在这里插入图片描述](https://img-blog.csdnimg.cn/166d8c9095584a6ab7a881309e777a4f.png
main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
import VueResource from "vue-resource"//http调用包
Vue.use(VueResource);
Vue.use(Antd)
Vue.http.options.emulateHTTP = true;
Vue.http.options.emulateJSON = true;
Vue.config.productionTip = false
Vue.directive('focus', {
  // 当绑定元素插入到 DOM 中。 其中 el为dom元素
  inserted: function (el)
  { // 聚焦元素
    el.focus(); } });
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

公共的request.js方法

import axios from 'axios'
import Vue from "vue";
//第一种方式导出service 引用的时候自己写方法类型
export const service = axios.create({
  //请求头数据
  baseURL:'http://localhost:8042/BlsEcologyMonitoring',
  timeout: 5000
});
//第二种展现形式 把常用的get 和post写好 直接引用时传路径和参数就行
//axios get
export function getAction(url,parameter) {
  return service({
    url: url,
    method: 'get',
    params: parameter
  })
}
//axios post
export function postAction(url,parameter) {
  return service({
    url: url,
    method: 'post',
    data: parameter
  })
}
// promise+http
export let request = {
  app: null,
  request: function (params, url,method) {
    // getUserFromCheckService()
    if (params == null) {
      params = {}
    }
    params = {}
    let self = this;
    let apiUrl = 'http://localhost:8042/BlsEcologyMonitoring'+ url;
    let promise = new Promise(function (resolve, reject) {
      Vue.http.post(apiUrl, params).then((success) => {
          if (success.data) {
            return resolve(success.data);
          } else {
            return reject(success.data);
          }
        },
        function (error) {  //其他http错误
          return reject({status: -1, msg: "服务器返回异常,请联系管理员!"});
        })
    })
    return promise;
  },
}

api.js 公共方法

import {service, getAction, postAction,request} from './request'
import Vue from "vue"
// 获取验证码
function captchaImage(params) {
  return service({
    url: '/zh/styz/getDeviceLists',
    method: 'get',
    params
  })
}
const addRole = (params)=>postAction("/zh/styz/getDeviceLists",params);
const editRole = (params)=>getAction("/zh/styz/getDeviceLists1",params);
function getAnimalVideoList(params) {
  return request.request(params, "/zh/styz/getDeviceLists")
}
export {
  captchaImage,
  editRole,
  addRole,
  getAnimalVideoList
}

test1组件中调用:

<template>
    <div class="zrbhd_dataqhdb_modail" style="position: fixed">
    </div>
</template>
<script>
  import top from "@/components/Top";
  import Child from "@/components/Child";
  import {captchaImage, editRole, getAnimalVideoList} from "@/api/api";
  import axios from 'axios'

  export default {
    name: 'Test',
    components: {
      top,
      Child
    },
    data() {
      return {
        msg: '23',
       }
    },
    mounted() {
      this.getDepartment()//axios调用
      this.getDepartment1()//axios调用
      this.getDepartment2()//promise+http
      this.getDepartment3()//ajax
      this.getDepartment4()//fetch
    },
    methods: {
      //axios第一种展现形式(常用)
      getDepartment() {//axios第一种
        var self = this;
        captchaImage().then(result => {
          self.departmentList = result.data.data ? result.data.data : [];
          console.log('self.departmentList=====', self.departmentList);
        }, function (error) {  //其他http错误
          self.$router.push('/');//跳转首页
        })
      },
      //axios第二种展示形式(常用)
      getDepartment1() {
        var self = this;
        editRole({}).then(result => {
          self.departmentList = result.data.data ? result.data.data : [];
          console.log('self.departmentList=====', self.departmentList);
        }, function (error) {  //其他http错误
          console.log('asdfsaassa', error);
          //self.$router.push('/');
        })
      },
      //promise+http 需要引入vue-resource包 少用
      getDepartment2() {
        var self = this;
        getAnimalVideoList({}).then(result => {
          self.departmentList = result.data.data ? result.data.data : [];
          console.log('self.getDepartment2=====', self.departmentList);
        }, function (error) {  //其他http错误
          console.log("error=======", error);
          //self.$router.push('/');
        })
      },
      //index.html引入jquery调用ajax 少用
      getDepartment3() {
        var self = this;
        var formData = new FormData();//格式化表单数据
        var url = 'http://localhost:8042/BlsEcologyMonitoring/zh/styz/getDeviceLists'
        $.ajax({
          url: url,
          type: "post",
          data: formData,
          // ajax传文件 一定要指定两个关键性的参数
          contentType: false,  // 不用任何编码 因为formdata对象自带编码 django能够识别该对象
          processData: false,  // 告诉浏览器不要处理我的数据 直接发就行
          ContentType: 'multipart/form-data',  // 此接口后台需要form表单格式,故加此header
          success(result) {
            self.departmentList = result.data ? result.data : [];
            //console.log('self.departmentList=====',self.departmentList);
          }, error(as) {
            console.log("as====", as);
          }
        })
      },
      //fetch代替ajax请求方式vue中ajax的替代品
      getDepartment4() {
        var self = this;
        var formData = new FormData();//格式化表单数据
        formData.append("dd","asdfasd");
        var url = 'http://localhost:8042/BlsEcologyMonitoring/zh/styz/getDeviceLists'
        fetch(url, {
          method: 'post', body: formData,
        headers: { 'Content-Type': 'application/json' }
      }).then(result => {
          self.departmentList = result.data ? result.data : [];
          console.log('self.getDepartment2=====', self.departmentList);
        }, function (error) {  //其他http错误
          console.log("error=======", error);
          //self.$router.push('/');
        });
      },
    }
  }
</script>
<style scoped>
</style>

注意:涉及到的跨域问题我用的是后端代码解决跨域,axios还可以添加拦截器做公共拦截处理

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * 跨域问题
 *
 * @author mousejoo
 */
@Configuration
public class CorsConfig {
	private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 1 允许任何域名使用
        corsConfiguration.addAllowedHeader("*"); // 2 允许任何头
        corsConfiguration.addAllowedMethod("*"); // 3 允许任何方法(post、get等)
        return corsConfiguration;
    }
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig()); // 4
        return new CorsFilter(source);
    }


}
axios和ajax区别

axios是通过promise实现对ajax技术的一种封装,就像jQuery实现ajax封装一样。
简单来说: ajax技术实现了网页的局部数据刷新,axios实现了对ajax的封装。
axios是ajax ajax不止axios。
ajax:
本身是针对MVC的编程,不符合现在前端MVVM的浪潮
基于原生的XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案
JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务
axios:
从 node.js 创建 http 请求
支持 Promise API
客户端支持防止CSRF
提供了一些并发请求的接口
使用ajax,不一定要引入jquery,ajax只是将XMLHttpRequest对象还有该对象api组合起来的一个方法,可以自己创建XMLHttpRequest对象来发送请求。

axios 全局配置
# 配置公共的请求头 
axios.defaults.baseURL = 'https://api.example.com'; 
# 配置 超时时间 
axios.defaults.timeout = 2500; 
# 配置公共的请求头 
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; 
# 配置公共的 post 的 Content-Type 
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios 同步样例
同步:
async getfiles() {
   	var result={};
   	var param = new URLSearchParams()
       param.append('id', $("#type").val())
       var url = "/backstage/fileupload/getFileName.action";
   	await axios.post(url, param).then(function (res) {
           if (res.status == 200) {
           	result=res.data.data;
           } else {
               alert("获取失败!");
           }
       });
   	this.filenames=result
   }
axios 拦截器

请求拦截器
1请求拦截器的作用是在请求发送前进行一些操作
2例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易
响应拦截器
1响应拦截器的作用是在接收到响应后进行一些操作
2例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页
请求案例:

// request interceptor
service.interceptors.request.use(config => {
  const token = Vue.ls.get(ACCESS_TOKEN)
  if (token) {
    config.headers[ 'X-Access-Token' ] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
  }
  //update-begin-author:taoyan date:2020707 for:多租户
  // debugger;
  let tenantid = Vue.ls.get(TENANT_ID)
  // let tenantid = ''
  // if (user) {
  //   tenantid = user.channelId;
  // }
  // config.headers[ 'channelId' ] = '402882db7494baab017494e2614e0002'
  //update-end-author:taoyan date:2020707 for:多租户
  if(config.method=='get'){
    if(config.url.indexOf("sys/dict/getDictItems")<0){
      config.params = {
        _t: Date.parse(new Date())/1000,
        ...config.params
      }
    }
  }
  if(typeof(config.params) == "undefined"){
      config.params = {
          ...config.params
      }
  }
  if(window._CONFIG['channelId'] != ''){
      config.params.channelId = window._CONFIG['channelId'];
  }
    if(window._CONFIG['clientType'] != ''){
        config.params.clientType = window._CONFIG['clientType'];
    }
  return config
},(error) => {
  return Promise.reject(error)
})

响应案例:

axios.interceptors.response.use(function (response) { // 当状态码为2xx/3xx开头的进这⾥
    // 对响应数据做点什么
    return response
}, async function (error) { // 响应状态码4xx/5xx进这⾥
    // 对响应错误做点什么
   if (error.response.status === 401) { // ⾝份过期/token⽆效
    //  1.清空vuex的token 
    store.commit('setToken', '')
    store.commit('setRefreshToken', '')
    // 2. 清空本地token 
    localStorage.removeItem('token')
    localStorage.removeItem('refresh_token')
    //  跳转到登录页⾯登录
    router.push({
      path: '/login'
    })
  }     
    return Promise.reject(error)
})
service.interceptors.response.use((response) => {
        var self = this;
        var data =  response.data;
        var requestCode = data.code;
        if(requestCode == 2001 || requestCode==2002 || requestCode==2003 || requestCode==2004){

            var responseUrl = response.request.responseURL;   //获取原请求地址
            var requestData = response.config.data;   //获取原请求参数

            let m_params = new FormData(); //创建form对象

            var token = geturlData().token;
            var userName = geturlData().userName;
            var userId = geturlData().userId;
            // var paraString = location.search;
            // var paras = paraString.split("&");
            //
            // var temStr = decodeURIComponent(paras[0])
            // // var token = temStr.substr(temStr.indexOf("token=") + 6);
            // var token = temStr.substr(temStr.indexOf("token=") + 6,temStr.indexOf("&userName=") - (temStr.indexOf("token=") + 6));
            // var userName = temStr.substr(temStr.indexOf("userName=") + 9,temStr.indexOf("token="));
            // var userId = temStr.substr(temStr.indexOf("userId=") + 7,(temStr.indexOf("token=") - temStr.indexOf("token=") + 6));
            m_params.append('login_token',token);
            m_params.append('resourceId',userId);
            m_params.append('userName', decodeURI(userName));

            $.ajax({
                type:"POST",
                async:false,
                processData: false,
                contentType: false,
                url:window._CONFIG['domianURL'] + '/sys/loginByResource',
                data:m_params,
                success:function(response){
                    if(response.code =='200'){
                        var result = response.result
                        const userInfo = result.userInfo
                        Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
                        Vue.ls.set(USER_NAME, userInfo.userName, 7 * 24 * 60 * 60 * 1000)
                        Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000)
                        Vue.ls.set(UI_CACHE_DB_DICT_DATA, result.sysAllDictItems, 7 * 24 * 60 * 60 * 1000)
                        window.localStorage.setItem('menu',JSON.stringify(result.menu));
                        window.localStorage.setItem('allAuth',JSON.stringify(result.allAuth))
                        window.localStorage.setItem('auth',JSON.stringify(result.auth))
                        window.localStorage.setItem('userInfo',JSON.stringify(result.userInfo))
                        responseUrl = responseUrl+"?token="+result.token;

                        $.ajax({
                            type: "POST",
                            async: false,
                            processData: false,
                            contentType: false,
                            url: responseUrl,
                            data:requestData,
                            success: function (resultData) {
                                data = resultData;
                            },
                            error:function(e){
                                console.log(e.status);
                                console.log(e.responseText);
                            }
                        });

                    }else{
                        reject(response)
                    }
                },
                error:function(e){
                    console.log(e.status);
                    console.log(e.responseText);
                }
            })
        }
        return data;
    }, autoLoginErr)
    const autoLoginErr = (error) => {
  if (error.response) {
    let that=this;
    let data = error.response.data
    const token = Vue.ls.get(ACCESS_TOKEN)
    console.log("------异常响应------",token)
    console.log("------异常响应------",error.response.status)
    switch (error.response.status) {
      case 403:
        break
      case 500:
        break
      case 404:
        break
      case 504:
        break
      case 401:
        break
      default:
        break
    }
  }
  return Promise.reject(error)
};
async/await用法
  • async/await是ES7引入的新语法,可以更加方便的进行异步操作
  • async关键词用于函数上(async函数的返回值是Promise实例对象)
  • await关键子用于async函数当中(await可以得到异步的结果)
async function queryData(id) {
    const ret = await axios.get('/data');
    return ret;
}
queryData.then(ret=>{
    console.log(ret)
})

在这里插入图片描述

常用备注

vue自身特性

1 v-on:click(简写@click)绑定事件加括号和不加括号区别

应该是 Vue 对函数调用表达式额外用了一个函数做了层包装。
事先说明:加与不加括号的区别在于事件对象参数 event 的处理。不加括号时,函数第一个参数为 event,加了括号后,需要手动传入 $event 才能获得事件对象

<input type="button" value="按钮1" v-on:click="fn($event)">
<input type="button" value="按钮1" v-on:click="fn">
methods:{
   fun(e){
        console.log(e)//打印结果一致
      }
   }
2 按钮禁用置灰属性disabled
<el-table-column
                    prop="status"
                    label="操作"
                    align="center"
                    width="300"
                    fixed="right">
                    <template slot-scope="scope">
                        <el-button class="reset_btn_sys" type="text" size="small" @click="operation(scope.row.id,0)"
                                   v-if="status=='0'" :disabled="status=='0' && scope.row.reviewStatus!='0'">通过
                        </el-button>
                        <el-button class="delete_btn_sys" type="text" size="small" @click="operation(scope.row.id,1)"
                                   v-if="status=='0'" :disabled="status=='0' && scope.row.reviewStatus!='0'">驳回
                        </el-button>
                        <el-button class="reset_btn_sys" type="text" size="small" @click="operation(scope.row.id,2)"
                                   v-if="status!='2'" :disabled="!(scope.row.isOnline=='1' && scope.row.reviewStatus=='1')">下线
                        </el-button>
                        <el-button class="reset_btn_sys" type="text" size="small" @click="operation(scope.row.id,3)"
                                   v-if="status!='2'" :disabled="!(scope.row.isOnline=='0' && scope.row.reviewStatus=='1')">上线
                        </el-button>
                        <el-button class="see_btn_sys" type="text" size="small" @click="detail(scope.row)">详情
                        </el-button>
                        <el-button class="delete_btn_sys" type="text" size="small" @click="operation(scope.row.id,4)"
                        >删除
                        </el-button>
                    </template>
                </el-table-column>
3 vue中调用ajax
var url = dataServer + "/pest/mill/addMillManagement"
$.ajax({
    url: url,
    type: "post",
    data: formData,
    // ajax传文件 一定要指定两个关键性的参数
    contentType: false,  // 不用任何编码 因为formdata对象自带编码 django能够识别该对象
    processData: false,  // 告诉浏览器不要处理我的数据 直接发就行
    ContentType: 'multipart/form-data',  // 此接口后台需要form表单格式,故加此header
    success(result) {
        self.$toast(result.msg)
        if(result.code == 0){
            self.$emit("addSuccess")
        }
    }, error() {

    }
})
4 vue中html注意事项

1、如果事件直接绑定函数名称,那么默认会传递事件对象作为事件函数的第一个参数
2、如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递, 并且事件对象的名称必须是$event

<button v-on:click='handle1'>点击1</button>
<button v-on:click='handle2(123, 456, $event)'>点击2</button>
methods: { handle1: function(event) { console.log(event.target.innerHTML) },handle2: function(p, p1, event) { console.log(p, p1) console.log(event.target.innerHTML) this.num++; } }

3、在html中使用data中数据不需要this
4、在函数中想要使用data中数据一定要加this

vue与element组合特性

1 element UI el-table 单元格中超出字省略号显示

filters过滤器

<div class="warninfo_tablebox_clcyfh">
            <el-table
                :data="tableData"
                border>
                <el-table-column
                    label="新闻名称"
                    align="center"
                    prop="newsName">
                </el-table-column>
                <el-table-column
                    prop="description"
                    label="描述"
                    align="center">
                    <template slot-scope="scope">
                        <span>{{ scope.row.description | ellipsis(10) }}</span> --过滤
                    </template>
                </el-table-column>
                <el-table-column
                    prop="status"
                    label="操作"
                    align="center"
                    width="300"
                    fixed="right">
                    <template slot-scope="scope">
                        <el-button class="reset_btn_sys" type="text" size="small" @click="operation(scope.row.id,0)"
                                   v-if="status=='0'" :disabled="status=='0' && scope.row.reviewStatus!='0'">通过
                        </el-button>
                        <el-button class="delete_btn_sys" type="text" size="small" @click="operation(scope.row.id,1)"
                                   v-if="status=='0'" :disabled="status=='0' && scope.row.reviewStatus!='0'">驳回
                        </el-button>
                        <el-button class="reset_btn_sys" type="text" size="small" @click="operation(scope.row.id,2)"
                                   v-if="status!='2'" :disabled="!(scope.row.isOnline=='1' && scope.row.reviewStatus=='1')">下线
                        </el-button>
                        <el-button class="reset_btn_sys" type="text" size="small" @click="operation(scope.row.id,3)"
                                   v-if="status!='2'" :disabled="!(scope.row.isOnline=='0' && scope.row.reviewStatus=='1')">上线
                        </el-button>
                        <el-button class="see_btn_sys" type="text" size="small" @click="detail(scope.row)">详情
                        </el-button>
                        <el-button class="delete_btn_sys" type="text" size="small" @click="operation(scope.row.id,4)"
                        >删除
                        </el-button>
                    </template>
                </el-table-column>
            </el-table>
        </div>

	computed: {},
    filters:{
        ellipsis(value, limit) {
            if (!value) return ''
            if (value.length > limit) {
                return value.slice(0, limit) + '...'
            }
            return value
        },
    },
   mounted() {}

2 elementUI的el-select选择器同时返回选中项的value和label值

<el-select v-model="ruleForm.category" @change="selectedCag" placeholder="请选择项目类别">
          <el-option
          v-for="item in ClaOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value">
        </el-option>
      </el-select>

methods: {
      selectedCag(vId){
        console.log(vId)
        let obj = {};
         obj = this.ClaOptions.find((item)=>{  //这里的ClaOptions就是上面遍历的数据源
             return item.value === vId;  //筛选出匹配数据,这里的value是你遍历数组每一项的value,如果没有对后台返回的数据做处理,一般为id
         });
      console.log(obj.label);//  这里的label就是对应label的
      this.addCagLabel = obj.label  //打印出来的obj.label就是想要的label值

      },   
   }

3 new FormData()传参与params传参

FormData对象的使用:

用一些键值对来模拟一系列表单控件:即把form中所有的元素的name与value组成一个queryString。
异步上传二进制文件。

4 elementUI 表单校验

1.正常校验和自定义校验
<el-form :model="model" :rules="rules" ref="model">
            <div style="display: inline-block">
                <el-form-item prop="newsName" label="新闻标题" :label-position="labelPosition" :label-width="labelWidth">
                    <el-input class="searchInput"
                              v-model="model.newsName"
                              placeholder="请输入新闻标题"
                              filterable
                              clearable
                              remote
                              reserve-keyword
                              size='small'>
                    </el-input>
                </el-form-item>
                <el-form-item prop="description" label="简要描述" :label-position="labelPosition" :label-width="labelWidth">
                    <el-input class="searchInput" v-model="model.description"
                              type="textarea"
                              :autosize="{maxRows: 6}"
                              placeholder="请输入类型描述"
                              filterable
                              clearable
                              remote
                              reserve-keyword
                              size='small'>
                    </el-input>
                </el-form-item>
            </div>
</el-form>

data(){
		//自定义校验
        var contents = (rule, value, callback) => {//新增文件校验
            console.log("content");
            if (value === '' || value==null) {
                callback(new Error('请输入内容'));
            }
            callback();
        };
        return {
            labelPosition:"right",
            labelWidth:"80px",
            rules:{
                description: [
                    {required: true, message: '请输入简要描述', trigger: 'blur'},
                    {pattern: '^[^ ]+$', message: '描述中不能含有空格'},
                ],
                source: [
                    {required: true, message: '请输入来源', trigger: 'blur'},
                    {pattern: '^[^ ]+$', message: '来源中不能含有空格'},
                     { min: 0, max: 20, message: '长度不超过20字符'}
                ],
                newsName: [
                    {required: true, message: '请输入新闻标题', trigger: 'blur'},
                    {pattern: '^[^ ]+$', message: '标题中不能含有空格'},
                ],
                content: [
                    {required: true, validator: contents, trigger: 'change'},
                ],
                fileList:[{required:true, message:"图片不能为空", trigger:"blur"}],
                newsTypeId: [
                    {required: true, message: '请输入新闻内容', trigger: 'change'},
                ],
            },
            model: {
                newsName: "",//新闻内容
                description: "",//描述
                content: "",//富文本编辑器内容
                imagePath: '',//封面path
                newsTypeId: '',//新闻分类id
                status: '',//发布状态0保存1发布2下线3定时发布
                id: '',//数据id
                fileList:[],//图片list
                groupId: '',//富文本编辑器图片的组id
                updateGroupId: '',
                categoryName:'',//新闻分类名称
                source:""//新闻来源
            },
            dialogImageUrl: '',//图片
            dialogVisible: false,
            disabled: false,
            delFileString:[],
            reloading: false,
            selectorId: new Date().getTime(),
            selectorId1: new Date().getTime(),
        }
    },
    mounted() {
        var self = this;

        if(self.isAdd && self.isAdd != 1){
            self.getInfo();
        }
    },
    methods:{
2.表单重置
<el-button v-if="isAdd != 2" @click="reset('model')" class="sys_form_button_pro">重置</el-button>
 reset(formDate) {//重置
            let self = this;
            self.$refs[formDate].resetFields();
        },
3.清除单个验证信息
 this.$refs.addForm.clearValidate(['imagePath']);
4.调用单个验证提示
this.$refs.model.validateField(['content']);
content: [
                    {required: true, validator: contents, trigger: 'change'},
                ],
if(self.model.content != null && self.model.content !=''){
   this.$refs.model.clearValidate(['content']);//清除单个验证信息
  }else{
      this.$refs.model.validateField(['content']);//调用单个表单验证
  }

5 列表复选框

需求:
在使用element中table列表可能会需要复选批量操作,这时我们只要手动添加一个el-table-column,设type属性为selection即可,
element文档中一共给出三个方法分别是手动勾选触发 勾选全选触发 勾选发生变化触发 里面的数据是列表中的每一数据
如果想用方法只需要在开头@方法名 自己在method里定义
在这里插入图片描述
方法:

this. r e f s . m u l t i p l e T a b l e . c l e a r S e l e c t i o n ( ) ; / / 清空所有单选 c l e a r S e l e c t i o n ( ) 这个函数是自带的,比如日期的 g e t F u l l Y e a r ( ) t h i s . refs.multipleTable.clearSelection();//清空所有单选clearSelection()这个函数是自带的,比如日期的getFullYear() this. refs.multipleTable.clearSelection();//清空所有单选clearSelection()这个函数是自带的,比如日期的getFullYear()this.refs.multipleTable.toggleRowSelection(it, true);toggleRowSelection这个函数需要传某行数据,true表示勾选,false表示不勾选,
@selection-change默认是勾选的,也就是说这个事件传进来被选中的数据如果你还是想勾选,那么不需要任何操作,除非你想不勾选,那么就把那条数据用false来去掉勾选。
ref=“multipleTable” ref 被用来给DOM元素或子组件注册引用信息。引用信息会根据父组件的 r e f s 对象进行注册。如果在普通的 D O M 元素上使用,引用信息就是元素 ; 如果用在子组件上,引用信息就是组件实 @ r o w − c l i c k 点击那一行数据触发的事件默认传点击那行的数据,自定义 o n S e l e c t O p ( r o w ) 函数,用 r o w 来接收点击的那行数据,先把所有的选项清空 t h i s . refs 对象进行注册。如果在普通的DOM元素上使用,引用信息就是元素; 如果用在子组件上,引用信息就是组件实 @row-click点击那一行数据触发的事件默认传点击那行的数据,自定义onSelectOp(row)函数, 用row来接收点击的那行数据, 先把所有的选项清空this. refs对象进行注册。如果在普通的DOM元素上使用,引用信息就是元素;如果用在子组件上,引用信息就是组件实@rowclick点击那一行数据触发的事件默认传点击那行的数据,自定义onSelectOp(row)函数,用row来接收点击的那行数据,先把所有的选项清空this.refs.multipleTable.clearSelection();
再把点击的那行勾选this.$refs.multipleTable.toggleRowSelection(row, true);
把自定义数组清空this.selectlist = [];
把新勾选的数据push进数组this.selectlist.push(row);
注意:只要想要在Vue中直接操作DOM元素,就必须用ref属性进行注册

<el-table
                    :data="tableData"
                    ref="multipleTable"
                    v-loading="isLoading"
                    @selection-change="handleChange"
                    border>
                    <el-table-column
                        fixed
                        type="selection"
                        width="36px" v-if="!isSenBY">
                    </el-table-column>
                    <el-table-column
                        label="县局林业局名称"
                        align="center"
                        prop="xianName">
                    </el-table-column>
                    <el-table-column
                        label="乡镇(林场)名称"
                        align="center"
                        prop="linchangName">
                    </el-table-column>
                    <el-table-column
                        label="林班号"
                        align="center"
                        prop="linban">
                    </el-table-column>
                    <el-table-column
                        label="小班号"
                        align="center"
                        prop="xiaobanhao">
                    </el-table-column>
                    <el-table-column
                        label="采集人"
                        align="center"
                        prop="collectPersonName">
                    </el-table-column>
                    <el-table-column
                        label="采集地点"
                        align="center"
                        prop="collectArea">
                    </el-table-column>
                    <el-table-column
                        prop="status"
                        label="操作"
                        align="center"
                        width="200"
                        fixed="right">
                        <template slot-scope="scope">
                            <el-button class="reset_btn_sys" type="text" size="small" :class="{grea:!getPower(scope.row)}"
                                   @click="addRecord(scope.row,getPower(scope.row))">{{ isSenBY ? "核实" : "上报" }}</el-button>
                            <el-button class="editor_btn_sys" type="text" size="small" :class="{grea:!getPower(scope.row)}"
                                  @click="edit(scope.row,getPower(scope.row))">编缉</el-button>
                            <el-button class="see_btn_sys" type="text" size="small" @click="lookInfo(scope.row)">详情</el-button>
                            <el-button class="delete_btn_sys" type="text" size="small" :class="{grea:!(getPower(scope.row)&&!isSenBY)}"
                                  @click="del(scope.row,getPower(scope.row)&&!isSenBY)">删除</el-button>
                        </template>
                    </el-table-column>
                </el-table>

全选中去掉个别选中选项

批量删除有个别数据不允许删除,当用户全选点击批量筛选不能删除数据取消勾选
del(item) {
            var self = this
            var ids = MLib.joinSplit(self.chooseArr, ",", "id")
            if (item == "delBatch") {
                if (ids == "") {
                    new MessageToast().show("请选择记录后再进行删除", MessageToast.ERROR)
                    return
                }
                var arr = self.chooseArr;
                var newChooseArr = [];
                var ble = false;//批量选中数据中是否有巡护员上报不能删除的数据存在
                for(var i=0;i<arr.length;i++){
                    //打印数组中的情况,便于跟踪数组中数据的变化
                    var success = this.getPower(arr[i])//查看该数据是否属于巡护员暂存数据,暂存的可以删除 上报的不可以删除
                    if(success){//能删除的抽取出来
                        //注意对比这行代码:删除元素后调整i的值
                        newChooseArr.push(arr[i]);
                        arr.splice(i,1);
                    }else{//不能删除的去掉
                        ble = true;
                    }
                };
                self.chooseArr = newChooseArr;
                this.$refs.multipleTable.clearSelection();//清空全部选中
                newChooseArr.forEach(row => {//把符合删除条件的数据重新选中
                    this.$refs.multipleTable.toggleRowSelection(row, true);
                });
                if(ble){
                    new MessageToast().show("记录中含有不可选择项,已去掉选中", MessageToast.SINGLETON)
                    return;
                }

                ids = MLib.joinSplit(self.chooseArr, ",", "id")
            } else {
                ids = item.id
            }
            self.$messageBox({
                title: "消息",
                text: "是否要删除记录",
                callback(action) {
                    if (action) {
                        var params = {}
                        params.ids = ids
                        handler.deleteDiscoloredStandingTreeReport(params).then(result => {
                            MLibVue.requestSuccess(result, true)
                            self.search(self.pg.pageIndex)
                        })
                    }
                }
            })
        },

6 循环删除数组中符合条件的元素

for(var i=0;i<arr.length;i++){
     //打印数组中的情况,便于跟踪数组中数据的变化
     var success = this.getPower(arr[i])//查看该数据是否属于巡护员暂存数据,暂存的可以删除 上报的不可以删除
     if(success){//能删除
         //注意对比这行代码:删除元素后调整i的值
         arr.splice(i,1);
     }
 };

7 element常用的消息提示

1删除提醒
del(id) {//点击删除按钮
                this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    var self = this;
                    var params = {};
                    params.id = id;
                    params.idDelete = "1";
                    handler.delNewsManagement(params).then(res => {
                        this.$message({
                            type: 'success',
                            message: '删除成功!'
                        });
                        self.pg.currentPage = 1
                        self.search();
                    })

                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
            },
2失败
self.$message.error(result.msg);

8 下拉选级联

注: 下拉选级联有两种实现方式

1 设置change方法联动
<el-form-item label="">
                <el-select v-model="model.city" placeholder="请选择市林业局名称" size="large" @change="changeData">
                    <el-option
                        v-for='item in MLibVue.getOrganizationList(22)'
                        :key="item.id"
                        :label="item.name"
                        :value="item.id">
                    </el-option>
                </el-select>
            </el-form-item>
            <el-form-item label="">
                <el-select v-model="model.xian" placeholder="请选择县林业局名称" size="large">
                    <el-option
                        v-for='item in xianList'
                        :key="item.id"
                        :label="item.name"
                        :value="item.id">
                    </el-option>
                </el-select>
            </el-form-item>


changeData() {//点击下拉选数据
                var self = this;
                var params = {}
                self.model.xian = null;
                self.model.linChang = "";
                self.linChangList = [];
                params.pid = self.model.city;
                handler.getOrganizationLists(params).then(result => {
                    self.xianList = result.data;
                })
            },
2 使用watch监测数据
<div class="searchItemContent">
            <!--                <div class="searchParams ">市林业局名称</div>-->
            <el-select class="searchInput" v-model="model.city" placeholder="请选择市林业局名称"
                       bind-data="linChang"
                       remote
                       clearable
                       reserve-keyword
                       size='small'>
                <el-option
                    class='forest-query-form-input'
                    v-for='item in MLibVue.getOrganizationList(22)'
                    :key="item.id"
                    :label="item.name"
                    :value="item.id">
                </el-option>
            </el-select>
        </div>
        <div class="searchItemContent">
            <!--                <div class="searchParams ">县林业局名称</div>-->
            <el-select class="searchInput" v-model="model.xian" placeholder="请选择县林业局名称"
                       bind-data="linChang"
                       remote
                       clearable
                       reserve-keyword
                       size='small'>
                <el-option
                    class='forest-query-form-input'
                    v-for='item in xianArr'
                    :key="item.id"
                    :label="item.name"
                    :value="item.id">
                </el-option>
            </el-select>
        </div>
        <div class="searchItemContent">
            <!--                <div class="searchParams ">乡镇(林场)名称</div>-->
            <el-select class="searchInput" v-model="model.linChang" placeholder="请选择乡镇(林场)名称"
                       bind-data="linChang"
                       remote
                       clearable
                       reserve-keyword
                       size='small'>
                <el-option
                    class='forest-query-form-input'
                    v-for='item in linChangArr'
                    :key="item.id"
                    :label="item.name"
                    :value="item.id">
                </el-option>
            </el-select>
        </div>
        <div class="searchItemContent">
            <!--                <div class="searchParams ">林班号</div>-->
            <el-select class="searchInput" v-model="model.linBanCode"
                       bind-data="linBanCode"
                       placeholder="请选择林班号"
                       clearable
                       remote
                       reserve-keyword
                       size='small'>
                <el-option
                    class='forest-query-form-input'
                    v-for='item in linBanArr'
                    :key="item.linban"
                    :label="item.linbanName"
                    :value="item.linban">
                </el-option>
            </el-select>
        </div>
        <div class="searchItemContent">
            <!--                <div class="searchParams ">小班号</div>-->
            <el-select class="searchInput" v-model="model.xiaoBan"
                       bind-data="xiaoBan"
                       placeholder="请选择小班号"
                       remote
                       clearable
                       reserve-keyword
                       size='small'>
                <el-option
                    class='forest-query-form-input'
                    v-for='item in xiaoBanArr'
                    :key="item.xiaoban"
                    :label="item.xiaobanName"
                    :value="item.xiaoban">
                </el-option>
            </el-select>
        </div>
watch: {
            'model.city'(newVal) {
                var self = this
                this.model.xian = ""
                self.xianArr = [];
                MLibVue.getOrganizationList(newVal, (arr) => {
                    self.xianArr = arr
                })

            },
            'model.xian'(newVal) {
                var self = this
                this.model.linChang = ""
                self.linChangArr = [];
                MLibVue.getOrganizationList(newVal, (arr) => {
                    self.linChangArr = arr
                })
            },
            'model.linChang'(newVal) {
                var self = this
                self.model.linBanCode = ""
                self.linBanArr=[];
                if(newVal!=''){
                    var params = {}
                    params.linchang = newVal;
                    handler.getLinBanList(params).then(result => {
                        self.linBanArr = result.data
                    })
                }
            },
            'model.linBanCode'(newVal, oldVal) {
                var self = this
                self.model.xiaoBan = ""
                self.xiaoBanArr=[]
                if(newVal!=''){
                    var params = {}
                    params.linban = newVal
                    handler.getXiaoBanHaoList(params).then(result => {
                        self.xiaoBanArr = result.data
                    })
                }
            },
        },

注意:
为el-select设置clearable属性,则可将选择器清空。需要注意的是,clearable属性仅适用于单选。

前端存储Stroage

什么是前端数据存储
客户端存储是快速为一个应用进行性能优化的绝佳方法。通过把数据存储在浏览器中,用户不必每次都向服务器请求获取同一个信息。在你离线时,使用本地存储的数据而不是向远端服务器上请求数据就显得非常有用,甚至在线用户也可以从中受益。客户端存储可以通过这些技来实现:cookie 、sessionstorage、localstorage(H5 存储 Web Storage )。

localStorage(Web 存储机制)

1.什么是 localStorage
localStorage 对象是存储特定于某个会话的数据,与 sessionStorage 不一样的就在于, localStorage 存储是持久的,不通过手动清除的话,就会一直存在与客户端。
2.localStorage 的特点

localStorage 会将第一次请求的数据直接存储在本地,可以存储 5M 数据,相比于 cookie 可以解决带宽,但只有高版本浏览器中才支持。
目前所有浏览器都会把 localStorage 的值类型限定为 string 类型,对于我们比较常见的 JSON 对象类型需要转换。
localStorage 本质上是对字符串的读取,如果存储内容多的话会小号内存空间,导致页面变卡。

3.localStorage 的用法

localStorage.setItem('menuInfo', JSON.stringify(this.menuInfo))//将菜单对象信息转成json存在本地
let str = localStorage.getItem('menuInfo');//本地获取json信息转成对象
            if (str) {
                this.menuInfo = JSON.parse(str);
            }
window.localStorage.removeItem("userInfo");//移除            

cookie

1、cookie 的作用
cookie 是比较老的前端缓存技术,使用 cookie 必须要有服务器(HTML 静态网页无效),存储的大小限制在 4k。为什么要有服务才能使用 cookie 呢?因为 cookie 是要在服务器和浏览器来回输送的,由于浏览器的的跨域限制,客户端和服务端必须保证是同源策略(也就是跨域)。而且 cookie 是存放在前端的,安全一直以来是个问题,适合使用一些会话信息传输。

2、cookie 的构成
一般来说,cookie 是有浏览器保存的以下几块信息构成的。
1.名称:cookie 名称,是个唯一值。
2.值:存储在 cookie 中的字符串值,值必须被 URL 编码。
3.域:cookie 对于哪个域是有效的,所有向该域发送的请求都会包含这个 cookie 信息。
4.路径:对于指定域中的路径,应该向服务器发送 cookie。
5.失效时间:表示 cookie 何时应该被删除的时间戳。
6.安全标志:指定后,cookie只有在使用SSL连接的时候才发送到服务器。
3. cookie 存储和获取

// 设置 cookie
function setCookie(name,value,options={}){
    let cookieData = `${name}=${value};`;
    for(let key in options){
        let str = `${key}=${options[key]};`;
        cookieData += str;
    };
    document.cookie = cookieData;
};

// 获取 cookie
function getCookie(name){
    let arr = document.cookie.split("; ");
    for(let i =0;i<arr.length;i++){
        let arr2 = arr[i].split("=");
        if(arr2[0]==name){
            return arr2[1];
        };
    };
    return "";
};

export function setCookie(c_name, value, expire) {
    var date = new Date()
    date.setSeconds(date.getSeconds() + expire)
    document.cookie = c_name + "=" + escape(value) + "; expires=" + date.toGMTString()
    // console.log(document.cookie)
}

/*获取cookie*/
export function getCookie(c_name) {
    if (document.cookie.length > 0) {
        let c_start = document.cookie.indexOf(c_name + "=")
        if (c_start != -1) {
            c_start = c_start + c_name.length + 1
            let c_end = document.cookie.indexOf(";", c_start)
            if (c_end == -1) c_end = document.cookie.length
            return unescape(document.cookie.substring(c_start, c_end))
        }
    }
    return ""
}

/*删除cookie*/
export function delCookie(c_name) {
    setCookie(c_name, "", -1)
}

sessionStorage

1.什么是 sessionStorage
sessionStorage 对象是存储特定于某个会话的数据,也就是数据只保存到浏览器关闭后消失,存储在 sesstionStorage 中的数据可以跨页面刷新而存在。
2.sessionStorage 的特点

同源策略限制,若想在同一个页面之间对同一个 sessionStorage 进行操作,这些页面必须是同协议、域名、端口号。
单标签页限制,sesstionStorage 操作限制在单个标签页中,在此标签页进行同源页面访问都可以共享 sesstionStorage 数据。
只在本地存储,seesionStorage 的数据不会跟随HTTP请求一起发送到服务器,只会在本地生效,并在关闭标签页后清除数据。
存储方式,seesionStorage 的存储方式采用 key、value 的方式。
存储上限限制,不同的浏览器存储的上限也不一样,但大多数浏览器把上限限制在 5MB 以下。

3.sessionStorage 的用法

sessionStorage.length  // 获取 storage 的个数
sessionStorage.key(n)  // 获取 storage 中第 n 个元素对的键值
sessionStorage.getItem(key)  // 获取 key 对应的值
sessionStorage.key    // 获取键值 key 对应的值
sessionStorage.setItem(key, value)  // 添加数据,键值为 key,值为 value
sessionStorage.removeItem(key)  // 移除键值为 key 的值
sessionStorage.clear()  // 清除所有数据
新增新闻中预览内容
detail(type) {
            var self = this;
            if(type==1){//新增预览
                sessionStorage.setItem("xinzengcontent", self.encode(self.model.content));//把新闻base64存储在本地
                let {href} = self.$router.resolve({
                    path: '/newsDetailVue1',
                    query: {
                        type:"0",
                        title: self.model.newsName,
                        author: self.model.source,
                        releaseDate: self.encode(""),
                    }
                });
                window.open(href, '_blank');//打开新窗口展示
          
        },
 
 if(sessionStorage.getItem('xinzengcontent')){
       self.content = self.decode(sessionStorage.getItem('xinzengcontent'));//接收数据并解析数据
  }       
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值