Vue 03 day
模板语法
允许开发者,声明式的将DOM绑定至最底层Vue实例的数据上。所有的Vue的模板都是合法的HTML。
Vue将模板编译成虚拟的DOM渲染函数。Vue能够智能的计算出最少需要重新渲染多少组件,并把DOM操作次数减少到最少。
疑问:虚拟DOM和真实DOM的区别。
虚拟DOM就是JavaScript对象以JavaScript对象的形式去添加DOM元素
计算属性(computed)
1.什么是计算属性?
不实际存储属性值,而是根据其他属性的值,动态计算获得。因为有些属性的值不能之直接获得,需要经过其他属性的值 计算后,才能获得,但是js面向对象规定:不能再一个属性中使用另一个属性,当一个属性的值,依赖于
计算属性在computed选项中定义。计算机属性就是当其他 依赖属性的值 发生变化时,这个属性的值会自动更新,与之相关的 Dom也会同步更新,这里的依赖属性值的是data。
原理:首次使用 new Vue()扫描到计算属性是,会自动执行计算属性的函数,获得返回值。new Vue()会立刻将本次计算的返回值缓存起来,反复使用。当下一次new Vue()再次扫描到同名的计算属性时,不会重复调用函数重复计算,而是自动从缓存中获取计算结果,直接使用——避免重复计算,同时效率高,除非当计算属性依赖另一个变量值发生变化,才能重新调用一次计算属性的函数,计算出新的结果,再次缓存起来反反复使用。
computed中的计算属性与methods中的函数有什么差别 ?
1,methods中普通函数计算结果不会被缓存,导致每次遇到,都要反复计算——效率低
2,computed
计算属性是基于他们的依赖进行缓存的,只有在相关依赖 发生改变时他们才会重新求职。
如果用方法(methoeds)实现,只要调用这个方法,无论data中这个值是否改变,方法 都会重新执行一次,增加了系统的开销。
注意:在调用methods中的一个方法时。所有的方法都会被 调用
<div id="app">
<button type="button" @click="a++">a+1</button>
<button type="button" @click="b++">a+1</button>
<p>number+a={{add1()}}</p>
<p>number+b={{add2()}}</p>
</div>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var app=new Vue({
el:"#app",
data:{
a:0,
b:0,
number:30
},
methods:{
add1:function(){
console.log("number+a");
return this.a+this.number
},
add2:function(){
console.log("number+b");
return this.b+this.number
}
}
})
</script>
结果:并没有点击,网页一刷新就出来了
最后:在触发事件时还是使用对应的方法。计算属性一般在数据量比较大,比较耗时的情况下使用,只有虚拟DOM与真实DOM下才 会执行computed。
侦听属性(watch)
watch监听器也可以来监测某个数据的变化。
不同的是:
计算属性仅仅是对于依赖 数据的变化 后进行的数据操作。
而watch更加侧重于对于监测中的某个数据发生变化后所执行的一系列的功能逻辑操作。
监听器以key-value的形式定义,key是一个字符串,他是需要被监测的对象,而value则可以是字符串(方法名称)、函数(可以监测获取到监听对象改变前 的 值以及更新后的值)或是一个对象(对象内可以包含回调函数的其他选项,列数是否初始化时执行监听,或是否执行深度遍历,是否对对象内部的属性进行监听)
//回调值为函数方法
<div id="app">
输入的值:<input type="text" v-model="message" />
</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:""
},
watch:{
message:function(newvalue,oldvalue){
console.log( "新值" + newvalue)
console.log( "旧值" + oldvalue)
}
}
})
</script>
//小案例
<div id="app">
<input type="text" v-model.lazy="uname" />
<span>{{tip}}</span>
</div>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var app=new Vue({
el:"#app",
data:{
uname:"",
tip:""
},
methods:{
checkName:function(uname){
//调用接口,使用定时器模拟接口调用
//因为定时器的指针值得是window,所以要存一下this
var that=this
setTimeout(function(){
if(uname=="admin"){
that.tip="用户名存在请换一个"
}else{
that.tip="用户名可用"
}
},2000)
}
},
watch:{
uname:function(val){
//调用后台接口验证用户的合法性
this.checkName(val);
//修改提示信息
this.tip="正在验证"
}
}
})
</script>
axios(ajax+node.js+mysql)
是一个基于promise的HTTP库,可以用在浏览器和node中,axios主要用于创建请求,在浏览器中创建XMLHTTPRequest请求(xhr代替),在node中创建普通的http请求
浏览器中创建xhr请求的4种方案
!原生创建xhr,麻烦
2,jQuery对的封装函数中,ajax的方法,jq中是只有ajax,还包含大量的DOM操作和动画操作,但是Vue只是使用ajax,别的都不用了、,大材小用
3,Vue-Resource(已被废弃)
4,使用第三方工具axios,axios本身与vue没有任何关系
注意:任何的ajax方法,都要重新封装(以后工作中)
cli中使用(开发使用)
直接在html引入axios的js文件
c
提示:在全局添加一个axios对象,包括发送请求api
调用 axios,发送异步请求
1,get请求
搭建本地服务器
1,创建空项目 vueServe
2,初始化项目 npm init -y; 初始化 完成之后,会在当前目录下生成一个packed。json文件,用来保存我们要下载的插件和模块
3,使用express搭建本地服务器
express是第三方的模块,所以需要下载**(npm install express --save)**
–save:是将我们下载的文件
下载完成后
4. 使用express搭建本地服务器
//引入express模块
const express=require("express");
//使用express的api创建服务器
var app= new express();
//为服务器绑定监听的端口(port)
app.listen(4000,()=>{
console.log("serve is running")
})
//添加访问路径
app.get("/",(req,res)=>{
res.send('123')
})
启动服务器(黑窗口中输入)
node app.js
注意:输入两遍ctrl+c 关闭服务器
在vueSever下
创建文件router,保存路由器
//引入express
const express=require("express");
//创建空的路由器对象
var router=express.Router();
//添加路由
router.get("/list",function(req,res){
res.send("我是list")
})
//导出路由
module.exports=router
在app.js中引入使用router路由器
//引入路由器
var routerlist=require("./router/rout.js");
//使用路由
app.use("/router",routerlist)
网页中的地址栏输入:localhost:8080/router/list 访问
操作数据库
下载mysql模块
npm install mysql --save
在vuesever下
创建pool文件
在该文件下创建pool.js
//导入mysql
const mysql=require("mysql");
//连接池
var pool=mysql.createPool({
host:'127.0.0.1',//服务器ip地址
prot:'3306',//端口号
user:'root',//用户名
password:'134658',//数据库密码
database:'ymy',//数据库名称
connectionLimit:20 //设置最大连接数,不写也可以,默认是15
})
//导出连接 池
module.exports=pool
在路由器中操作数据库:
pool.query("select *from user",[],(request,response)=>{
// res.send(response)
res.write(JSON.stringify(response));
res.end();
})
axios post请求
axios.post("http://127.0.0.1:4000/router/list",Qs.stringify({uname:"哈哈哈哈"})).then(result=>{
console.log(result.data)
})
注意:get和post方法传参时,配置属性名不一样,get请求传参,用的params:{}对象,而post请求传参,必须是字符串
服务器端获取 get 请求的参数 req.query
服务器端获取post请求的参数 不能使用req.query
我们使用body-parser中间件
下载body-parser中间件:npm install body-parser --save;
在app.js中导入
//导入中间件
const bodyParser=require("body-parser");
//使用body-parser中间件
app.use(bodyParser.urlencoded({
extend:false
}))
注意:bodyparser的中间件一定要在路由调用之前
提示:extend为false是不使用qs模块格式化为对象,而是使用querystring
解决问题:qs模块
引入qs模块
使用:Qs.stringify会将对象转为querystring语法
axios.post(“url”,Qs.stringify({参数:值,…})).then()
注意:获得相应主体的数据,数据不是直接返回的,而是包裹在一个对象的data属性中返回,无论get/post请求,获得的响应都是一个全新的对象。传统的响应包裹数据,包含在该对象的res.data属性中,所以,res.data才能获得响应的结果
总代 码
//html中代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- <button type="button" @click="sendGet">get发送请求</button> -->
<button type="button" @click="sendGet">post请求</button>
</div>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="js/axios.min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/qs.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
//测试axios是否成功导入
// console.log(axios)
new Vue({
el:"#app",
data:{},
methods:{
sendGet:function(){
//调用aixos的get方法
//在没有自己服务器的情况下
// axios.get("http://127.0.0.1:4000/router/list",{
// params:{}
// }).then(result=>{
// console.log(result.data)
// })
axios.post("http://127.0.0.1:4000/router/list",Qs.stringify({uname:"哈哈哈哈"})).then(result=>{
console.log(result.data)
})
}
}
})
</script>
</body>
</html>
//app.js
//引入express模块
const express=require("express");
//导入中间件
const bodyParser=require("body-parser");
//引入路由器
var routerlist=require("./router/rout.js");
//使用express的api创建服务器
var app= new express();
//使用路由
app.use("/router",routerlist)
//使用body-parser中间件
app.use(bodyParser.urlencoded({
extend:false
}))
//为服务器绑定监听的端口(port)
app.listen(4000,()=>{
console.log("serve is running")
})
//添加访问路径
app.get("/",(req,res)=>{
res.send('123')
})
//router.js
//引入express
const express=require("express");
//导入连接池
const pool=require("../pool/pool.js")
//创建空的路由器对象
var router=express.Router();
// //添加路由
// router.get('/',(req,res)=>{
// res.send('叶梦宇')
// })
// router.get("/list",function(req,res){
// // res.send("我是路由")
// //操作数据库
// res.writeHeader(200,{
// "Access-Control-Allow-Origin":"*"
// })
// pool.query("select *from user",[],(request,response)=>{
// // res.send(response)
// res.write(JSON.stringify(response));
// res.end();
// })
// })
//post请求
router.post("/list",function(req,res){
// console.log(req.query)
console.log(req.body)
res.writeHeader(200,{
"Access-Control-Allow-Origin":"*"
})
pool.query("select *from user",[],(request,response)=>{
// res.send(response)
res.write(JSON.stringify(response));
res.end();
})
})
//导出路由
module.exports=router
//pool.js
//导入mysql
const mysql=require("mysql");
//连接池
var pool=mysql.createPool({
host:'127.0.0.1',//服务器ip地址
prot:'3306',//端口号
user:'root',//用户名
password:'134658',//数据库密码
database:'ymy',//数据库名称
connectionLimit:20 //设置最大连接数,不写也可以,默认是15
})
//导出连接 池
module.exports=pool
组件
页面中一块拥有专属html+css+js数据的可重用的页面独立区域
使用组件
定义组件(全局组件)
方法一
<div id="app">
<my-cont></my-cont>
</div>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
//定义全局组件
Vue.component("my-cont", {
//所有的标签只能包裹在div中,不然会报错,有且只能有一个根目录
template: `<div>
<button type="button" @click="add">+</button>
<p>{{num}}</p>
<button type="button" @click="min">-</button>
</div>`,
//data中的数据保存在data的函数返回的
data() {
//可以反复使用
//每次调用都会创建一个data对象
return {
//相当于new vue中的data
num: 0
}
},
//后面和new vue中一样了
methods: {
add: function() {
this.num++
},
min: function() {
this.num--
},
}
})
var app = new Vue({
el: "#app"
})
方法二
因为写模板字符串恒麻烦、
<div id="app">
<my-cout></my-cout>
</div>
<template id="temp1">
<div>
<button type="button" @click="add">+</button>
<p>{{num}}</p>
<button type="button" @click="min">-</button>
</div>
</template>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
Vue.component('my-cout', {
template: "#temp1",
data() {
return {
num: 0
}
},
methods: {
add: function() {
this.num++
},
min: function() {
this.num--
}
}
})
var app = new Vue({
el: "#app"
})
</script>
定义 私有组件
<div id="app">
<login></login>
</div>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
components:{
login:{
template:`<div>哈哈哈哈</div>`
}
}
})
</script>
切换组件显示
<div id="app">
<button type="button" @click="flag='login'">登录</button>
<button type="button" @click="flag='zuce'">注册</button>
<!-- components是占位符,is是组件名称 -->
<components :is="flag"></components>
</div>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
Vue.component('login',{
template:`<div>登录</div>`
})
Vue.component('zuce',{
template:`<div>注册</div>`
})
var app = new Vue({
el: "#app",
data:{
flag:"login"
}
})
</script>
小总结
父组件向子组件传值
<div id="app">
//利用v-bind,父组件可以把数据以属性 绑定的形式传递给 子组件。供子组件使用。
<com1 v-bind:parentmsg="msg"></com1>
</div>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var app=new Vue({
el:"#app",
data:{
msg:'这是父组件中的值'
},
methods:{},
components:{
com1:{
template:`<div><h1>这是子组件-------------------------{{parentmsg}}</h1></div>`,
//把父组件传递过来的parentmsg属性,先在props数组中定义 一下,这样才能 使用这个数据
//注意:组件中的所有props中的数据,都是通过父组件传递给子组件的。
props:['parentmsg'],
//props中的数据都是只读的,无法重新赋值。
}
}
})
</script>
父组件向子组件传递 方法
<div id="app">
<!-- 因为要传方法,所以要使用事件 绑定v-on -->
<comm @func="show"></comm>
</div>
<template id="tmp1">
<div >
<h1>这是子组件</h1>
<button type="button" @click="myclick">调用父级的方法</button>
</div>
</template>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
//定义一个字面量类型 的 组件模板对象
var com2={
template:"#tmp1",//指定了一个id名,表示去加载这个指定id的template的内容,当作组件的HTML结构
methods:{
myclick(){
//emit触发父组件的方法
this.$emit('func')
}
}
}
var app=new Vue({
el:"#app",
data:{},
methods:{
show(){
console.log("调用了父组件中的 方法")
}
},
components:{
comm:com2
}
})
</script>
子组件向父组件传值
<div id="app">
<!-- 因为要传方法,所以要使用事件 绑定v-on -->
<comm @func="show"></comm>
</div>
<template id="tmp1">
<div >
<h1>这是子组件</h1>
<button type="button" @click="myclick">调用父级的方法</button>
</div>
</template>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
//定义一个字面量类型 的 组件模板对象
var com2={
template:"#tmp1",//指定了一个id名,表示去加载这个指定id的template的内容,当作组件的HTML结构
methods:{
myclick(){
//emit触发父组件的方法
//将123传给父组件的show方法
this.$emit('func',123)
}
}
}
var app=new Vue({
el:"#app",
data:{},
methods:{
show(data){
console.log("调用了父组件中的 方法" + data)
}
},
components:{
comm:com2
}
})
兄弟组件传值
<div id="app">
<com1></com1>
<com2></com2>
</div>
<template id="tmp1">
<button type="button" @click="myclick">兄弟传参</button>
</template>
<template id="tmp2">
<h1>我是接受者</h1>
</template>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var bus =new Vue()
var com1={
template:"#tmp1",
methods:{
myclick(){
//发送者
bus.$emit("show","兄弟传值 ")
}
}
};
var com2={
template:"#tmp2",
mounted(){
//接受者
bus.$on("show",(data)=>{
console.log(data)
})
}
}
var app=new Vue({
el:"#app",
methods:{},
components:{
com1,com2
}
})
</script>