JavaScript、jQuery、Vue、Ajax、Json的理解

  • JavaScript是前端开发语言,经常与html、css技术一起构成前端开发,JavaScript一般通过Ajax与后台进行数据交互。
  • Ajax是一种结合了Java、XML以及JavaScript等编程开发技术,全称 Asynchronous JavaScript andXML(异步js和xml),能提供异步更新的机制,换句话说就是能够实现网页部分更新,再具体就是表格添加更新删除操作之后,也只是表格进行刷新,菜单栏不会随网页刷新。使用他时,就会用到Json进行传输。Ajax致力于创建交互式网页应用,核心是XmlHttpRequest。
  • Json是种数据传输格式,我们知道,前后端传输都是字符串类型,那么将对象属性进行分别赋值形如key:value,这样前后端处理来就会很方便。因此服务端就会有Json文件,前端接收并处理即可。格式一般是:{“key1”:obj,“key2”:obj,“key3”:obj…}。
  • jQuery与Vue是一种框架,都是基于JavaScript语言而开发的框架,以jQuery为例,他大大简化了JavaScript程序的语言编写,如一些取值,赋值等等,同时也集合了Ajax的技术。总的来说,jQuery封装了JavaScript和Ajax的功能,使得前后端交互开发更为方便便捷。

首先先知道前后端的交互有三种方法:

  1. 通过ajax将已经封装好的Json数据对象传到服务器后台(主流)
  2. 通过表单action提交到服务器后台(次)
  3. 通过dom获取标签,触发标签的submit方法,直接提交数据到后台(少)

下面分别对

  1. JavaScript基本的赋值操作作示例;
  2. 用传统ajax和json方式进行前后端交互如增删查改。
  3. jQuery实现上面的功能并比较。

1. JavaScript基本的赋值操作作示例;

1)html中id和name的区别

根据我的理解,id是唯一的,name可以重复。一般给控件赋值的时候会用到getElementById获取控件并进行赋值。而name是多用于表单中提交数据时用,表单叫有name的传到服务器,服务器根据name对应取到相应的值。同时,一样的name,赋值也是一样的。

<form>
    <input type="radio" name="num" value="A">数字1</input>
    <input type="radio" name="num" value="B">数字2</input>
    <input type="radio" name="num" value="C">数字3</input>
    <input type="radio" name="num" value="D">数字4</input>
</form>
<br>
<form>
    <input type="radio" name="num1" value="A">数字1</input>
    <input type="radio" name="num2" value="B">数字2</input>
    <input type="radio" name="num3" value="C">数字3</input>
    <input type="radio" name="num4" value="D">数字4</input>
</form>

在这里插入图片描述

2)赋值

html
span标签只能用innerText进行内容注入,像input这些有value属性的也只能getElementById(“id”).value来注入

jsid:account:innerText<span id="account" name="account"></span><br>
jsid:password:innerText<span id="password" name="password"></span><br>
jsid:account:value:<input id="account1" ><br>
jsid:password:value:<input id="password1" ><br>
jsid:password:innerText:<input id="password2"  type="text" ><br>

JavaScript
这里是前端controller传了一个cookie值,简单点可以直接赋值

<script>
   // var account = '${cookie.account.value}';
    // var password = '${cookie.password.value}';
    var arrstr = document.cookie.split("; ");
    // cookie值是这样的->  account=xxxx;password=xxxx
    for (var i = 0; i < arrstr.length; i++) {
        var temp = arrstr[i].split("=");
        if (temp[0] == "account"){
            document.getElementById("account").innerText = temp[1];
            document.getElementById("account1").value = temp[1];
        }
        if (temp[0] == "password"){
            document.getElementById("password").innerText = temp[1];
            document.getElementById("password1").value = temp[1];
            document.getElementById("password2").innerText = temp[1];
        }
    }
    // document.getElementById("shenfen").value=account;
</script>

controller

@GetMapping("login")
    public String login(String account, String password, String captcha, Model model,HttpServletResponse response) {

        // 新建Cookie
        Cookie account_cookie = new Cookie("account", account);
        Cookie password_cookie = new Cookie("password", password);
        // 输出到客户端
        response.addCookie(account_cookie);
        response.addCookie(password_cookie);
        model.addAttribute("account",account);
        if(this.adminService.login(account,password)!=null&&captcha.equals("xszg"))
            return "OK";
        return "OK";
    }
    

还有一种是getElementById(“id”).innerHtml="< h1 >xxxxx</ h 1 >";是注入标签.

元素的获取分两种,getElementByxx和querySelectorxx
,前者是获取动态集合,后者是静态集合。具体去看这里->传送门

2. 用传统ajax和json方式进行前后端交互如增删查改。

