long blogs

进一步有进一步惊喜


  • Home
  • Archive
  • Tags
  •  

© 2025 long

Theme Typography by Makito

Proudly published with Hexo

vue笔记

Posted at 2019-04-29 笔记 前端 

1、*.vue的文件

表示一个vue组件,和使用commponet生成的模版类似,但是比之要多出一点东西,单页式组件
(1)视图模版 <template><div id="app"></div></template> 这是html的模版
(2)样式定义 <style></style> 可以放置样式
(3)组件代码 <script></script> js处理,代码逻辑
如何在.vue文件中调用声明的数据
使用this来获取相应的数据,比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default {
name: 'Page2',
data (){
return {
number: 1
}
},
methods: { // 方法属性
back(e){ // 设置了按钮的点击监听事件
// alert("你点击了我")
this.number+=1;
console.log(this.number);
},
clickbtn(){
// alert("计算属性");
this.number-=1;
}
},

声明了一个number的数据,使用this.number便可以获取该值,但是并不是所有的地方使用this语句便可以获得值得。
问题
使用back:()=>{}和back(){}的区别
***.vue组件相互引用**
在某vue文件中加载另一组件。和配置路由的嵌套不同。
在<script>标签中使用
import mycomponent from './xxx.vue'
暴露components:{mycomponent}
在<template>标签中可以使用<mycomponent>来加载组件。注意和路由渲染之间的区别。
一个列子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<div id="Page1inner">
这是Page1inner的内容,在这个页面中将使用饿了么组件并
使用内嵌组件
<el-button>按钮</el-button>
<i class="el-icon-edit"></i>
<mycomponent></mycomponent>
<mycomponent2></mycomponent2>
</div>
</template>

<script>
// 引入其他的组件
import mycomponent from './mycomponent.vue'
import mycomponent2 from './mycomponent2.vue'

export default {
components:{
mycomponent,mycomponent2
}
}
</script>
<style>
</style>

2、样式绑定

npm安装less编译包
$ npm i less style-loader css - loader less-loader - D
在包配置中配置

1
2
3
4
{
test:/\.less$/, // 配置less样式
loader:"style-loader!css-loader!less-loader"
}

在<script></script> 标签中引用less文件
import './assetd/xxx.less'

在<style></style> 中引用。

1
2
3
4
<style scoped>
@import './assets/xxx.less'
</style>

这种方式还没运行起来

3、编程技巧

(1)凡是样式绑定必然是绑定到判断对象上的,不能直接写CSS类名,即使是一个固定的CSS类也都要这样写
(2)

4、路由的一些理解

4.1 路由的声明和引用

引用 import VueRouter from 'vue-router
使用 Vue.use(VueRouter)
实例化

1
2
3
4
5
6
7
const router = new VueRouter({
mode: 'history', // 可选
routes: [
{name: 'Home', path: '/Home', component: Home},
{name: 'Layout', path: '/Layout', component: Layout}
]
})

相关说明:name 别名,在<router-link> 的 to = “Home” 和 to=”/Home” 相同的作用。但是使用别名的话更改只要改一个地方就行了。
name还可以直接再js中使用
this.$router.push({name: 'Home'})
当调用该js的时候就会转到home中了

4.2 获得url中的路由的参数

需求描述:
当前页面的请求url为http://localhost:9528/#/login?examId=23414515151
我想要将examId的值给获取并做进一步处理。
实现:
监听路由的变化,当路由变化时获得路由的值。

1
2
3
4
5
6
7
8
9
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect
this.examId = route.query.examId
},
immediate: true
}
},

核心的语句是route.query.examId
在一些地方,获得请求的url中的参数使用query,特别是获得get请求的时候。有些时候使用body来获得请求中的请求体。
应用的实例为:当用户扫描一个带有路径信息url的二维码时,跳转到登陆页面。这时候,登陆的时候可以将二维码中信息返回的给后台。这样就可以轻松的统计一些移动端的信息。毕竟很少人会通过电脑扫描二维码进行登陆。

4.2 界面和文件之间的关系是怎么样的?

