0%

使用express创建服务器,发起Get,Post请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const express=require('express')
//创建web服务器实例
const app=express()
//监听客户端的get请求post请求,并向客户端响应请求
app.get('/user',(req,res)=>{
res.send({name:'zs',age:20,gender:'男'})
})
app.post('/user',(req,res)=>{
res.send('请求成功')
})
//获取请求参数
app.get("/",(req,res)=>{
//req.query可以获取到客户端发送过来的查询参数向客户端响应一个查询参数
console.log(req.query)
res.send(req.query)
})
//获取到URL中的动态参数
app.get("/user/:id/:username",(req,res)=>{
console.log(req.params)
res.send(req.params)
})

//启动服务器
app.listen(80,()=>{
console.log('express server running at http://127.0.0.1')
})

托管静态资源

express.static():创建一个静态资源服务器,通过如下代码可以将public目录下的图片,CSS文件,JavaScript文件对外开放访问

1
2
3
4
5
6
7
8
9
10
11
12
const express=require('express')
//创建web服务器实例
const app=express()
//托管多个静态资源目录,express.static会根据目录的添加顺序查找所需文件,http://127.0.0.1,public不出现在路径中
app.use(express.static('public'))
app.use(express.static('files'))
//希望挂载前缀
ap.use('/public',express.static('public',))//打开的是http://127.0.0.1/public,如果希望public出现在路径中则将访问前缀写public
//启动服务器
app.listen(80,()=>{
console.log('express server running at http://127.0.0.1')
})

中间件

中间件的作用:

多个中间件之间共享一份req和res,基于这种特性可以在上游的中间件中,统一为req或res对象添加自定义顶点属性或方法,供下游的中间件或路由进行使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const express=require("express")
const app=express()
//中间件的作用:共享req,res
app.use((req,res,next)=>{
const time=Date.now()
req.startTime=time
next()
})
app.get('/',(req,res)=>{
res.send('Home page'+req.startTime)
})
app.get('/user',(req,res)=>{
res.send('User page'+req.startTime)
})
app.listen(80,()=>{
console.log('http://127.0.0.1')
})

中间件分类:

[]: http://expressjs.com/en/guide/using-middleware.html

错误级别的中间件要注册在所有路由之后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const express = require("express");
const app=express()
app.get('/',(req,res)=>{
throw new Error('服务器发生错误')
res.send('Home page')
})
//错误级别中间件必须注册在所有路由之后
app.use((err,req,res,next)=>{
console.error(err.message)
res.send('Something broke:'+err.message)
})
app.listen(80,()=>{
console.log('http://127.0.0.1')
})

使用中间件的注意事项

  • 要在路由之前注册中间件
  • 客户端发送过来的请求,可以连续调用多个中间件进行处理
  • 执行完中间件的业务代码,要记得调用next()函数
  • 连续调用的多个中间件时,多个中间件间共享req和res对象

Web和微信小程序中本地存储的差别

使用上

Web:localStorage.setItem(“key”,”value”)

​ localStorage.getItem(“key”)

小程序中:wx.setStorageSync(“key”,”value”);

​ wx.getStorageSync(“key”)

数据存储

Web:不管存入的是什么类型的数据,最终都会先调用toString(),把数据编程字符串再存进去

小程序:不存在类型转换,存什么类型的数据进去,获取的就是什么类型的数据

swiper存在默认宽度和高度:100%*150px

image存在默认宽度和高度:320px*240px

设计图片和轮播图:

1 先看原图的宽高:750*340

2 让图片的高度自适应 宽度等于100%

3 让swiper标签的高度变成和图片的一样高即可

4 图片标签mode=“widthFix”

父组件向子组件传递数据

1 父组件中:

1
2
3
<view>
<Tab tabs="{{tabs}}" binditemChange="handleItemChange"></Tab>
</view>

2.子组件:

1
2
3
4
5
6
7
properties: {
tabs:{
type:Array,
value:[]
}

},

子组件向父组件传递数据:

1 子组件:用this.triggerEvent(“事件名”,传递的参数)

1
2
3
4
5
6
7
8
9
methods:{
handle(e){
const {index}=e.currentTarget.dataset;
this.triggerEvent("itemChange",{index});


}

}

2 父组件:用”bind+事件名”触发自定义方法

1
2
3
<view>
<Tab tabs="{{tabs}}" binditemChange="handleItemChange"></Tab>
</view>
1
2
3
4
5
6
7
8
9
10
handleItemChange(e){
//console.log(e)
const {index}=e.detail;
let {tabs}=this.data;
tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
this.setData({
tabs
})

}

绑定输入事件

  • 用bindinput
  • 获取输入框的值用e.detail.value
  • 输入框赋值用this.setData({num:e.detail.num})

点击事件

  • 关键字:bindtap
  • 无法在小程序中的事件直接传参,通过自定义事件传参
  • 事件源中获取自定义属性

query参数:

1
2
3
4
5
6
7
8
<li v-for='m in messageList' :key='m.id'>
<!-- 通过query传递参数 -->
<router-link :to="
{
name:'messageDetail',
query:{id:m.id,title:m.title}
}">{{m.title}}</router-link>
</li>

params参数:

1 配置路由声明接收param参数