主要用到XmlHttpRequest对象

  1. 首先创建XMLHttpRequest 对象->xmlhttp
  2. 利用xmlhttp.open(method,URL,async);发送请求
    第一参数为传递的方法可以使post 或者get ,
    第二个参数是url的地址,可以是servlet、jsp、或者txt等
    第三个参数是布尔变量,表示是否是异步 true(异步)或 false(同步
    ———————————

为何要用到setRequestHeader
通常在HTTP协议里,客户端像服务器取得某个网页的时候,必须发送一个HTTP协议的头文件,告诉服务器客户端要下载什么信息以及相关的参数。而 XMLHTTP 就是通过HTTP协议取得网站上的文件数据的,所以也要发送HTTP头给服务器。 但是 XMLHTTP 默认的情况下有些参数可能没有说明在HTTP头里,这是当我们需要修改或添加这些参数时就用到

具体实现看这里->传送门

3. jQuery实现上面的功能并比较。

首先比较jQuery与js的基本操作区别->原链接传送门

1 定位元素 
JS 
document.getElementById("abc") 

jQuery 
$("#abc") 通过id定位 
$(".abc") 通过class定位 
$("div") 通过标签定位 

需要注意的是JS返回的结果是这个元素,jQuery返回的结果是一个JS的对象。以下例子中假设已经定位了元素abc。 

2 改变元素的内容 
JS 
abc.innerHTML = "test";                //现在的项目中有用到
jQuery 
abc.html("test"); 

3 显示隐藏元素 
JS 
abc.style.display = "none";              //现在的项目中有用到
abc.style.display = "block"; 

jQuery 
abc.hide(); 
abc.show();

abc.toggle();         //在显示和隐藏之间切换、


4 获得焦点 

JS和jQuery是一样的,都是abc.focus(); 

5 为表单赋值 
JS 
abc.value = "test"; 
jQuery 
abc.val("test"); 

6 获得表单的值 
JS 
alert(abc.value); 
jQuery 
alert(abc.val()); 

7 设置元素不可用 
JS 
abc.disabled = true; 
jQuery 
abc.attr("disabled", true);

8 修改元素样式
JS
abc.style.fontSize=size;
jQuery
abc.css('font-size', 20);

JS
abc.className="test";
JQuery
abc.removeClass(); 
abc.addClass("test");

9 判断复选框是否选中

jQuery
if(abc.attr("checked") == "checked")
注意:网上说的.attr("checked") == true实际上不能用,上面这个测试过能

4.vue学习

MVVM架构

在这里插入图片描述

v-for的应用

用vue简单制作一个表格

通过此例子来贯穿所有的基本知识

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>

		<!--css-->
		<style type="text/css">
			table tr th {
				background: #f7f7f7;
			}

			table,
			table tr th,
			table tr td {
				border: 1px solid #eaeaea;
			}

			table {
				min-width: 200px;
				min-height: 25px;
				line-height: 25px;
				text-align: center;
				border-collapse: collapse;
			}
		</style>
	</head>
	<body>
		<div id="book">
			{{ message }}
			<table>
				<tr>
					<!-- <th>序号</th> -->
					<th v-for="th in tableTh">
						{{th.title}}
					</th>
				</tr>
				<tr v-for="(tr,index) in bookList" :key="tr.id">
					<!-- <td>{{index+1}}</td> -->
					<td>{{tr.id}}</td>
					<td>{{tr.name}}</td>
					<td>{{tr.date}}</td>
					<td>{{formatprice(tr.price)}}</td>
					<td><button v-on:click="tr.num -= 1" :disabled="tr.num <1">-</button> {{tr.num}} <button v-on:click="tr.num += 1">+</button></td>
					<td><button v-on:click="remove(index)">移除</button></td>
				</tr>

			</table>
			<h3>总价格: {{formatprice(totalSumAll)}}</h3>
		</div>
		<!-- js最后引入-->
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			var book = new Vue({
				el: '#book',
				data: {
					message: '书籍',
					num1: 1,
					orderBy: ["t1", "t2", "t3", "t4", "t5", "t6"], //可以控制字段的先后顺序,想调整列的先后顺序,改这个数组就行,可以做个性化设置
					tableTh: { //表头的描述信息
						t1: {
							title: " ", //还可以增加其他描述,比如width等
							align: "left"
						},
						t2: {
							title: "书籍名称",
							align: "right"
						},
						t3: {
							title: "出版日期",
							align: "right"
						},
						t4: {
							title: "价格",
							align: "right"
						},
						t5: {
							title: "购买数量",
							align: "right"
						},
						t6: {
							title: "操作",
							align: "right"
						}
					},

					bookList: [{
							id: 1,
							date: '2010-10',
							price: 98,
							num: 1,
							name: 'JAVA',
						},
						{
							id: 2,
							date: '2011-10',
							price: 100,
							num: 1,
							name: 'PYTHON',
						},
						{
							id: 3,
							date: '2012-10',
							price: 111,
							num: 1,
							name: 'PHP',
						},
						{
							id: 4,
							date: '2013-10',
							price: 222,
							num: 1,
							name: '什么',
						}
					],

				},
				methods: {
					reduce: function() {
						this.num1 = this.num1 - 1
					},
					add: function() {
						this.num1 = this.num1 + 1
					},
					remove: function(index) {
						console.log(index);
						this.bookList.splice(index, 1);
					},

				},


				computed: {
					// 计算总价格,方法1
					totalSumAll() {
						let totalSumAll = 0;
						this.bookList.forEach((item) => {
							totalSumAll += item.price * item.num
						});
						return totalSumAll
					},
					// 计算总价格,方法2
					totalSumAll2() {
						return this.bookList.reduce((returnVal, nextItem) => returnVal + nextItem.price * nextItem.num, 0);
					},
					// 给价格增加两个小数点,方法1
					formatprice: function() {
						return function(price) {
							console.log(price);
							return "¥" + price.toFixed(2);
						}
					},
					// 给价格增加两个小数点,方法2,简写
					// formatprice:function(){
					// 	return price=>"¥"+price.toFixed(2);
					// },



				},
				// 给价格增加两个小数点,方法3,过滤,注意filters与computed同级
				// filters: {
				//   formatprice:price=>"¥"+price.toFixed(2)
				// }


			})
		</script>

	</body>
</html>






效果图:
在这里插入图片描述

方法糖

即简写方法
如:
v-on:click=>@click
v-bind,可以省略v-bind,直接写一个冒号’’:"即 v-bind:class=>:class

动态绑定:class

简写方式:class

v-for中的key

作用:同步数据与状态
列表渲染输出。

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute:

<div v-for="item in items" v-bind:key="item.id">
  <!-- 内容 -->
</div>

建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。

v-bind绑定class和style

给hello变色的例子

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			.active{
				color: red;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<h2 :class="{active: isActive}" >{{message}}</h1>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			let app=new Vue({
				el:('#app'),
				data:{
					message: 'hello',
					isActive: true
				}
			})
			
		</script>
	</body>
</html>

上述运行结果为:
在这里插入图片描述
可以通过isActive的true和false来动态控制样式是否激活

如果给 isAcitve加上’ ’

<h2 :class="{active: 'isActive'}" >{{message}}</h1>

运行的结果是,若’‘中是空的则是false,’'中有值则一律true

这里可以总结出,{}中加了引号的值就不是变量了,不加引号一律被看作是变量来解析,这样就实现了动态绑定

{}中还能加条件判断
如:

<h2 :class="{active: age>30}" >{{message}}</h2>

给字体变化大小
如果不想在计算属性那里加px,就要在div那里进行拼接

<div :style="{fontSize : fontSize+'px'}" >{{message}}</div>

计算属性

computed与watch的区别

计算属性与方法的区别:
两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数

计算属性目的是高性能,计算属性默认只有getter方法,setter基本不用(但也可以去设定一个)

				
				computed:{
				<!--这是计算属性的例子,计算总价格方法1-->
				  totalSumAll(){
				    let totalSumAll = 0;
				    this.bookList.forEach((item)  => {totalSumAll += item.price*item.num});
				    return totalSumAll
				  },
				  <!--这是计算属性的例子,计算总价格方法2-->
				  totalSumAll2(){
				    return this.bookList.reduce((returnVal,nextItem)=>returnVal+nextItem.price*nextItem.num,0);
				  },
				    // 给价格增加两个小数点,方法1
				 formatprice:function(){
					  return function(price){
						  console.log(price);
						  return "¥"+price.toFixed(2);
					  }
				  },
				    // 给价格增加两个小数点,方法2,简写
				  // formatprice:function(){
				  // 	return price=>"¥"+price.toFixed(2);
				  // },
				}
				
				

给价格增加小数的第三个方法,即过滤器filters

<div id="book">
  {{ message }} 
  <table>
    <tr>
      <!-- <th>序号</th> -->
      <th v-for="th in tableTh" >
        {{th.title}}
      </th>
    </tr>
    <tr v-for="(tr,index) in bookList">
      <!-- <td>{{index+1}}</td> -->
      <td>{{tr.id}}</td>
	  <td>{{tr.name}}</td>
	  <td>{{tr.date}}</td>
	  <td>{{tr.price | formatprice}}</td>
	  <td><button v-on:click="tr.num -= 1" :disabled="tr.num <1">-</button> {{tr.num}} <button v-on:click="tr.num += 1">+</button></td>
	  <td><button v-on:click="remove(index)">移除</button></td>
    </tr>
	
  </table>
  <h3>总价格: {{ totalSumAll2 | formatprice}}</h3>
</div>

应用场景

<!-- 在双花括号中 -->
{{ message | capitalize }}

<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>

js

 // 给价格增加两个小数点,方法3,过滤,注意filters与computed同级
				filters: {
				  formatprice:price=>"¥"+price.toFixed(2)
				}
				

事件绑定

上面的表格示例中

<td><button v-on:click="tr.num -= 1" :disabled="tr.num <1">-</button> {{tr.num}} <button v-on:click="tr.num += 1">+</button></td>

逻辑处理最好在js中,因此可以改为下列
body

<tr v-for="(tr,index) in bookList">
					<!-- <td>{{index+1}}</td> -->
					<td>{{tr.id}}</td>
					<td>{{tr.name}}</td>
					<td>{{tr.date}}</td>
					<td>{{formatprice(tr.price)}}</td>
					<td><button v-on:click="reduce(tr)" :disabled="tr.num <1">-</button> {{tr.num}} <button v-on:click="add(tr)">+</button></td>
					<td><button v-on:click="remove(index)">移除</button></td>
				</tr>

js

methods: {
					reduce: function(item) {
						console.log(item);
						item.num --;
						
					},
					add: function(item) {
						console.log(item);
						item.num ++;
					},
					remove: function(index) {
						console.log(index);
						this.bookList.splice(index, 1);
					},

				},
		}

v-model

提供双向绑定的功能

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			{{message}}
			<input type="text" v-model:value="message" value="haha"/>
			<input type="text" v-bind:value="message" @input="change"/>
		</div>
		<!-- js最后引入-->
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			let app=new Vue({
				el:('#app'),
				data:{
					message: 'hello',
				},
				methods:{
					change:function(){
						console.log(event);
						return event.target.value
					}
				}
			})
		</script>
	</body>
</html>

v-model能够修改js 中data的值,bind不能

文本

<!DOCTYPE html>
<html>
   <head>
   	<meta charset="utf-8">
   	<title></title>
   </head>
   <body>
   	<div id="app">
   	<input v-model="message" placeholder="edit me">
   	<p>我叫: {{ message }}</p>
   	</div>
   	<!-- js最后引入-->
   	<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
   	<script type="text/javascript">
   		let app=new Vue({
   			el:('#app'),
   			data:{
   				message: ' ',
   			}
   		
   		})
   	</script>
   </body>
</html>

在这里插入图片描述
多行

	<div id="app">
		<!-- <input v-model="message" placeholder="edit me">
		<p>我叫: {{ message }}</p> -->
		<span>自我介绍:</span>
		<p style="white-space: pre-line;">{{ message }}</p>
		<br>
		<textarea v-model="message" placeholder="add multiple lines"></textarea>
		</div>
	

在这里插入图片描述多选框,并归并到一个数组中

	<div id="app">
		<!-- <input v-model="message" placeholder="edit me">
		<p>我叫: {{ message }}</p> -->
	<!-- 	<span>自我介绍:</span>
		<p style="white-space: pre-line;">{{ message }}</p>
		<br>
		<textarea v-model="message" placeholder="add multiple lines"></textarea>
		</div> -->
		<input type="checkbox" id="fa" value="fa" v-model="checkedNames">
		<label for="jack">fa</label>
		<input type="checkbox" id="san" value="san" v-model="checkedNames">
		<label for="john">san</label>
		<input type="checkbox" id="js" value="js" v-model="checkedNames">
		<label for="mike">js</label>
		<br>
		<span>选择的用户: {{ checkedNames }}</span>
		<!-- js最后引入-->
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			let app=new Vue({
				el:('#app'),
				data:{
					checkedNames: [],
				}
			
			})
		</script>

在这里插入图片描述
单选

 <input type="radio" id="yes" value="yes" v-model="picked">
		  <label for="yes"></label>
		  <br>
		  <input type="radio" id="no" value="no" v-model="picked">
		  <label for="no"></label>
		  <br>
		  <span>选择: {{ picked }}</span>

在这里插入图片描述

选择框

 <select v-model="selected">
		    <option disabled value="">请选择</option>
		    <option>普通用户</option>
		    <option>管理员</option>
		    <option>高层管理员</option>
		  </select>
		  <span>Selected: {{ selected }}</span>

在这里插入图片描述
修饰符:
.lazy:

组件的使用

组件的好处是body只需要写好标签,所有的数据传输和逻辑处理在js中处理即可。还有它是可以复用的,且之间的数据互不影响。
注册方式分为全局注册和局部注册
全局注册:

<button-counter></button-counter>
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

注意,和之前不同的是data必须是一个函数

局部注册:
componets在data中与methods同级,组件中使用方法的话,需要再组件声明一个methods,与外部的methods不相同。

<td><button-reduce :list="tr" :index="index"></button-reduce> {{tr.num}} <button v-on:click="add(tr)">+</button></td>
					<td><button-remove :index="index"></button-remove></td>
components:{
					'button-remove':{
						props: ['index'],
						template: `
						<button v-on:click="remove(index)" >移除</button>
						`,
						methods: {
							remove: function(index) {
								console.log("index:::"+index);
								this.$root.bookList.splice(index, 1);
							}
						
						},
					},
					'button-reduce': {
						props: ['list','index'],
						template: `
						<button v-on:click="reduce(list,index)" :disabled="list.num <1">-</button>
						`,
						methods: {
							reduce: function(item,index) {
								console.log(item,index);
								item.num --;
								if(item.num==0){
									this.bookList.splice(index, 1);
								}
								}
						},
					}
				},

注意组件对外部声明的数组进行修改时,需要增加this.$root.数组,为了修改根数据的值,如果不加则,会报下列错误。

vue.js:634 [Vue warn]: Error in v-on handler: "TypeError: Cannot read property 'splice' of undefined"

found in

---> <ButtonReduce>
       <Root>

也就是方法无法执行,排除到根源就是没有数组

父子组件的通信(传值)

传值用到的属性
父传子=》props
子传父=》$emit

父传子:
必须写在vue实例上面不然报错

Vue.component('blog-post', {
  data: function () {
		 return { 
				     }
				    },
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})

template为插入的html标签

{{title}}中的title值来自于props中的title,props中的title来自于html中,被绑定的(:title=)的值
即:

<blog-post title="我叫发啊发"></blog-post>

如果在data加上title值,优先级会是html标签中赋予的值,并且会报错
错误是:

[Vue warn]: The data property “title” is already declared as a prop.

子传父(监听):

<blog-post title="Why Vue is so fun"></blog-post> -->
			<blog-post
			 v-on:change="changebig" 
			:style="{fontSize: fontsize+'px'}"
			title="我叫发啊发"
			></blog-post>
		
		

通过引入一个按钮,触发点击事件$emit(‘change’),change为html点击事件名称,changebig为js中放大的执行事件方法

v-on:自定义事件a=“方法名b”一般用于子传父调用方法用,子调用a,父调用b即在实例vue的methods。

template右边的符号可以是单引号’'或者 ``斜单引号(即波浪号位置)。单引号只能写在一行,斜单引号可以多行

Vue.component('blog-post', {
				data: function () {
				  return {
				  }
				},
			  props: ['title'],
			  template: `
			  <div>
			  <h3>{{ title }}</h3>
			  <button v-on:click="$emit('change')">放大字体</button>
			  </div>
			  `
			})

写在对应vue实例中,与data同级

methods:{
					changebig: function(){
						console.log("changebig");
						this.fontsize++;
					}
				}

$emit监听的事件中还能进行传值
如:

			  template: `
			  <div>
			  <h3>{{ title }}{{ list.name }}</h3>
			  <button v-on:click="$emit('change',30)">放大字体</button>
			  </div>
			  `
methods:{
					changebig: function(value){
						console.log("changebig");
						this.fontsize=value+this.fontsize;
					}
				}

下面是组件通信完整的例子

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>

<!-- 表格高亮 -->
	<style type="text/css">
			
			tr td,tr th{
				
				width: 200px;
				line-height: 30px;
				text-align: center;
			}
		
		
	</style>


		<!--css-->
		<!-- 表格 -->
		<style type="text/css">
			table tr th {
				background: #f7f7f7;
			}

			table,
			table tr th,
			table tr td {
				border: 1px solid #eaeaea;
			}

			table {
				min-width: 200px;
				min-height: 25px;
				line-height: 25px;
				text-align: center;
				border-collapse: collapse;
			}
		
		</style>
	</head>
	<body>
		<div id="app">
			<button-counter></button-counter>
			<!-- <blog-post title="My journey with Vue"></blog-post>
			<blog-post title="Blogging with Vue"></blog-post>
			<blog-post title="Why Vue is so fun"></blog-post> -->
			<blog-post
			  v-for="item in list"
			  v-bind:key="item.id"
			  v-bind:list="item"
			  v-bind:title="item.title"
			   v-on:change="changebig"
			   :style="{fontSize: fontsize+'px'}"
			></blog-post>
			<div haha="自定义"></div>
			
		</div>
		
		<!-- js最后引入-->
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			Vue.component('button-counter', {
			  data: function () {
			    return {
			      count: 0
			    }
			  },
			  template: `<button v-on:click="count++">
			  You clicked me {{ count }} times.
			  </button>`
			})
			Vue.component('blog-post', {
				data: function () {
				  return {
				  }
				},
			  props: ['title','list'],
			  template: `
			  <div>
			  <h3>{{ title }}{{ list.name }}</h3>
			  <button v-on:click="$emit('change')">放大字体</button>
			  </div>
			  `
			})
		
			var app = new Vue({
				el: '#app',
				data: {
					message: '书籍',
					num1: 1,
					fontsize: 20,
					list: [{
						    isChecked: false,
							id: 1,
							date: '2010-10',
							price: 98,
							num: 1,
							name: 'JAVA',
							title: 'JAVA',
						},
						{
							isChecked: false,
							id: 2,
							date: '2011-10',
							price: 100,
							num: 1,
							name: 'PYTHON',
							title: 'JAVA2',
						},
						{
							isChecked: false,
							id: 3,
							date: '2012-10',
							price: 111,
							num: 1,
							name: 'PHP',
							title: 'JAVA3',
						},
						{
							isChecked: false,
							id: 4,
							date: '2013-10',
							price: 222,
							num: 1,
							name: '什么',
							title: 'JAVA4',
						}
					],

				},
				methods:{
					changebig: function(){
						console.log("changebig");
						this.fontsize++;
					}
				}
			




			})
		</script>
		<!-- 高亮js -->
	</body>
</html>

在这里插入图片描述非父子组件的通信方式
创建中间站:

	let bus =new Vue;

绑定监听事件 :vue.$ on

mounted: function(){
							//监听
							bus.$on('changeEvents',function(){
								console.log('person1收到了');
							});
						},

触发事件:vue.$ emit(‘xxx’)

template: `<ul>
						<li @click="getContent" v-for="item in list">{{item}}</li>
						</ul>
						`,
						methods:{
							getContent:function(){
								bus.$emit('changeEvents')
							}
						},

撤销监听事件 vue.$ off
在这里插入图片描述下面为完整实例:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<div id="app">
			<person1></person1>
			<person2></person2>
		</div>
		
		<!-- js最后引入-->
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			let bus =new Vue;
			var app = new Vue({
				el: '#app',
				data: {
					

				},
				components:{
					'person1': {
						data: function(){
							return {
								message: 'hello person2'
							};
						},
						template: '<div><h2>{{message}}</h2><button @click="songli">送礼</button></div>',
						mounted: function(){
							//监听
							bus.$on('changeEvents',function(){
								console.log('person1收到了');
							});
						},
						methods:{
								
							songli:function(){
								bus.$emit('jieshou','iphone')
							}
						}
					},
					'person2': {
						data: function(){
							return {
								list: ['哈哈','呵呵','嘻嘻']
							};
						},
						template: `<ul>
						<li @click="getContent" v-for="item in list">{{item}}</li>
						</ul>
						`,
						methods:{
							getContent:function(){
								bus.$emit('changeEvents')
							}
						},
						mounted:function(){
							bus.$on('jieshou',function(val){
								console.log("收到了 "+ val)
							});
						}
					},
					
				}
				
			




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

生命周期

一个vue实例,有创建到销毁一个过程。
在这里插入图片描述这是官网的图。
主要是
created :创建vue实例后做的操作
mouted:页面挂载成功后做的操作,即el data 这些
等等

下面是实例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<p :style="{fontSize : fontSize+'px'}">{{ message }}</p>
			<button v-on:click="change">放大</button>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
	var app=new Vue({
				el: '#app',
				data: {
					message: 'Hello Vue!',
					fontSize: 10
				},
				methods:{
					change: function(){
						console.log("change被调用");
						this.fontSize=this.fontSize+10;
					}
				},
				beforeCreate(){
					console.log("beforeCreate");
				},
				created(){
					console.log("created");
				},
				beforeMount(){
					console.log("beforeMount");
				},
				mounted(){
					console.log("mounted");
				},
				beforeUpdate(){
					console.log("beforeUpdate");
				},
				updated(){
					console.log("updated");
				},
				beforeDestroy(){
					console.log("beforeDestroy");
				},
				destroyed(){
					console.log("destroyed");
				},
			})			
		</script>
	</body>
</html>

开始运行
在这里插入图片描述点击放大后
在这里插入图片描述destroyed没有演示,因为需要多个页面

vue cli脚手架

后面会更新不用脚手架时手动搭。

下面介绍脚手架如何使用。
npm下载,可以快速导入
脚手架安装
在这里插入图片描述

vuex

在这里插入图片描述vuex store类似于vue实例中的data methods等模块
因此,在vuex中,页面与后端的传值主要是对store的操作。

下面的是actions(用户操作事件)、state(存储原始值,vuex一般不对他直接操作)、view
在这里插入图片描述在这里插入图片描述

state的基本使用

1.html代码中

{{$store.state.xxx}}

2.javascript代码中

this.$store.state.xxx

3.通过mapState,映射为组件的属性或计算属性

xx.vue

<template>
	<div>
		<h3>计算属性:message1:{{message1}} ,message:{{message}}</h3>
	</div>
	
</template>
<script>
	import {mapState} from 'vuex'
	export default {
		data: function() {
			return {
				count: 0,
				id:'',
			}
		},
		computed: {
			...mapState(['message1', 'message'])
		}
	}
</script>

<style scoped>
</style>

index.js

export default new Vuex.Store({
	state: {
		count: 0,
		message: 'nihao',
		message1: 'nihao1',
	},
	mutations: {},
	actions: {},
	modules: {}
})

Getter的基本使用

1.html代码

<ul>
<li v-for=" item in $store.getters.ckBooks " :key="item.id">{{item.name}}</li>
</ul>
<h3>书本数量为:{{$store.getters.ckBooksLength}}</h3>

2.html js代码

	export default {

	}

3.index.js代码

	state: {
		count: 0,
		message: 'nihao',
		message1: 'nihao1',
		bookList: [{
				isChecked: true,
				id: 1,
				date: '2010-10',
				price: 98,
				num: 1,
				name: 'JAVA',
			},
			{
				isChecked: true,
				id: 2,
				date: '2011-10',
				price: 100,
				num: 1,
				name: 'PYTHON',
			},
			{
				isChecked: false,
				id: 3,
				date: '2012-10',
				price: 111,
				num: 1,
				name: 'PHP',
			},
			{
				isChecked: false,
				id: 4,
				date: '2013-10',
				price: 222,
				num: 1,
				name: '什么',
			}
		],
	},
getters: {
		ckBooks(state) {
			console.log("xxx::" + state.bookList.filter(item => item.isChecked));
			return state.bookList.filter(item => item.isChecked)
		},
		ckBooksLength(state, getters) {
			return getters.ckBooks.length
		},
		
	},

4.通过Getter目的是为了获取值
reduce.vue

<template>
	<div>
		<h1>Reduce 组件count:{{$store.state.count}}</h1>
		<button @click="reduce">mt-</button>
		<button @click="mtReduce">mt映射-</button>
		<button @click="reducen">mt单值 n-</button>
		<button @click="reducendx">mt对象 n-</button>
		<button @click="reducenhs">mt函数 n-</button>
		<button @click="reducenyb">mt异步</button>
	</div>
</template>

<script>
	// mt映射需要的辅助函数 组件中的 methods 映射为 store.commit 调用
	import { mapMutations } from 'vuex'
	
	export default {
		data: function() {
			return {
				count: 0
			}
		},
		methods: {
			reduce() {
				console.log("count:::"+this.count);
				// this.count--;
				this.$store.commit('mtReduce')
			},
			//采用映射函数的话上面的html可以直接引用
			...mapMutations(['mtReduce']),
			//传普通值
			reducen() {
				this.$store.commit('mtReducen',5)
			},
			//传对象
			reducendx() {
				this.$store.commit('mtReducendx',{count:5})
			},
			//传函数
			reducenhs() {
				this.$store.commit('mtReducenhs',function(){
					return 5
				})
			},
			//mutations尝试异步更新,结果是不行的,当做比较用
			reducenyb() {
				this.$store.commit('mtyb')
			},

		},
	}
</script>

<style scoped>
</style>

index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
	state: {
		count: 0,
		bookList: [{
				isChecked: true,
				id: 1,
				date: '2010-10',
				price: 98,
				num: 1,
				name: 'JAVA',
			},
			{
				isChecked: true,
				id: 2,
				date: '2011-10',
				price: 100,
				num: 1,
				name: 'PYTHON',
			},
			{
				isChecked: false,
				id: 3,
				date: '2012-10',
				price: 111,
				num: 1,
				name: 'PHP',
			},
			{
				isChecked: false,
				id: 4,
				date: '2013-10',
				price: 222,
				num: 1,
				name: '什么',
			}
		],
	},
	mutations: {
		mtReduce(state) {
			state.count--
		},
		mtadd(state) {
			state.count++
		},
		mtReducen(state,payload) {
			state.count-=payload
		},
		mtReducendx(state,payload) {
			state.count-=payload.count
		},
		mtReducenhs(state,payload) {
			state.count-=payload()
		},
		mtyb(state) {
			setTimeout(() => state.count--,1000)
		},
	},
	actions: {},
	modules: {}
})

上面说到mutations异步更新不行,是的,它必须是同步函数,即只修改页面上的值(做了延迟修改的操作就不能更新state的值了)。可以用浏览器的vue插件看有没有传到值。
具体如下:
在这里插入图片描述前面的-20是按了同步函数的,都可以看到右边同步更新,但是又按了6下异步,还是-20,说明了它不能异步更新的问题。
如何解决呢?
actions能够解决问题,就是为了解决异步更新。

Actions的使用

1.store中的index.js定义方式

actions: {
		acReduce(context) {
			setTimeout(() => {
				console.log("请求完成数据");
			},1000)
			context.commit('mtReduce')
		},
	},

2.vue组件中通过context调用,即上面的 context.commit(‘mtReduce’)
3.组件中的代码

<template>
	<div>
		<button @click="reducenac">ac异步</button>
	</div>
</template>

<script>
	export default {
		data: function() {
			return {
				count: 0
			}
		},
		methods: {
			reducenac() {
				// this.$store.commit('acReduce')错误
				this.$store.dispatch('acReduce')
			
			},
		},
	}
</script>

<style scoped>
</style>

结果图如下:
在这里插入图片描述可以看到3次都是同步了,说明actions完美解决异步更新问题。

Mutations的基本使用

1.目的是为了操作state中的值
2.所有上面说过的state方法不可行
3.基本使用涉及到传参包括普通值、对象、函数,还有mapMutations
下面直接上一个减法的计数器例子,实现所有

element ui的基本使用

前面学完了vuex后,看element ui会容易点,超快建立网站~
1.安装
可以使用vue clic的vue ui里面的插件,下载即可,创建项目选上elementui即可。
在这里插入图片描述成功后会出现这样的文件夹,里面有element.js
在这里插入图片描述官网看安装也行。
2.按钮的使用
一般用什么组件导什么组件
这里直接把全部导进来了
element.js
在这里插入图片描述

import Vue from 'vue'
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(Element)

页面使用

<el-button>el-button</el-button>

这种el开头的按钮即可

3.登录案例
 1)el-form el-input el-card的使用
 2)表单处理
  a)重置按钮的实现
   1.给Form表单增加ref属性,这样取值可以直接取到表单值
   2.在点击事件中通过this.$refs[‘ref属性里的值名称’].resetFields()进行操作,官网那个方法不行
   3.一定不要忘了给表单中每个值加上prop绑定,且绑定的对象属性名称是和下面jsdata 声明的对象属性名称要一样。

 3)输入框和密码输入框
 4)记住密码复选框
 5)登录和重置按钮
 6)表单的验证