两个非常重要的标签,<router-link>和<router-view>其中link是接收路由事件,view是加载内容的容器。
*.vue作为一个页面组件,通过引用之后加载进入view中,每一个.vue的文件的加载由link和view决定。关于嵌套路由,在view中有viwe,这样如何确定页面是如何加载在某一个页面的呢?使用命名路由便可以让某一个组件渲染进相应的router-view中

4.3 嵌套路由

在某个组件中声明一个<router-view>则可以在该组件中 加载所引入的组件。routes中声明如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
name: 'Home',
paht: '/Home',
componnent: Home,
childern: [ // Home 组件中嵌套tab的组件
{ // 空白子路由
path: '',
component: XX
},
{
path:'Tab', // 路由路径为/Home/tab
component: Tab
}
]
}
  • 多级路由嵌套
    如何配置多级的路由嵌套?首先,假设A中嵌套B,在B中嵌套C。这时候有A.vue和B.vue和C.vue组件。在A.vue文件中有一<router-link>来指向B的路由。在A中的<router-view>来显示B组件的内容,同理在B.vue中也有相应的标签指向C和相应的view来渲染C.
    1、在.vue文件中<router-link>的写法.
    A.vue中<router-link to="B">这是到B的路由</router-link>
    B.vue中<router-link to="C">这是到C的路由</router-link>
    2、路由的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
path: '/A', // 到A的路由
component: A, // A的组件
children: [
{
path: '/B', // 到B的路由,是A的嵌套路由
component: B, // 组件B
children: [
{
path: '/C', // 到C的路由,是B的嵌套,同时是A的嵌套的嵌套
component: C // 组件C
}
]
}
]
}

使用了两个children的关键字,在使用的过程中需要注意的是<router-link>中to属性的值和path的对应关系。使用to="B"和to="/B"是一样的作用,但是推荐使用第一种命名。

  • 路由跳转
    使用js来操作页面的跳转,
    1、使用this.router获得全局的路由
    2、调用相关的函数来进行路由的跳转
    this.$router.push('World') 跳转到World的路由
    this.$router.back() 返回上一个页面
    this.$router.go(n) 跳转到第n次路由
    3、路由跳转带参
    3.1 命名的路由,跳转到list页面,携带路由对象row
    this.$route.push({name: 'list',params: {row:row}})
    3.1 读取路由中的参数。获得row的对象
    this.$route.params.row

4.2 命名视图

解决同级页面组件问题,和嵌套路由不一样
如何渲染在不同的<router-view>?
通过view标签中的name属性来区分。没有设置名字默认为default。

1
2
3
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>

多个页面有多个组件,则在配置路由时和嵌套路由的不一样。使用的components有个s

1
2
3
4
5
6
7
8
{
path: '/pathurl',
components: {
default: Component1, // 默认的视图
a: Component2, // 命名为a的加载的组件为Componnent2
b: Component3 // 命名为b的router-viwe加载组件为Component3
}
}

通过命名路由之后,就把组件分在同一个级别上了,而不是嵌套。可以命名视图和嵌套视图的一起使用来完成应用的布局
配置路由就是嵌套路由和命名视图时所用的路由的综合。
同级路由和嵌套路由整合
假设:World组件中有两个同级的组件A和B,在B的组件中有C和D两个嵌套组件。嵌套组件每次只能渲染其中的一个,同级组件则会全部渲染。
相应的div结构如下

1
2
3
4
5
6
7
8
9
<div id="World">
<!-- 组件A渲染> -->
<div id="A">
<div id="C"></div>
<!-- 或者渲染为<div id="D"></div> -->
</div>
<!-- 组件B渲染 -->
<div id="B"></div>
</div>

由结构可知,A和B都是World的子节点,C和D是A的子节点。使用的配置文件为

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
{
name: 'World',
path: '/World',
component: World,
children:[
{
path: '',
components:
{
A: A,
B: B
},
children: [
{
path: '/C', // 配置C的路由
components:{
Aview: C // C组件渲染到A中name为Aview的router-view中
}
},
{
path: '/D',
components: {
Aview: D //
}
}
]
},

]
}

