Vue Cli项目搭建
vue项目需要自建服务器:node
什么是node:
- 用C++语言编写,用来运行JavaScript语言
- node可以为前端项目提供server (包含了socket)
一、环境搭建
1、官网下载安装包,傻瓜式安装:https://nodejs.org/zh-cn/
2、装完了后在cmd输入node即可启动一个命令行交互环境,运行javascript代码
3、可以更换国内源,加速下载:npm install -g cnpm --registry=https://registry.npm.taobao.org
在更换源后,所有的npm命令都可以替换为cnpm。
改完后npm的源还是国外的源,cnpm的源是淘宝的源。
4、安装vue cli环境:脚手架,命令行快速创建项目
cnpm install -g @vue/cli
5、安装脚手架报错的时候,需要清空缓存处理
npm cache clean --force
二、项目创建
以管理员的身份运行cmd ,否则可能出现一些不必要的麻烦
- 首先cd切换到目标目录
- 执行:vue create 项目名
- 选择自定义方式创建项目,选取Router, Vuex插件
- 选择第二个进入自定义配置:
5. 执行时,会提示下载源,选择淘宝镜像即可。(有大写的选大写,大写是建议的选项)
6. 具体配置:上下键切换,空格键选择,回车键进入下一步
勾选Babel、Router、Vuex、Formatter
Babel :jsES6语法转换ES5
Router:路由
Vuex:组件数据交互
Formatter:格式化代码
下一步选Y,接下来的配置都是提示选项有大写选大写,没有默认选第一个配置就行
安装完后的目录如下:
三、终端启动项目
- cd到你的项目:cd vue_proj
- npm run serve
- 访问:http://localhost:8080/
四、pycharm配置
- 在使用pycharm开发时,打开后,vue文件会有提示需要安装插件,直接点击下载即可。
- 如果没有提示,那么就要在settings的plugins里面搜索vue.js插件,然后安装。
- 安装完后需要重启ide。
- 如果命令行启动的,在你更改一些代码后,页面没有刷新,这时候在命令行按ctrl+c就可以刷新。但是连续在命令行按两次ctrl+c就会提示你是否退出,选择退出或不退就行。
- 需要在pycharm配置npm启动项:先点击下拉菜单的Edit,然后点击小+号,选择npm
接着需要指定json文件,运行的脚本等。项目名可以起也可以不起。
上面配置完成后,即可在pycharm启动项目。
我们把上面的项目可以当作一个模板,以后有需要,直接就把除了node_modules的其他文件夹及文件全部复制到新项目
然后再到相应的目录下执行:cnpm install
这样,就会根据电脑环境,项目需求重新下载依赖(node_modules)了。
五、项目目录
来看一下main.js主脚本文件:
import App from './App.vue'
//我可以把它改成下面的形式,@就代表src的绝对路径
//@后就可以采用相对于src的相对路径
import App from '@/App.vue'
import router from './router'
import store from './store'
//这个是禁用提示,比如你第一次下载某个app,刚进去会有操作指南
Vue.config.productionTip = false;
//下面是ES6的写法
// new Vue({
// router,
// store,
// render: h => h(App)
// }).$mount('#app');
//改成ES5的看看
new Vue({
el: '#app',
router: router,
store: store,
render: function (h) {
return h(App)
}
});
.vue文件
router.js的路由配置部分:
{
path: '/',
name: 'home',
// 路由的重定向
redirect: '/home'
}
{
// 一级路由, 在根组件中被渲染, 替换根组件的<router-view/>标签
path: '/one-view',
name: 'one',
component: () => import('./views/OneView.vue')
}
{
// 多级路由, 在根组件中被渲染, 替换根组件的<router-view/>标签
path: '/one-view/one-detail',
component: () => import('./views/OneDetail.vue'),
// 子路由, 在所属路由指向的组件中被渲染, 替换该组件(OneDetail)的<router-view/>标签
children: [{
path: 'show',
component: () => import('./components/OneShow.vue')
}]
}
<router-link to="/">Home</router-link> router-link渲染为a标签
store.js:vuex
// 在任何一个组件中,均可以通过this.$store.state.msg访问msg的数据
state: {
msg: "状态管理器"
},
// 让state拥有多个状态值
mutations: {
// 在一个一个组件中,均可以通过this.$store.commit('setMsg', new_msg)来修改state中的msg
setMsg(state, new_msg) {
state.msg = new_msg
}
},
// 让mutations拥有多个状态值
actions: {
}
六、案例
6.1、在根组件中渲染页面组件
我们要在views中创建一个Main.vue,用来作为主页:
<template>
<div class="main">
<h1>{{ title }}</h1>
</div>
</template>
<script>
export default {
name: "Main",
data:function () {
return{
title:'主页'
}
}
}
</script>
<!-- 局部的要写scoped-->
<style scoped>
.main {
/*vh:相对于视窗的高度,那么vw:则是相对于视窗的宽度*/
height: 100vh; /*100vh代表网页撑满一个屏*/
background-color: orange;
}
h1 {
margin: 0; /*去除h1标签自带的margin边距*/
color: red;
}
</style>
接下来我们要考虑的就是如何在页面中显示它,怎么现实呢?这时候就要到App.vue文件中去注册渲染。
<template>
<div id="app">
<!--3:注册完的组件就可以在这里用了-->
<Main></Main>
</div>
</template>
<script>
// 1:要渲染主页的内容,首先要在逻辑中导入
import Main from '@/views/Main'
export default {
//2:导入的是局部组件,需要注册
components:{
Main:Main
}
}
</script>
<!-- 根组件这里不用写scoped-->
<style>
html, body {
margin: 0;
}
</style>
6.2、路由:单页面实现页面之间转跳
先来准备三个文件(局部组件):
Main.vue
<template>
<div class="main">
<h1>{{ title }}</h1>
</div>
</template>
<script>
export default {
name: "Main",
data:function () {
return{
title:'主页'
}
}
}
</script>
<!-- 局部组件要写scoped-->
<style scoped>
.main {
/*vh:相对于视窗的高度,那么vw:则是相对于视窗的宽度*/
height: 100vh; /*100vh代表网页撑满一个屏*/
background-color: orange;
}
h1 {
margin: 0; /*去除h1标签自带的margin边距*/
color: red;
}
</style>
User.vue
<template>
<!--类名一般就是文件名小写-->
<div class="user">
<h1>个人页</h1>
</div>
</template>
<script>
export default {
name: "User"
}
</script>
<style scoped>
</style>
Goods.vue
<template>
<div class="goods">
<h1>商品页</h1>
</div>
</template>
<script>
export default {
name: "Goods"
}
</script>
<style scoped>
.goods {
height: 100vh;
background-color: blue;
}
</style>
接下来要到router.js中注册
import Vue from 'vue'
import Router from 'vue-router'
//导入
import Goods from './views/Goods'
import User from './views/User'
import Main from './views/Main'
Vue.use(Router);
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
//注册
{
path: '/',
name: 'main',
component: Main
},
{
path: '/goods',
name: 'goods',
component: Goods
},
{
path: '/user',
name: 'user',
component: User
},
]
})
最后到App.vue中调用:<router-view /> <!--相当于每个页面要渲染的内容-->
<template>
<div id="app">
<!--注册完的组件就可以在这里用了-->
<ul class="nav">
<li>
<router-link to="/">主页</router-link>
</li>
<li>
<router-link to="/goods">商品页</router-link>
</li>
<li>
<router-link to="/user">个人页</router-link>
</li>
</ul>
<router-view />
</div>
</template>
<script>
export default {
}
</script>
<!-- 根组件这里不用写scoped-->
<style>
html, body,ul,h1 {
margin: 0;
}
.nav {
height: 60px;
background-color: #d2a1ab;
}
.nav li{
list-style: none;
float: left;
/*垂直居中*/
line-height: 60px;
width: 120px;
/*水平居中*/
text-align: center;
}
.nav li:hover{
background-color: aqua;
}
.nav li a{
/*去掉a标签的下划线*/
text-decoration: none;
/*字体大小及样式*/
font: bold 20px/60px 'STSong';
}
ul {
list-style: none;
}
</style>
至此就实现了单页面的局部组件切换了。
6.3、前后台交互(基于6.2的页面Goods)
上面我们已经实现了单页面的切换,那么我们肯定每个页面都要到后台拿数据,比如我点击商品页后就要动态从数据库获取信息,然后展示到前端页面,这就涉及到了前后台的交互问题。
我们以Goods为例来看一下生命周期钩子
- 钩子表示一个vue实例从创建到销毁的这个过程,将这个过程的一些时间节点赋予了对应的钩子函数
- 钩子函数: 满足特点条件被回调的方法
我们在Goods.vue的script中加入钩子
当点击商品页时,会触发钩子:
了解了这个,下面我们以django作为后台,来实现以下交互
因为交互是vue自己完成的,我们拿不到csrf的认证字符串,所以直接去配置文件中把这个中间件注释掉。
然后我们通过axios向后台发请求。
注意,在前后台交互的时候,会产生跨域的问题
什么是跨域问题?
通常情况下,A网页访问B服务器资源时,不满足以下三个条件其一就是跨域访问
1. 协议不同
2. 端口不同
3. 主机不同
django解决跨域问题:
安装django-cors-headers模块
在settings.py中配置
# 注册app
INSTALLED_APPS = [
...
'corsheaders'
]
# 添加中间件
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware'
]
# 允许跨域源
CORS_ORIGIN_ALLOW_ALL = True
然后前端vue这边需要安装axios(ajax):
cnpm install axios --save
接着要去main.js里对axios进行全局配置:
import Axios from 'axios' Vue.prototype.$ajax = Axios;
//配置完后在任何地方都能通过this.$ajax拿到它
具体的Goods的代码如下:
<template>
<div class="goods">
<h1>商品页</h1>
<h2>{{ msg }}</h2>
</div>
</template>
<script>
export default {
name: "Goods",
data:function(){
return {
msg: '123'
}
},
beforeCreate () {
window.console.log("开始创建Goods组件");
},
created () {
window.console.log("Goods组件创建成功, data, methods已拥有");
},
mounted () {
window.console.log("页面已被vue实例渲染, data, methods已更新");
//我们选择渲染完成后拿数据
//请求后台
let _this = this;
this.$ajax({
url:'http://127.0.0.1:8000/goods/',
method:'post',
params:{
info:'前台数据'
}
}).then(function (result) { //then就是回调函数,相当于ajax的success
// this代表的是回调then这个方法的调用者(axios插件),也就是发生了this的重指向
// 要更新页面的title变量,title属于vue实例
// res为回调的对象,该对象的data属性就是后台返回的数据
let data = result.data;
//this指向的是then的function,我们前面定义的_this才是全局
_this.msg = data;
})
}
}
</script>
<style scoped>
.goods {
height: 100vh;
background-color: blue;
}
</style>
后台的视图函数:
def goods(request):
print(request.method)
# axios的请求,原生Django都在GET字典中拿前台数据
print(request.GET)
print(request.POST)
return HttpResponse('后台数据')
阅读目录
Vue项目开发:
前后端完全分离
后端:提供接口数据
前端:页面转跳、页面布局、页面数据渲染全部由前端做
中间交互:请求
搭建Vue项目环境:
Vue项目需要自建服务器:node
node介绍:
1.用C++语言编写,用来运行JavaScript语言
2.node可以为前端项目提供server (包含了socket)
node下载安装:https://nodejs.org/zh-cn/
一路点击下一步就可以。
npm:包管理器 - 为node拓展功能的
# 换国内源,加速下载,通过命令行换源:
# 管理员命令行:npm install -g cnpm --registry=https://registry.npm.taobao.org
# MacOS: sudo npm install -g cnpm --registry=https://registry.npm.taobao.org
# 索引npm的指令都可以换成cnpm
# npm install vuex => cnpm install vuex
vue cli环境:脚手架 - 命令行快速创建项目
# cnpm install -g @vue/cli
# 如果报错:npm cache clean --force
创建Vue项目
起步
1.cd 到目标目录
2.创建项目:vue create 目录名
创建项目的过程
提示下载原:选择淘宝镜像
具体配置:上下键切换,空格键选择,回车键进入下一步
1.第二个选项进入自定义配置
2.Babel jsES6语法转换ES5,Router路由 Vuex组件数据交互 Formatter格式化代码
3...有提示选择大写,没提示默认第一个即可
选y
开始下载:
启动项目
两种启动方式:
①终端启动
1.进入项目:cd到项目目录
2.启动项目:npm run serve
②pycharm配置启动
1.安装vue.js插件,重启
2.配置项目的npm启动项
3.启动node搭建的socket
如果项目环境搭建失败,可以将搭建成功的项目中的相关文件及文件夹:
然后打开管理员打开cmd命令
cd e:\vue-proj进入项目文件目录下
cnpm install 对自己电脑的当前环境进行重新安装依赖,重构项目环境,这样就可以用了,使用pycharm打开该文件夹就行了
该方法可以用于快速创建和搭建项目环境使用,这样就不用每次vue create进行下一步下一步了
项目目录
打开main.js
修改后按ctrl+s保存后页面会实时刷新,且文件后缀都可以省略不写
页面组件开发
组件创建:
创建新组件之后的基本页面情况:
<template>
<!-- 只能有一个根标签 -->
</template> <script>
export default {
name: "Main",
data: function() {
return { }
},
...
}
</script> <style scoped>
/* scoped 可以让样式实现局部化*/
/* 如果让样式实现全局化,则应该写在根组件样式中*/
</style>
组件渲染
<!-- Main.vue 主页组件 -->
<template>
<div class="main">
<h1>{{ title }}</h1>
</div>
</template> <script>
export default {
name: "Main",
data:function () {
return {
title:'主页'
}
}
}
</script> <style scoped>
.main {
height: 100vh;
background-color: beige;
}
h1 {
margin: 0;
color: darkred;
}
</style>
<!-- App.vue根组件 -->
<template>
<div id="app">
<Main></Main> </div>
</template> <script>
import Main from '@/views/Main'
export default {
components:{
Main:Main
}
}
</script> <style>
html, body {
margin: 0;
}
</style>
说明:
路由:router.js
在根组件中设计转跳页面的导航栏
<template>
<div id="app">
<ul class="nav">
<li>主页</li>
<li>商品页</li>
<li>个人页</li>
</ul>
</div>
</template> <script>
import Main from '@/views/Main'
export default {
components:{
Main:Main
}
}
</script> <style>
.nav {
height: 60px;
background-color: silver;
}
.nav li {
float: left;
height: 60px;
width: 123px;
text-align: center;
line-height: 60px;
}
.nav li:hover {
background-color: aquamarine;
} html, body, ul {
margin: 0;
}
ul {
list-style: none;
}
</style>
创建三个页面组件
<!--Main.vue-->
<template>
<div class="main">
<h1>{{ title }}</h1>
</div>
</template> <script>
export default {
name: "Main",
data:function () {
return {
title:'主页'
}
}
}
</script>
<style scoped>
.main {
height: 100vh;
background-color: beige;
}
h1 {
margin: 0;
color: darkred;
}
</style>
<!--Goods.vue-->
<template>
<div class="goods">
<h1>商品页</h1>
</div>
</template> <script>
export default {
name: "Goods"
}
</script> <style scoped> </style>
<!--User.vue-->
<template>
<div class="user">
<h1>个人页</h1>
</div>
</template> <script>
export default {
name: "User"
}
</script> <style scoped> </style>
配置路由(router.js中)
import Vue from 'vue'
import Router from 'vue-router'
import Main from '@/views/Main.vue'
import Goods from '@/views/Goods.vue'
import User from '@/views/User.vue' Vue.use(Router) export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'main',
component: Main
},
{
path: '/goods',
name: 'goods',
component: Goods
},
{
path: '/user',
name: 'user',
component: User
},
//第二种方式
// {
// path: '/about',
// name: 'about',
// // route level code-splitting
// // this generates a separate chunk (about.[hash].js) for this route
// // which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
// }
]
})
根组件中:
<template>
<div id="app">
<ul class="nav">
<li>
<router-link to="/">主页</router-link>
</li>
<li>
<router-link to="/goods">商品页</router-link>
</li>
<li>
<router-link to="/user">个人页</router-link>
</li>
</ul>
<!--<router-view></router-view>-->
<router-view/>
</div>
</template> <script>
import Main from '@/views/Main'
export default {
components:{
Main:Main
}
}
</script> <style>
.nav {
height: 60px;
background-color: silver;
}
.nav li {
float: left;
height: 60px;
width: 123px;
text-align: center;
line-height: 60px;
}
.nav li:hover {
background-color: aquamarine;
} html, body, ul, h1 {
margin: 0;
}
ul {
list-style: none;
}
a {
text-decoration: none;
font: bold 20px/60px 'STSong';
}
</style>
前后台交互
axios
// 安装 axios(ajax)的命令
// npm install axios --save
// 为项目配置全局axios(main.js中)
import Axios from 'axios'
Vue.prototype.$ajax = Axios
goods组件中设置ajax给后台发送数据(在组件渲染完毕时候发送)
<!--Goods.vue-->
<template>
<div class="goods">
<h1>商品页</h1>
</div>
</template>
<script>
export default {
name: "Goods",
beforeCreate() {
window.console.log("开始创建Goods组件");
},
created() {
window.console.log("创建Goods组件完毕");
},
mounted() {
window.console.log("Goods组件渲染完毕");
// 请求后台
this.$ajax({
method:'post',
url:'http://127.0.0.1:8000/goods/',
params:{
info:'前台数据'
} }).then(function (res) {
window.console.log(res)
})
}
} </script>
<style scoped> </style>
新建一个Django项目,作为后台接收、返回数据
settings.py中手动将csrf中间件注释掉(这里需要注意真正项目中前后端分离时,Django的csrf中间件时通过代码层面禁用并手写安全认证,这里注释掉主要方便我们测试)
路由配置:
from django.conf.urls import url
from django.contrib import admin
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^goods/', views.goods),
]
视图函数
def goods(request):
print(request.method)
print(request.POST)
print(request.GET) return HttpResponse('后台数据')
发现跨域问题:后台能收到前台发送的请求数据,但是由于跨域问题,只要前台端给后端发送数据,后端都会接收,来者不拒,但是由于跨域问题,导致Django不认识它,所以
不给它返回数据。
## Django跨域问题 #### 什么是跨域 ```python
'''
通常情况下,A网页访问B服务器资源时,不满足以下三个条件其一就是跨域访问
1. 协议不同
2. 端口不同
3. 主机不同
'''
``` #### Django解决跨域 ```python
'''
安装django-cors-headers模块 在settings.py中配置
# 注册app
INSTALLED_APPS = [
...
'corsheaders'
]
# 添加中间件
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware'
]
# 允许跨域源
CORS_ORIGIN_ALLOW_ALL = True
'''
```
解决跨域:
①在pycharm中安装django-cors-headers
②在Django配置文件中:
然后前端进行处理数据:
这样渲染msg后发现报错:
发现msg没有被定义,但是在data中明明已经定义了msg,所以错误不在data中,最后发现在then的回调函数中的this
问题解析:
① 在this.ajax上先声明个变量_this=this将vue实例存起来,然后在then的回调函数中打印this和_this
从以上结果来看,在生命周期钩子函数下的this指向的是当前创建的vue实例,而在这些函数内部使用例如axios与后台交互后回调函数的内部的this并非指向当前的vue实例;
箭头函数相当于匿名函数,并且简化了函数定义。看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。此时this在箭头函数中已经按照词法作用域绑定了。很明显,使用箭头函数之后,箭头函数指向的函数内部的this已经绑定了外部的vue实例了.
vue-cookie
// 安装cookie的命令
// npm install vue-cookie --save
// 为项目配置全局vue-cookie(在main.js中)
import VueCookie from 'vue-cookie'
// 将插件设置给Vue原型,作为全局的属性,在任何地方都可以通过this.$cookie进行访问
Vue.prototype.$cookie = VueCookie
// 持久化存储val的值到cookie中
this.$cookie.set('val', this.val)
// 获取cookie中val字段值
this.$cookie.get('val')