上代码,只上Login.vue这个组件的代码,足矣

<template>
	<el-form ref="form" :rules="rules" :model="loginForm" label-width="60px" class="login-card">
		<el-card shadow="always">
			<el-form-item class="login-btn" style="margin-left:80px">
				<el-image style="margin-left:100px,width: 200px; height: 100px" src="https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg" fit="fill"></el-image>
			</el-form-item>
			<el-form-item label="账号" prop="name">
				<el-input v-model="loginForm.name"></el-input>
			</el-form-item>
			<el-form-item label="密码" prop="password">
				<el-input type="password" v-model="loginForm.password" autocomplete="off"></el-input>
			</el-form-item>
			<el-form-item prop="isChecked">
				<el-checkbox label="记住密码" v-model="loginForm.isChecked" name="type"></el-checkbox>
			</el-form-item>
			<el-button-group class="login-btn">
				<el-button type="primary" @click="submitForm()">登录</el-button>
				<el-button @click="resetForm()">重置</el-button>
			</el-button-group>
		</el-card>
	</el-form>
</template>

<script>
	export default {
		data() {
			return {

				loginForm: {
					name: '',
					password: '',
					isChecked: false
				},
				rules: {
					name: [{
							required: true,
							message: '请输入账号',
							trigger: 'blur'
						},
						{
							min: 4,
							max: 10,
							message: '长度在 4 到 10 个字符',
							trigger: 'blur'
						}
					],
					password: [{
							required: true,
							message: '请输入密码',
							trigger: 'blur'
						},
						{
							min: 4,
							max: 10,
							message: '长度在 4 到 10 个数字',
							trigger: 'blur'
						}
					]
				}

			}
		},
		methods: {
			submitForm() {
				this.$refs['form'].validate((valid) => {
					if (valid) {
						return this.$router.push({ name: 'Main',params: { userId: '123' } })
					} else {
						console.log('error submit!!');
						return false;
					}
				});
			},
			resetForm() {
				this.$refs['form'].resetFields();
			}
		}
	}
