一、vue项目本地开发完成后部署到服务器后报404是什么原因呢?
1、如何部署?
前后端分离开发模式下,前后端是独立部署的,前端只需要将打包后的构建物上传至目标服务器的web容器指定的静态目录下即可。
Vue项目在构建完后,会生成一系列的静态文件,常规部署只需要将打包后的文件上传至目标服务器即可。如nginx:配置完成后需要重启nginx(nginx -s reload),操作完后就可以在浏览器输入域名进行访问了。
server {
listen 80;
server_name www.xxx.com;
location / {
index /data/dist/index.html;
}
}
2、404问题
但是vue项目在本地时运行正常,但部署到服务器中,刷新页面,出现404错误是什么原因?
HTTP 404意味着链接指向的资源不存在,只有history模式会出现这个问题,hash模式不会出现。为什么?
根据配置,在地址栏中输入www.xxx.com时会打开我们dist目录下的index.html文件,在跳转路由进入到www.xxx.com/login
在www.xxx.com/login页面执行刷新操作,nginx location是没有相关配置的,所以就会出现404.
hash模式下没有问题是因为路由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:
server{
listen 80;
server_name www.xxx.com;
location / {
index /data/dist/index.html;
try_files $uri $uri/ /index.html;
}
}
修改完配置文件后记得配置的更新:
nginx -s reload
设置后服务器就不会再返回404错误页面,因为对于所有路径都会返回index.html文件。为了避免这种情况,你应该在vue应用里面覆盖所有的路由,然后再给出一个404页面
const router=new VueRouter({
mode:'history',
routes:[
{path:'*',component:NotFoundComponent}
]
})
关于后端配置方案还有:Apache、nodejs等,思想是一致的。
二、data属性为什么是一个函数而不是一个对象?
组件实例对象data必须为函数,目的是为了防止多个组件实例对象之间共用一个data,产生数据污染。采用函数的形式,initData时会将其作为工厂函数返回全新的data对象。
如果不同组件的data是一个对象,那么修改data中的key会同步修改另一个组件。这是因为它们共用了同一个内存地址,componentA修改的内容同样会对componentB产生影响。
如果采用函数形式定义data,则不会出现这种情况(因为函数返回的对象内存地址并不相同)。修改componentA组件data属性的值,componentB的值不受影响。
vue组件可能会有多个实例,采用函数返回data,使每个实例对象的数据不会受到其他实例对象的污染。
vue源码中会对data类型进行判断,如果不是function则会警告提示。
扩展:在定义Vue实例(即根实例对象)时,data既可以是一个函数也可以是一个对象。因为根实例是单例,不会产生数据污染情况。
三、vue2动态给data添加一个新的属性,视图却没有更新是为什么?
原因:Vue2通过Object.defineProperty实现数据响应式,当访问或修改已经定义过的属性值的时候都能够触发setter和getter。但是为obj添加新属性的时候,却无法触发事件属性的拦截。原因是一开始旧的属性就被设置成了响应式数据,而新增的属性并没有通过Object.defineProperty设置成响应式数据。
解决方案:
(1)Vue.set(要修改的对象,新属性名,新属性值),适用于为对象添加少量属性。
(2)Object.assign({},新对象名, 新对象值即旧对象+新属性)//需要重新定义一个变量,适用于为对象添加多个属性。
(3)this.$forceUpdate()不推荐!!!:$forceUpdate会迫使Vue实例重新渲染。如果需要在vue中做一次强制更新,99.9%的情况是在某个地方做错了事。$forceUpdate仅仅会影响实例本身和插入插槽内容的子组件,而不是所有子组件。
PS:vue3是用过proxy实现数据响应式的,直接动态添加新属性仍可以实现数据响应式。
<template>
<p v-for="(value,key) in items" :key="key">{{value}}</p>
<p v-for="(value,key) in newItems" :key="key">{{value}}</p>
<el-button @click="addNewProperty">动态添加新属性</el-button>
</template>
<script>
import Vue from 'vue'
data{
return{
items:{oldProperty:'旧属性'},
newItems:null
}
}
methods:{
addNewProperty(){
//未更新
this.items.newProperty='新属性'
console.log(this.items)
//方式一:Vue.set()实现更新,需要引入Vue
Vue.set(this.items,'newProperty','新属性')
//方式二:Object.assign()实现更新
this.newItems=Object.assign({},this.newItems,{...this.items,newProperty:'新属性'})
//方式三:$forceUpdate()
this.$forceUpdate()
}
}
</script>