前言
小弟初入前端这是小弟的学习笔记和总结,不适合学习使用;如有大佬发现错误还望指出,在此谢过。
跨域解决
1.vue-cli4创建项目
在根目录下的webpack.config.js文件中添加代码
... //省略代码webpack配置文件
module.exports={
... //省略代码webpack配置进、出口文件
devServer:{
... //省略代码webpack
proxy:{
'/app':{
target:'http://www.weather.com',//要代理的地址
changeOrigin:true,
pathRewrite:{
'^/app':''
}
},
'/api':{
target:'http://www.baidu.com',//要代理的地址
changeOrigin:true,
pathRewrite"{
'^/app':''
}
}
}
}
}
2.vue-cli3创建项目
Config文件夹下的index.js文件
... //省略代码webpack配置文件
module.exports={
dev:{
... //省略代码webpack
proxyTable:{
'/app':{
target:'http://www.weather.com',//要代理的地址
changeOrigin:true,
pathRewrite:{
'^/app':''
}
},
'/api':{
target:'http://www.baidu.com',//要代理的地址
changeOrigin:true,
pathRewrite"{
'^/app':''
}
}
}
}
... //省略代码webpack配置进、出口文件
}
3.生产环境
把dist目录复制到nginx下的html文件夹下面 , 更改conf文件夹下nginx.conf文件如下图
... //省略代码
server{
listen 8082; //端口号
server_name localhost; //ip地址
root D:/nginx-1.17.5/html/dist; //打包生产文件夹位置
index index.html; //打开html文件
... ////省略代码
location /api/{
proxy_pass http://127.0.0.1:3000/;
add_eader Content_Type "teXt/plain;charset = utf_8";
add_header "Access_Control_Allow_Origin" '*';
add_header "Access_Control_Allow_Credentials" 'true';
add_header "Access_Control_Allow_Methods" 'GET','POST';
} //如果多个在此处继续写
... //省略代码
}
打包上线
命令行输入:npm run build
打包出来后项目中就会多了一个文件夹dist,这就是我们打包过后的项目。
第一个问题:
文件引用路径。我们直接运行打包后的文件夹中的index.html文件,会看到网页一片空白,f12调试,全是css,js路径引用错误的问题。
解决:到config文件夹中打开index.js文件。文件里面有两个assetsPublicPath属性,更改第二个,也就是更改build里面的assetsPublicPath属性:assetsPublicPath: './'
assetsPublicPath属性作用是指定编译发布的根目录,‘/'指的是项目的根目录 ,'./'指的是当前目录。
第二个问题:
router-view中的内容显示不出来。路由history模式。这个坑是当你使用了路由之后,在没有后端配合的情况下就手贱打开路由history模式的时候,打包出来的文件也会是一片空白的情况,
解决 : 在 router.js 中将 mode: history注释掉
背景图片引入问题:
img标签引入一般不会有问题,但通过css引入的背景图片或者js引入的就会出现路径问题
解决方法:
找到根目录下build文件中的utils.js文件,搜索ExtractTextPlugin.extract,并为其添加属性和值为 publicPath: '../../',如下图
if (options.extract) {
return ExtractTextPlug4.extract({
use:loaders
publicPath:'../../',
faliback: 'vue-style-loadec'
})
}
通过判断绑定那个数据
<div :icon="marker===1 ? icon2:icon3"><div>
百度地图点的图标(icon)使用本地图片
data(){
return {
icon1:{url:require('../../ass/img/dw.png'),size:{width:300,heigth:157}}
}
}
子父组件传值
父组件传值
<pop v-if='pop' :father='src' @srcChange="handleSrcChange">
<script>
exprort default{
... //省略代码
methods:{
handleSrcChange:function (e){
//父组件自定义事件。参数e为子组件传递过来的参数
console.log(e)
}
}
}
</script>
子组件接收
<template>
{{father}}
<div class="dsd" @click="baseHidden"></div>
</template>
<script>
exprort default{
props:['father']
... //省略代码
methods:{
baseHidden:function (){
//子向父传递数据通过触发事件
// this.$emit("父组件自定义的事件名称","要传递的参数")
this.$emit("srcChange","this.src")
}
}
}
</script>
//传参校验
props: {
// 基础的类型检查 (`null` 匹配任何类型)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
如果父组件传递图片路径,应以父组件的位置写
VueX使用
第一步:安装:npm install vuex --save
第二步:在src目录下创建一个store文件夹并在store文件夹下创建一个index.js文件
文件内容如下
import Vuex from'vuex';
import Vue from 'vue';
Vue.use(Vuex);
//创建仓库
const store Vuex.Store({
//数据
state: {
test_data: “this is some test data”,
color: “light-green”
},
//修改值得方法
mutations: {
setColor(state, coLor) {
state.color= color;
},
Action:{
login({commit}, username) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (username === 'admin') {
commit('setColor',res.data.data)//调用上方mutations中setColor方法修改数据
resolve()
} else {
reject()
}
}, 1000);
})
}
},
modules: {//模块化使用modules定义多个子模块利于组件复杂状态
user,
}
}
export default store
第三步:main.js加载和挂载
import stort from './store/index'
new Vue({
el: ‘#app’,
router,
store,
components: { App },
template: ‘<App!>’
})
第四步:使用
① 修改
//第一个参数为mutations下的方法,二为参数
//不用加载任何vuex的文件main.js中已经全局加载了
this.$store.commit('setColor',res.data.data)
② 使用
this.$store.state.color
③Action派发
this.$store.dispatch('login', 'admin').then(() => {
this.$router.push(this.$route.query.redirect)
}).catch(() => {
alert('用户名或密码错误')
})
④模块化
user.js 定义
export default {
namespaced: true, // 避免命名冲突
// ...
}
访问方式响应变化
// Login.vue
<button @click="login" v-if="!$store.state.user.color">登录</button> //多上一个文件名$store.state.user.color和$store.state.color
this.$store.dispatch('user/login', 'admin').then(() => {
const redirect = this.$route.query.redirect || '/'
this.$router.push(redirect)
}).catch(() => {
alert('用户名或密码错误')
})
路由携带参数
路由页面是设置
<router-link :to="{path:'/xiangx',query:{a:atm.a}}"></router-link> //也可以写成to="/xiangx?a=1"
目标页设置
getImgUrl(){
console.log(this.$route.query.a)//获取参数的值
}
请求
进入项目,npm安装npm install axios --save
在main.js下引用axios
import axios from 'axios';
Vue.prototype.$axios=axios;
使用
this.$axios.post('/api/students',{
params: { name:"admin", pass:123123}, //参数
}).then(res => { console.log(res) //请求成功后的处理数
}).catch(err => { console.log(err) //请求失败后的处理数
})
//有请求头
this.$axios({url:'/app/index',method: 'post',
data: { _csrf: sessionStorage.getItem('csrfToken'), msg:this.msg, typeid:this.typeid,jiajei:this.jiajei,neir:this.neir}, //参数
headers: {'x-csrf-token': sessionStorage.getItem('csrfToken')}
}).then(res => { console.log(res) //请求成功后的处理数
}).catch(err => { console.log(err) //请求失败后的处理数
})
}
扩展优化
优化方案 一
// api.js
/* 登入页面获取公钥 */
export const getPublicKey = (data) => {
return this.$axios.post({ url: '/userGateway/user/getPublicKey' }, data)
}
// 用户登录
export const login = data => {
return this.$axios.post({ url: '/userGateway/userSentry/login' }, data)
}
// 验证码登录
export const loginByCode = data => {
return this.$axios.post({ url: '/userGateway/userSentry/loginByCode' }, data)
}
在组件中使用接口:
<script>
import { getPublicKey } from './config/api.js'
export default {
mounted() {
getPublicKey().then(res => {
// xxx
}).catch(err => {
// xxx
})
}
}
</script>
深度优化
// api.js
const apiList = [
'/userGateway/user/getPublicKey', // 登入页面获取公钥
'/userGateway/userSentry/login', // 用户登录
'/userGateway/userSentry/loginByCode', // 验证码登录
]
let apiName, API = {}
apiList.forEach(path => {
// 使用正则取到接口路径的最后一个子串,比如: getPublicKey
apiName = /(?<=\/)[^/]+$/.exec(path)[0]
API[apiName] = (data) => {
return this.$axios.post({url: path}, data)
}
})
export { API }
在组件中使用接口:
<script>
import { API } from './config/api.js'
export default {
mounted() {
API.getPublicKey().then(res => {
// xxx
}).catch(err => {
// xxx
})
}
}
</script>
Vue-cli 4以上版本修改
将router下的index.js中的mode设置成hash,不要设置成history
在vue.config.js文件中加入如下配置:
module.exports = {
devServer : {
open:true,
port:8089,
host:"127.0.0.1",
proxy:{ // 设置代理
'/api':{
target:'',
changeOrigin:true,
pathRewrite:{
'^/api':''
}
}
}
},
publicPath:'./',
outputDir:'dist',
assetsDir:'static'
}
module.exports = {
publicPath: "./", // 公共路径(必须有的)
outputDir: "dist", // 输出文件目录
// 静态资源存放的文件夹(相对于ouputDir)
assetsDir: "static",
// eslint-loader 是否在保存的时候检查(果断不用,这玩意儿我都没装)
lintOnSave:false,
// 我用的only,打包后小些
runtimeCompiler: false,
productionSourceMap: true, // 不需要生产环境的设置false可以减小dist文件大小,加速构建
devServer: {
open: true, // npm run serve后自动打开页面
host: '0.0.0.0', // 匹配本机IP地址(默认是0.0.0.0)
port: 8080, // 开发服务器运行端口号
proxy: null,
},
}
最全的
module.exports = {
publicPath: "./", // 公共路径(必须有的)
outputDir: "dist", // 输出文件目录
assetsDir: "assets", // 静态资源存放的文件夹(相对于ouputDir)
lintOnSave:false, // eslint-loader 是否在保存的时候检查(果断不用,这玩意儿我都没装)
compiler: false, // 我用的only,打包后小些
productionSourceMap: true, // 不需要生产环境的设置false可以减小dist文件大小,加速构建
// css: { // css相关配置(我暂时没用到)
// extract: true, // 是否使用css分离插件 ExtractTextPlugin
// sourceMap: false, // 开启 CSS source maps?
// loaderOptions: {}, // css预设器配置项
// modules: false // 启用 CSS modules for all css / pre-processor files.
// },
devServer: { // webpack-dev-server 相关配置
open:true, // npm run serve后自动打开页面
host: '0.0.0.0', // 匹配本机IP地址(默认是0.0.0.0)
port: 8080, // 开发服务器运行端口号
proxy: null,
// 注:目前本项目暂时没有写后台接口,没有跨域问题,暂时不配置proxy
},
}
全局变量(例如请求地址的域名
(1)引用组件实现全局变量
新建js文件,将全局变量暴露出来,在需要用到全局变量的地方引入。
import common from "../commom.js; //引入js文件
var serse=common.server
(2)main.js文件挂载实现全局变量
在main.js文件中如下设置
vue.prototype.server="https://www.imovit.com/superhero";//网站地址为全局变量
在需要使用此全局变量的地方this.server就可以
Vue实例的生命周期函数和属性
(1)生命周期函数
创建期间的生命周期函数:
运行期间的生命周期函数:
updated:实例更新完毕之后调用此函数,此时 data 中的状态值和界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
销毁期间的生命周期函数:
(2)实例属性
methods :事件方法执行 例:methods:{}
watch :监听一个值的变化,执行相应函数
computed :计算属性
filters :注册过滤器
components :组件挂载
directives :自定义指令
路由守卫
(1)设置和获取localStorage
localStorage.setItem('Authorization', "123");
alStorage.getItem('Authorization');
(2)设置路由守卫
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
const router =new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},{
path: '/home',
component: resolve => require(['../components/home.vue'], resolve),
},{
path: '/alarm',
component: resolve => require(['../components/alarm.vue'], resolve),
},{
path: '/baidu',
component: resolve => require(['../components/baidumap.vue'], resolve),
},{
path: '/',
component: resolve => require(['../components/HelloWorld.vue'], resolve),
}
]
});
router.beforeEach((to, from, next) => {
if (to.path === '/') {
next();
} else {
let token = localStorage.getItem('Authorization');
if (token === null || token === '') {
next('/');
} else {
next();
}
}
});
export default router;
watch使用
在vue中watch是用来响应数据的,watch的写法有三种
①最简单最常用的
<input type="text" v-model="cityName"/>
new Vue({
el:"#root",
data:{
cityName:'shanghai'
},
watch:{
cityName(newName,oldName){
....
}
}
})
//也可以直接加字符串的方法名
//watch:{
// cityName:'nameChange'
// }
② immediate和handler
监听的数据写成对象的形式,包含handler函数和immediate,immediate默认为flaset,第一次绑定时不会执行函数,值改变时才执行。
new Vue({
el:"#root",
data:{
cityName:'shanghai'
},
watch:{
cityName:{
handler(newName,oldName){
....
},
immediate:true //watch声明时就立即执行
}
}
})
③ deep 深度监听
<input type="text" v-model="cityName"/>
new Vue({
el:"#root",
data:{
cityName:{id:1,name:'shanghai'}
},
watch:{
cityName:{
handler(newName,oldName){
....
},
immediate:true, //watch声明时就立即执行
deep:true //给cityName的所有属性都加上监听,任何一个变化都会执行handler函数
}
}
})
//如果只想监听对象中的一个属性
watch:{
'cityName.name':{
handler(newName,oldName){ /*....*/},
immediate:true, //watch声明时就立即执行
deep:true //给cityName的所有属性都加上监听,任何一个变化都会执行handler函数
}
}
插槽
插槽就是子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的标签。
①默认插槽
//子组件
<template>
<div>
<h1>今天天气状况:</h1>
<slot></slot> //子组件中挖坑
</div>
</template>
//父组件
<template>
<div>
<child><div>多云</div></child>//父组件中填坑
</div>
</template>
②具名插槽
//子组件
<template>
<div>
<div class="header"><slot name="header"></slot></div>//我是页头的具体内容
<div class="defond"><slot></slot></div> //我是默认内容
<div class="footer"><slot name="footer"></slot></div>//我是页尾的具体内容
</div>
</template>
//父组件
<template>
<div>
<child1>
<template slot="header"><p>我是页头的具体内容</p> </template>
<template slot="footer"> <p>我是页尾的具体内容</p></template>
<template ><p>我是默认内容</p></template>
</child1>
</div>
</template>
注意:
父级的填充内容如果指定到子组件的没有对应名字插槽,那么该内容不会被填充到默认插槽中。
如果子组件没有默认插槽,而父级的填充内容指定到默认插槽中,那么该内容就“不会”填充到子组件的任何一个插槽中。
如果子组件有多个默认插槽,而父组件所有指定到默认插槽的填充内容,将“会” “全都”填充到子组件的每个默认插槽中。
<template>
<div id="app">
<hand></hand>
</div>
</template>
<script>
import Hand from './components/HelloWorld.vue'
export default {
name: 'App',
data () {
return {
}
},
components: {
Hand
},
mounted(){
},
methods: {
}
}
</script>
<style scoped>
html,body,#app {
width: 100%;
height: 100%;
margin: 0;
background-color: #f6f6f6;
}
</style>