</script>

<style scoped>
	.login-card {
		width: 480px;
		margin: auto;
		transform: translateY(50%);
	}

	.login-btn {
		width: 100%;
	}

	.login-btn .el-button {
		width: 50%;
	}

	.login-btn .i {
		width: 50%;
	}
</style>

编程式导航

前面讲过路由< router-link >这种,叫做声明式路由,即只能在template中使用。
那我们在js进行逻辑判断然后跳转怎么办呢?
这里就出现了另一种方式,编程式路由(导航),上面的例子有涉及到一点。
官网给出的,结果发现用不了

// 字符串
router.push('home')

// 对象
router.push({ path: 'home' })

// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})

// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

查找了下发现加上return就行了,在函数中

return this.$router.push

表单提交与登录拦截

表单提交需要用到axios。

 npm install axios 
 npm install --save axios vue-axios

在main.js中加入

import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.use(VueAxios, axios)

或者另起一个插件文件夹,创一个axios的js文件,然后再引入axios到main.js
操作如下:

在这里插入图片描述
在这里插入图片描述通过axios进行表单提交返回的方法:

submitForm() {
                var that = this;
                this.$refs['form'].validate((valid) => {
                    if (valid) {
                        //npm i vue-axios
                        //npm i axios
                        this.axios
                            .post('http://118.89.176.28:8080/admin/login', this.loginForm)
                            .then(result => {
                                console.log("result:::" + JSON.stringify(result.data.code));
                                console.log("idencode:::" + that.loginForm.idencode);
                                console.log("checkCode:::" + that.checkCode);
                                if (JSON.stringify(result.data.code) == 200 && that.loginForm.idencode == that.checkCode) {
                                    console.log("username:::" + this.loginForm.username)
                                    return this.$router.push({
                                        name: 'Main',
                                        params: {
                                            userId: '123'
                                        }
                                    })
                                }
                            })
                            .catch(function(err) {
                                console.log("err:::" + err);
                            });
                        // http.post('http://118.89.176.28:8080/admin/login', this.loginForm)
                        // .then(result => {
                        // 	console.log(result);
                        // })

                    } else {
                        console.log('error submit!!');
                        return false;
                    }
                });
            },