问题1是若是不指定C和D组件渲染入对应的<router-view>中的话,C和D也会渲染到B的<router-view>中,暂时解决的办法就是使用命名来指定对应的组件渲染在对应的地方。
问题2若是组件嵌套的逻辑过多的话,就会造成路由配置文件的愈发复杂。如何将路由的配置分配在不同的文件中?

4.3 单页面路由配置

在需要设置路由的界面里,在<script>标签中引入vue和vue-router.然后新建一个路由对象,在这个路由对象中配置路由。然后暴露出去之后便可以了。每一个vue文件是否对应一个vue对象。
路由配置也可以使用外置文件引入的方式

4.3.1 一个页面自己声明路由

例子:

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
32
33
<template>
<div id="D">
这是D中的内容
<p>测试内嵌路由</p>
<router-link to="test">测试</router-link>
<router-link to="test2">测试2</router-link>
<router-view/>
</div>
</template>
<script>
import Vue from 'vue'
import Router from 'vue-router'
import Test from './test.vue'
import Test2 from './test2.vue'
Vue.use(Router)
var router = new Router({
routes:[
{
path:'/test',
component:Test
},
{
path:'/test2',
component:Test2
}
]
})
export default {
router
}
</script>
<style>
</style>
4.3.2 引用js路由文件

在根目录创建一个文件夹D,在D中创建文件名为D.js的路由js。内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import Vue from 'vue'
import Router from 'vue-router'
import Test from '@/components/test'
import Test2 from '@/components/test2'
Vue.use(Router)

export default new Router({
routes:[
{
path:'/test',
component:Test
},
{
path:'/test2',
component:Test2
}
]
})

在D.vue文件相应的更改为

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
32
33
34
35
<template>
<div id="D">
这是D中的内容
<p>测试内嵌路由</p>
<router-link to="test">测试</router-link>
<router-link to="test2">测试2</router-link>
<router-view/>
</div>
</template>
<script>
//import Vue from 'vue'
//import Router from 'vue-router'
//import Test from './test.vue'
//import Test2 from './test2.vue'
//Vue.use(Router)
// var router = new Router({
// routes:[
// {
// path:'/test',
// component:Test
// },
// {
// path:'/test2',
// component:Test2
// }
// ]
// })
// 引用D文件夹中的路由文件
import router from '@/D/D'
export default {
router
}
</script>
<style>
</style>

结果和4.3.1配置的结果是一样的效果。

4.5 路由的一些总结

  • 可以使用统一的一个路由文件来维护整个系统的路由。这样的做的好处是利于维护。但是当路由过多的话路由文件中就很大。
  • 每个组件在自己的vue中配置自己的路由信息。好处是灵活,但是不利于维护
  • 折中的办法

4.6 一些路由的坑

  • 使用this.$router.push({ path: '/example',params: {value:value}})路由的参数无法传递.使用this.$router.push({ name: 'Example',params:{value:value}})可以传递参数

5、引入Element组件

1、官方文档得引入
在main.js里面加入

1
2
3
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)

在渲染的页面中,最顶层引入了index.css的样式。这样就可以使用ELement的标签了。因为已经在渲染的Html文件的头部加入样式表,标签便可以被识别。若是使用额外的样式则需要另外添加样式渲染的插件和模块。
###6、Vue文件逻辑处理
1、v-bind的缩写:,例如<a :href="url"></a>
2、v-on的缩写@,例如<a v-on:click="doSomething"></a>=><a @click="doSomething"></a>缩写之后没有:
3、计算属性,任何的复杂逻辑,都应该使用计算属性
(1)使用计算属性,在标签中声明和了一个属性,然后在computed里面对这个属性进行处理。在vue文件中也是直接在 computed:{}之中完成逻辑处理
(2)计算属性和方法的区别,计算属性是依赖于所绑定的数据,若是所依赖的数据没有变化。则使用计算属性就会返回之前计算出来的结果,不会重新计算。方法的话每次访问的话就会重新计算,使用计算机的运算资源。不论所依赖的数据是否已经发生变化。从一定程度来说,计算属性是用空间来换取时间(增加缓存,减少cup的使用时间)。而方法在每一次都会重新执行,申请计算资源。
(3)计算属性默认是没有set方法的。可以自己定义.
4、监听watch:{}是用来对数据进行监听的。若是对数据进行的监听。若是数据发生变化,则会触发监听事件。但是这个和v-model有什么区别??v-model是对<input>、<textarea>、<select>进行双向数据绑定。不会涉及数据处理
5、一个逐渐的data选项必须是一个函数,便于复用。