1
2
3
4
5
6
7
8
9
10
11
{path:'/home',
component:Home,
children:[
{path:'news',
component:News},
{path:'message',
component:Message,
children:[
{path:'detail/:id/:title',name:'messageDetail',component:Detail}//使用占位符声明接收params参数
]}
]},

2 传递参数

1
2
3
4
5
6
7
8
9
10
 <li v-for='m in messageList' :key='m.id'>
<!--跳转并携带params参数,to的字符写法--!>
<router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{m.title}}</router-link>
<!-- 对象写法只能写name不能写path -->
<!-- <router-link :to="
{name:'messageDetail',
params:{id:m.id,title:m.title}

}">{{m.title}}</router-link> -->
</li>

注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置项

props配置

1
2
3
4
5
6
7
8
9
10
11
12
//props第一种写法,值为对象,该对象中的key-value都会以props的形式传给Detail组件
props:{a:1,b:'hello'},
//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数以props的形式传给Detail组件
props:true,
//第三种写法,值为函数
props($route){
return {id:$route.query.id,title:$route.query.title}
},
//解构赋值
props({query}){
return {id:query.id,title:query.title}
}

Detail组件接收参数:

1
2
3
4
5
6
<script>
export default {
name:'Detail',
props:['id','title'],
}
</script>

全局事件总线

一种组件间的通信方式,适用于任意组件间的通信。

安装全局事件总线:

  1. 引入/编写事件库

  2. 在入口文件中挂载

  3. 在组件中引入并使用

    安装:npm install –save vue3-eventbus

    挂载:

    1
    2
    3
    //App.vue
    import eventBus from 'vue3-eventbus'
    app.use(eventBus)

    使用:

    1
    2
    3
    4
    5
    6
    7
    8
    //Button.vue
    import bus from 'vue3-eventbus'
    export default {
    setup(){
    bus.emit('foo',{a:'b'})
    }
    }

    消息订阅预发布(pubsub)

    1. 安装pubsub:npm install pubsub-js

    2. 引入:import pubsub from “pubsub-js”

    3. 接收数据,A组件想接收数据,则在A组件中订阅消息,订阅回调留在A组件自身。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      methods(){
      demo(data){

      }
      }
      mounted(){
      this.pid=pubsub.subscribe('xxx',(msg,data)=>{

      })//订阅消息
      }
      1. 提供数据:pubsub.publish(‘xxx’,数据)
      2. 最好在beforeDestroy钩子中,用Pubsub.unsubscribe(pid)取消订阅

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
setup(){
function myRef(value,delay=500){
let timeout
return customRef((track,trigger)=>{
return {
get(){
console.log(`有人从myRef中读取了数据:${value}`)
track()//通知Vue追踪value的变化(提前和get商量一下,让它认为这个value是可用的)
return value
},
set(newValue){
clearTimeout(timeout)
console.log(`有人从myRef中修改了数据:${newValue}`)
timeout=setTimeout(()=>{
value=newValue
trigger()//通知Vue重新解析模板
},delay)
}
}
})
}
let val=myRef("hello")

return {
val

}


}

shallowReactive:只处理对象最外层属性的响应式(浅响应式)

shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理

什么时候使用?

如果有一个对象数据,结构比较深,但变化时只是外层属性变化==>shallowReactive

如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换==>shallowRef

toRef:

作用:创建一个ref对象,其value值指向另一个对象中的某个属性,可以用来为源响应式对象上的某个 property 新创建一个 ref。然后,ref 可以被传递,它会保持对其源 property 的响应式连接。

语法:const name=toRef(person,’name’)

应用:要将响应式对象中的某个属性单独提供给外部使用时

扩展:toRefs与toRef功能一致,但可以批量创建多个ref对象,语法:toRefs(person),将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref

1
2
3
4
5
6
7
8
9
10
11
12
const state = reactive({
foo: 1,
bar: 2
})

const fooRef = toRef(state, 'foo')

fooRef.value++
console.log(state.foo) // 2

state.foo++
console.log(fooRef.value) // 3

当你要将 prop 的 ref 传递给复合函数时,toRef 很有用:

1
2
3
4
5
export default {
setup(props) {
useSomeFeature(toRef(props, 'foo'))
}
}

即使源 property 不存在,toRef 也会返回一个可用的 ref。这使得它在使用可选 prop 时特别有用,可选 prop 并不会被 toRefs 处理。

toRefs

将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const state = reactive({
foo: 1,
bar: 2
})

const stateAsRefs = toRefs(state)
/*
stateAsRefs 的类型:

{
foo: Ref<number>,
bar: Ref<number>
}
*/

// ref 和原始 property 已经“链接”起来了
state.foo++
console.log(stateAsRefs.foo.value) // 2

stateAsRefs.foo.value++
console.log(state.foo) // 3

当从组合式函数返回响应式对象时,toRefs 非常有用,这样消费组件就可以在不丢失响应性的情况下对返回的对象进行解构/展开:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function useFeatureX() {
const state = reactive({
foo: 1,
bar: 2
})

// 操作 state 的逻辑

// 返回时转换为ref
return toRefs(state)
}

export default {
setup() {
// 可以在不失去响应性的情况下解构
const { foo, bar } = useFeatureX()

return {
foo,
bar
}
}
}

toRefs 只会为源对象中包含的 property 生成 ref。如果要为特定的 property 创建 ref,则应当使用 toRef