上面的地址请求可以进一步优化,即将请求地址放在api文件夹统一引入和管理,因此上面在main引入的axios需要改成在api文件引入,然后api在main引入。这样层层调用很清晰明了。axios.js里面还可以设置请求基地址及延迟

首先修改一下axios.js,添加了基地址和请求响应拦截器

import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.use(VueAxios, axios)
axios.defaults.baseURL='http://118.89.176.28:8080'
axios.defaults.timeout=15000
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    console.log("请求interceptors.request")
    return config;
}, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
});

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    console.log("响应interceptors.response")
    return response;
}, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
});

t添加vue-cookie用来实现记住密码
安装vue-cookie

npm install vue-cookies --save

引入cookie.js

import Vue from 'vue'
import VueCookies from 'vue-cookies'
Vue.use(VueCookies)

最后在main引入即可
下面是更新完的完整例子

<template>
    <el-form ref="form" :rules="rules" :model="loginForm" label-width="60px" class="login-card">
        <el-card shadow="always">
            <el-form-item class="login-btn" style="margin-left:80px">
                <el-image style="margin-left:100px,width: 200px; height: 100px" src="https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg"
                          fit="fill"></el-image>
            </el-form-item>
            <el-form-item label="账号" prop="username">
                <el-input v-model="loginForm.username"></el-input>
            </el-form-item>
            <el-form-item label="密码" prop="password">
                <el-input type="password" v-model="loginForm.password" autocomplete="off"></el-input>
            </el-form-item>
            <el-container>
                <el-form-item prop="isChecked" class="login-btn">
                    <el-checkbox label="记住密码" v-model="loginForm.isChecked" name="type"></el-checkbox>
                </el-form-item>
                <el-form-item prop="idencode" class="login-btn">
                    <el-input v-model="loginForm.idencode" placeholder="验证码"></el-input>
                </el-form-item>
                <div class="code">
                    <span @click="createCode" class="codecontent" label="left">{{checkCode}}</span>
                </div>
            </el-container>
            <el-button-group class="login-btn">
                <el-button type="primary" @click="submitForm()">登录</el-button>
                <el-button @click="resetForm()">重置</el-button>
            </el-button-group>
        </el-card>
    </el-form>