6、异步和等待(async await)

有时候异步的处理中有同步的逻辑。这时候需要异步中的等待,例如:异步获得数据,但是将数据渲染到模板中的话就必须等待数据加载完毕之后才能进一步渲染,否则将会得到怪异的结果。虽然重渲染可能看不出来,但是网络差的时候。显示的会是模板语法。await就是解决async中的不确定。执行到await函数之后不会再往下执行了,得等到await函数执行完毕之后再执行。

7、promise

8、vue处理每次访问生成新的sessionId问题

在使用axios处,设置axios的对象属性

1
2
3
4
5
6
7
const service = axios.create({
baseURL: baseURL, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
// 设置统一session
service.defaults.withCredentials = true

9、使用v-for时ESLint报错

vue 2.2.0+ 里使用v-for时key是必须的。解决办法,添加:key绑定

使用axios下载文件

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
export function downloadFile(id) {
let service = axios.create({
baseURL: "http://127.0.0.1:8080",
timeout: 5000, // request timeout
responseType:'blob'
})
service.interceptors.request.use(
config => {
config.headers['Authorization'] = getToken()
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)

let downloadReq = service({
url: "/Api/File/DownloadFile",
method: "post",
data: {id: id}
})

downloadReq.then(rsp => {
console.log(">>> Download File")
console.log(rsp)
console.log("<<<")
const filenameUTF8 = rsp['headers']['content-disposition'].split('filename')[1].split("=")[1]
const url = window.URL.createObjectURL(new Blob([rsp.data]))
const link = document.createElement('a')
link.href = url
let filename = decodeURI(filenameUTF8);
link.download = filename
document.body.appendChild(link)
var evt = document.createEvent('MouseEvents')
evt.initEvent('click', false, false)
link.dispatchEvent(evt)
document.body.removeChild(link)
}).catch(err => {
console.log(err)
return false
})
return true
}

使用axios时headers的conenten-disposition字段缺失。

解决办法,后端在返回值的时候设置response.setHeader("Access-Control-Expose-Headers","content-disposition");

后端部分代码

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
32
33
34
35
36
37
38
39
File out = new File(filepath);
if (!out.exists() || out.isDirectory()){
log.warn("DownloadFile id = {} file path = {} error",requestVo.getId(), filepath);
return;
}
log.info("Download File path = {}", filepath);
FileInputStream fileInputStream = null;
BufferedInputStream bufferedInputStream = null;
try{
response.setCharacterEncoding("UTF-8");
response.setHeader("content-Type","application/octet-stream");
response.setHeader("Access-Control-Expose-Headers","content-disposition");
String filename = URLEncoder.encode(fileEntity.getFilename(),"UTF-8");
response.setHeader("content-disposition","attachment;filename="+ filename);
response.setContentType("application/octet-stream");
// 文件下载
byte[] buffer = new byte[1024];
fileInputStream = new FileInputStream(out);
bufferedInputStream = new BufferedInputStream(fileInputStream);
OutputStream outputStream = response.getOutputStream();
int i = bufferedInputStream.read(buffer);
while (i != -1){
outputStream.write(buffer,0,i);
i = bufferedInputStream.read(buffer);
}
}catch (Exception e){
log.error(e.getMessage());
}

try {
if (null != bufferedInputStream){
bufferedInputStream.close();
}
if (null != fileInputStream){
fileInputStream.close();
}
}catch (IOException e){
log.error(e.getMessage());
}

注意 为了不出现中文乱码,需要在后端对文件名进行编码,前端也需要相应的解码。

Share 

 Previous post: git常用操作 Next post: 爬取B站的视频链接 

© 2025 long

Theme Typography by Makito

Proudly published with Hexo