VUE08

1.说下$attrs$listeners的使用场景。

vue组件的数据通信方式很多,本篇着重讲$attrs/$listeners
神助是v-bind="$attrs"/v-on="$listeners

$attrs/$listeners的常用场景:封装第三方组件或者表单组件,从而减少组件处理成本。

$attrs
使用组件的时候,vue内部会将组件上面的属性,自动会合并到组件内部根元素上面。

<template lang="pug">
  list-item(a="a" b="b" c="c" style="color:red")
</template>
<!-- ListItem组件 -->
<template lang="pug">
  section(title="hello") 我是组件内部
</template>

渲染的时候会这样

<section title="hi" a="a" b="b" c="c">组件内部</section>

但这里限制在组件根元素上,若,组件内部其他元素也需要使用属性呢,此时就用到$attrs。

<template lang="pug">
section(title="hi") 组件内部
  //- { "a": "a", "b": "b", "c": "c" }
  div {{$attrs}}
</template>

这里如果不希望根元素继承那些属性,可以在组件内部配置inheritAttrs: false

$listeners
同理,对于事件,如果组件上面的事件是native模式,组件内部的最外层元素也会自动绑定该事件。

<template lang="pug">
  list-item(@click.native="()=>{ title = 1}")
</template>
<!-- ListItem组件 -->
<template lang="pug">
  section 我是组件内部
</template>

渲染的时候,事件就会自动绑定到最外层元素上面

<section @click="()=>{ title = 1}">组件内部</section>

但这里任然限制在组件根元素上,若,组件内部其他元素也需要绑定事件呢,此时就用到$listeners,其是非native事件的合集。
在这里插入图片描述

<template lang="pug">
//- 父组件
div
  span {{title}}
  list-item(
    @click="()=>{ title = '点了 内部绑定事件的元素'}"
    @mousedown="()=>{ title = 'mousedown'}"
    @click.native="()=>{ title='点了 内部根元素'}")
</template>
<script>
import ListItem from "@/components/ListItem";
export default {
  name: "List",
  components: { ListItem },
  data() {
    return {
      title: "点击组件的不同元素修改标题"
    };
  }
};
</script>
<template lang="pug">
section(title="hi") 组件根元素
  div(@click.stop="$listeners.click") 组件绑定事件的元素
</template>
<script>
export default {
  name: "ListItem",
  mounted() {
    // {click:fn,mousedown:fn}
    console.log("$listeners", this.$listeners);
  }
};
</script>

使用场景:封装第三方组件、表单组件

封装第三方组件、或者表单组件的的时候使用,往往结合v-bind=“ a t t r s " / v − o n = " attrs"/v-on=" attrs"/von="listeners”,这样就不用考虑用户给组件传入什么属性或者事件了。
比如希望封装baidu-map组件,而baidu-map上面的属性和事件直接用他们自己库的。

<template lang="pug">
  enforced-map(:title="title" @resizeMap="...")
</template>
<!-- EnforcedMap.vue  -->
<template lang="pug">
div
  baidu-map(v-bind="$attrs" v-on="$listeners")
</template>

封装表单组件的时候,inputListeners之类的计算属性通常非常有用。
始终牢记,子组件想要改变父组件的数据,需要$emit哈。

2.分析下Vue项目本地开发完成后部署到服务器报错404原因?

前后端分离开发模式下,前后端是独立布署的,前端只需要将最后的构建物上传至目标服务器的web容器指定的静态目录下即可

我们知道vue项目在构建后,是生成一系列的静态文件

常规布署我们只需要将这个目录上传至目标服务器即可

// scp 上传 user为主机登录用户,host为主机外网ip, xx为web容器静态资源路径
scp dist.zip user@host:/xx/xx/xx

让web容器跑起来,以nginx为例

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
  }
}

配置完成记得重启nginx

// 检查配置是否正确
nginx -t 

// 平滑重启
nginx -s reload

操作完后就可以在浏览器输入域名进行访问了

当然上面只是提到最简单也是最直接的一种布署方式

vue项目在本地时运行正常,但部署到服务器中,刷新页面,出现了404错误
先定位一下,HTTP 404 错误意味着链接指向的资源不存在

问题在于为什么不存在?且为什么只有history模式下会出现这个问题?
Vue是属于单页应用(single-page application)

而SPA是一种网络应用程序或网站的模型,所有用户交互是通过动态重写当前页面,前面我们也看到了,不管我们应用有多少页面,构建物都只会产出一个index.html

现在,我们回头来看一下我们的nginx配置

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
  }
}

可以根据 nginx 配置得出,当我们在地址栏输入 www.xxx.com 时,这时会打开我们 dist 目录下的 index.html 文件,然后我们在跳转路由进入到 www.xxx.com/login。

hash没问题?
关键在这里,当我们在 website.com/login 页执行刷新操作,nginx location 是没有相关配置的,所以就会出现 404 的情况。
router hash 模式我们都知道是用符号#表示的,如 website.com/#/login, hash 的值为 #/login

它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对服务端完全没有影响,因此改变 hash 不会重新加载页面

hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 website.com/#/login 只有 website.com 会被包含在请求中 ,因此对于服务端来说,即使没有配置location,也不会返回404错误

产生问题的本质是因为我们的路由是通过JS来执行视图切换的,

当我们进入到子路由时刷新页面,web容器没有相对应的页面此时会出现404

所以我们只需要配置将任意页面都重定向到 index.html,把路由交由前端处理

对nginx配置文件.conf修改,添加 try_files $uri $uri/index.html`;

uri/ /index.html;

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
    try_files $uri $uri/ /index.html;
  }
}

修改完配置文件后记得配置的更新

```csharp
nginx -s reload

这么做以后,你的服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件

为了避免这种情况,你应该在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 页面

const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '*', component: NotFoundComponent }
  ]
})

3.v-once的使用场景?

v-once
应用场景: 如果显示的信息后续不需要再修改,使用v-once,这样可以提高性能。只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

4.Vue表单修饰符.lazy的理解

默认情况下,在每次 input 事件触发后将输入框的值与数据进行同步。
你可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步。即光标离开才更新视图。

<input type="input" v-model.lazy="message">
<p class="input-value">{{ message }}</p>

加上.lazy后相当于 双向数据绑定不起作用了。

注意:el-input不支持v-model修饰符
补充:
.trim
动过滤用户输入的首尾空白字符

<input type="input" v-model.trim="message">
<p class="input-value">{{ message }}</p>

.number
将输入值转为数值类型

<input type="input" v-model.number="message">
<p class="input-value">{{ message }}</p>

如果先输入数字,则会限制你输入的只能是数字
如果先输入的不是数字,则相当于没有使用 .number。

5.Vue为什么要求组件模板只有一个根元素?

每个子组件在其父级virtual dom中作为单个vnode,而在diffing的时候, 当前的结构可以保证每个vnode的唯一性。
因为当前父级的virtual dom作为一个实例管理着自己的每一个vnode。而且当父级知道自己有多少个vnode的时候便于在diff进行重大更改重渲染的时候,始终可以知道多少根节点的HTML ELEMENT可以跳过。它是渲染性能至关重要的一环。
我们简单的概括的话,可以理解成单个根节点可以更好的提高重新渲染的性能,并且让Vue更好的管理当前的虚拟dom。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值