</template>

<script>
    // import http from 'axios'
    // import {api_login} from '../api/login.js'
    export default {
        data() {
            return {
                loginForm: {
                    username: '',
                    password: '',
                    isChecked: false,
                    idencode: '',
                },
                checkCode: '',
                rules: {
                    username: [{
                        required: true,
                        message: '请输入账号',
                        trigger: 'blur'
                    },
                        {
                            min: 4,
                            max: 10,
                            message: '长度在 4 到 10 个字符',
                            trigger: 'blur'
                        }
                    ],
                    password: [{
                        required: true,
                        message: '请输入密码',
                        trigger: 'blur'
                    },
                        {
                            min: 4,
                            max: 10,
                            message: '长度在 4 到 10 个数字',
                            trigger: 'blur'
                        }
                    ]
                }

            }
        },
        mounted() {
            this.createCode();
        },
        methods: {
            submitForm() {
                var that = this;
                this.$refs['form'].validate((valid) => {
                    if (valid) {
                        //npm i vue-axios
                        //npm i axios
                        this.axios
                            .post('/admin/login', this.loginForm)
                            .then(result => {
                                console.log("result:::" + JSON.stringify(result.data.code));
                                console.log("idencode:::" + that.loginForm.idencode);
                                console.log("checkCode:::" + that.checkCode);
                                if (this.loginForm.isChecked) {
                                    this.$cookies.set('username', this.loginForm.username, '7D')
                                    this.$cookies.set('password', this.loginForm.password, '7D')
                                } else {
                                    this.$cookies.remove('username')
                                    this.$cookies.remove('password')
                                }

                                if (JSON.stringify(result.data.code) == 200 && that.loginForm.idencode == that.checkCode) {
                                    console.log("username:::" + this.loginForm.username)
                                    return this.$router.push({
                                        name: 'Main',
                                        params: {
                                            userId: '123'
                                        }
                                    })
                                }
                            })
                            .catch(function(err) {
                                console.log("err:::" + err);
                            });
                        // http.post('http://118.89.176.28:8080/admin/login', this.loginForm)
                        // .then(result => {
                        // 	console.log(result);
                        // })

                    } else {
                        console.log('error submit!!');
                        return false;
                    }

                });
            },
            resetForm() {
                this.$refs['form'].resetFields();
            },
            createCode() {
                let code = "";
                const codeLength = 4; //验证码的长度
                const random = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
                    'M', 'N', 'O', 'P', 'Q', 'R',
                    'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'); //随机数
                for (let i = 0; i < codeLength; i++) { //循环操作
                    let index = Math.floor(Math.random() * 36); //取得随机数的索引(0~35)
                    code += random[index]; //根据索引取得随机数加到code上
                }
                this.checkCode = code; //把code值赋给验证码
                console.log("createCode:::" + this.checkCode);
            },
        },
        created() {
            //在页面加载前,获取cookie值并绑定在值上
            this.loginForm.username = this.$cookies.get('username')
            this.loginForm.password = this.$cookies.get('password')
        }
    }
</script>

<style scoped>
    .login-card {
        width: 480px;
        margin: auto;
        transform: translateY(50%);
    }

    .login-btn {
        width: 100%;
    }

    .login-btn .el-button {
        width: 50%;
    }

    .login-btn .i {
        width: 50%;
    }
    .code{
        background-color: #DCDFE6;
        line-height:1.7;
        margin-left: 10px;
        border-radius: 4px;
        border: 1px;
        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
        height: 40px;
        width: 100px;
    }
    .codecontent{
        color: #606266;
        font-size: 20px;
        margin: 10px;
    }
</style>

只能手动填地址,api引用老是出bug,不过用api的方式挺繁琐的,不如直接填地址呢。后面更新看看哪里出问题了

问题

1.[Vue warn]: Property or method “reduce” is not defined on the instance but referenced during render

在进行v-on:click 按钮触发事件时候出现这样的问题:

解决:

methods需要和data同级,而不是在data里面

2.Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the “name” option.
在进行组件的注册时,出现的问题

解决:使用的是全局注册,需要将vue.componet放在script的前面才行。

  1. 在子组件中添加子组件的时候出现这样的问题
vue.js:634 [Vue warn]: Error compiling template:

Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.

1  |  <h3>{{ title }}{{ list.name }}</h3><button>放大字体</button>
   |                                     ^^^^^^^^^^^^^^^^^^^^^

found in

---> <BlogPost>
       <Root>

需要加上div即可

猜你喜欢

转载自blog.csdn.net/weixin_41487978/article/details/106558972