vue学习
vue 官网 https://cn.vuejs.org/
Vue项目开发
环境搭建
-
安装nodejs
https://nodejs.org/zh-cn/ 下载nodejs
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g @vue/cli@4.1.1
创建项目
C:\Users\13922>F:
F:\>cd VUE学习
F:\VUE学习>vue ui
F:\VUE学习>vue create vue_proj
cd vue_proj
npm serve
项目目录
"""
node_modules:项目依赖
public:公用文件
favicon.ico:页面标签图标
index.html:项目的唯一页面(单页面)
src:项目开发文件目录
assets:静态资源
css|js|img
components:小组件
*.vue
views:视图组件
*.vue
App.vue:根组件
main.js:主脚本文件
router.js:路由脚本文件 - vue-router
store.js:仓库脚本文件 - vuex
*.xml|json|js:一系列配置文件
README.md:使用说明
"""
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<%= BASE_URL %>
表示项目根路径
<div id="app"></div>
挂载点, 挂载vue的页面, 如果没有这个标签, vue页面什么都没有
根组件 App.vue 文件
<router-view/>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
主脚本文件
原内容
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App).use(store).use(router).mount('#app')
说明
import Vue from 'vue' // node_modules下的依赖直接写名字
import App from './App.vue' // ./代表相对路径的当前目录,文件后缀军可以省略
import router from '@/router.js' // @ 代表src的绝对路径
import store from './store'
// 在main中配置的信息就是给整个项目配置
// 已配置 vue | 根组件App | 路由 | 仓库
// 以后还可以配置 cookie | ajax(axios) | element-ui
createApp(App).config.productionTip = false;; // Tip小提示
new Vue({
el: '#app',
router: router,
store,
// render: function (fn) {
// return fn(App)
// }
// 解释:function (h) {return 1} | (h) => {return 1} | h => 1
render: readTemplateFn => readTemplateFn(App)
});
如果 import App from './App.vue'
改成 import App from './App.vuexxxxxxxxxxxxx'
如果vue还没启动, 将无法启动, 报如下的错
ERROR Failed to compile with 1 errors 下午1:19:20
This relative module was not found:
* ./App.vuexxxxxxxxxxx in ./src/main.js
如果启动了, 页面上将会报错, 因为vue是单页面实时刷新的
自定义组件1
第一步:在 components 下面新建vue文件
<!--html代码:有且只有一个根标签-->
<template>
<div>
<h1 :class="{active: is_active}" @click="btnClick">我的组件</h1>
</div>
</template>
<!--js代码:在export default {} 的括号内完成组件的各项成员:data|methods|... -->
<script>
export default {
data () {
return {
is_active: false
}
},
methods: {
btnClick() {
this.is_active = !this.is_active;
}
}
}
</script>
<!--css代码:scoped样式组件化 - 样式只在该组件内部起作用 -->
<style scoped>
.active {
color: red;
}
</style>
第二步:在about.vue中引入该组件
<template>
<div class="about">
<h1>This is an about page</h1>
<h2>好</h2>
<mycompon></mycompon>
</div>
</template>
<script>
import mycompon from '@/components/mycomponent'
export default {
components: {
mycompon,
}
}
</script>
自定义组件2
第一步:在 components 下面新建vue文件header.vue
<template>
<div class="header">
<div class="header-slogan">xxxxxx集团 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活!</div>
<div class="header-nav">
<h1 class="header-logo"><router-link to="/"><img src="@/assets/img/header-logo.svg" alt=""></router-link></h1>
<ul class="header-menu">
<li>
<router-link to="/">主页</router-link>
</li>
<li>
<router-link to="/user">用户</router-link>
</li>
</ul>
<div class="header-owner">
<div v-if="is_logout">
<span>登陆</span> | <span>注册</span>
</div>
<div v-else>
<span>Owen</span> | <span>个人中心</span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Header",
data() {
return {
is_logout: true,
page: 'normal'
}
},
methods: {
togglePage(page) {
this.page = page;
}
}
}
</script>
<style scoped>
.header {
width: 100%;
background-color: #ccc;
position: fixed;
}
.header-slogan {
width: 1200px;
font: normal 14px/36px '微软雅黑';
color: #333;
margin: 0 auto;
}
.header-nav {
width: 1200px;
margin: 0 auto;
/*background-color: orange;*/
}
.header-nav:after {
content: "";
display: block;
clear: both;
}
.header-logo, .header-menu {
float: left;
}
.header-owner {
float: right;
}
.header-logo {
width: 118px;
height: 60px;
padding-top: 20px;
/*background: url("/src/assets/img/header-logo.svg") no-repeat;*/
/* background: url("../assets/img/header-logo.svg") no-repeat 0; */
}
.header-menu {
margin-left: 40px;
}
.header-menu li {
float: left;
margin-top: 26px;
cursor: pointer;
margin-right: 20px;
}
.header-menu li:hover {
color: #444;
padding-bottom: 5px;
border-bottom: 2px solid #444;
}
.header-owner {
padding-top: 26px;
}
.active {
color: #444;
padding-bottom: 5px;
}
</style>
第二步:在home.vue中引入该组件
<template>
<div class="home">
<Header></Header>
<div class="wrapper">
<h1>我是主页</h1>
</div>
</div>
</template>
<script>
// @ is an alias to /src
import Header from '@/components/Header.vue'
export default {
name: 'header2',
components: {
Header,
}
}
</script>
<style scoped>
.wrapper {
padding-top: 116px
}
</style>
第三步: 创建User.vue并引入header.vue
- 创建
User.vue
模板文件
<template>
<div class="User">
<Header></Header>
<div class="wrapper">
<h1>User页面</h1>
</div>
</div>
</template>
<script>
// @ is an alias to /src
import Header from '@/components/Header.vue'
export default {
components: {
Header,
}
}
</script>
<style scoped>
.wrapper {
padding-top: 116px
}
</style>
- 在
/src/router/index.js
中添加路由
import User from '../views/User.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/user',
name: 'User',
component: User
},
]
第四步: 在App.vue中渲染组件
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<style>
</style>
第五步: 格式化样式, 并在main.js中引入
- 创建
/src/assets/css/reset.css
body, h1, h2, h3, h4, h5, h6, p, ul {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
a {
text-decoration: none;
color: black;
}
- 在main.js中引入该文件
// 配置reset.css
import '@/assets/css/reset.css'
相关报错
1. 定义了组件没有应用组件
2. 组件调用时候用了和定义组件时候一样的名字
3. 组件调用时候用了和定义组件时候一样的名字, 但是大小写不同
vue.runtime.esm.js?2b0e:619 [Vue warn]: Do not use built-in or reserved HTML elements as component id: header·
路由:vue-router
1)name使用
用{}前面需要用:绑定, {}内写变量,
路由配置
import Main from './views/Main'
routes: [
{
path: '/main',
name: 'main',
component: Main
}
]
视图使用
<router-link :to="{name: 'main'}">主页</router-link>
2)router-link与系统a标签的区别
router-link:会被vue渲染成a标签,但是点击这样的a标签不能发生页面的转跳,只会出现组件的替换
a:也可以完成同样的效果,但是会发生页面的转跳
3)路由重定向
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/home',
redirect: '/', // 重定向
}
]
4)路由传参-1
路由:router/index.js
import Course from '../views/Course.vue'
import CourseDetail from '../views/CourseDetail.vue'
{
path: '/course',
name: 'Course',
component: Course
},
{
path: '/course/detail/:id',
name: 'CourseDetail',
component: CourseDetail
},
转跳页面:Course.vue
<template>
<div class="course">
<h1>名著</h1>
<hr>
<ul>
<li v-for="course in courses" :key="course.title">
<router-link :to="'/course/detail/' + course.id">{{ course.title }}</router-link>
</li>
</ul>
</div>
</template>
<script>
let course_list = [
{ id: 1, title: "西游记" },
{ id: 2, title: "三国演义" },
{ id: 3, "title": "水浒传" },
{ id: 4, "title": "红楼梦" },
];
export default {
name: "Course",
data() {
return {
courses: []
}
},
created() {
this.courses = course_list
}
}
</script>
<style scoped>
li a {
display: block;
}
li,
li a {
border: 1px solid pink;
background-color: rgba(123, 21, 56, 0.3);
margin-top: 10px;
line-height: 80px;
cursor: pointer;
}
</style>
渲染页面:CourseDetail.vue
<template>
<div class="course-detail">
<h1>四大名著详情</h1>
<hr>
<h2>{{ ctx }}</h2>
</div>
</template>
<script>
let course_detail_list = ["数据有误", "西游记", "三国演义", "水浒传", "红楼梦"]
export default {
name: "CourseDetail",
data() {
return {
ctx: ''
}
},
created() {
console.log('详情页面被渲染了')
let index = this.$route.params.id
if (index <= 0 || index > course_detail_list.length) index=0
this.ctx = course_detail_list[index]
},
}
</script>
<style scoped>
</style>
4)路由传参-2
路由:router/index.js
{
path: '/course/detail',
name: 'course-detail',
component: CourseDetail
}
转跳页面:Course.vue
<router-link :to="'/course/detail?id=' + course.id">{{ course.title }}</router-link>
渲染页面:CourseDetail.vue
created () {
let index = this.$route.query.id;
if (index < 0 || index >= course_detail_list.length) index = 0;
this.ctx = course_detail_list[index]
}
5)路由传参-3
路由:router/index.js
{
path: '/course/detail',
name: 'course-detail',
component: CourseDetail
}
转跳页面:Course.vue
<template>
<div class="course">
<h1>课程</h1>
<hr>
<ul>
<li v-for="course in courses" :key="course.title" @click="toDetail(course.id)">
<!--<router-link :to="{name: 'course-detail'}">{{ course.title }}</router-link>-->
<!--<router-link :to="'/course/detail?id=' + course.id">{{ course.title }}</router-link>-->
{{ course.title }}
</li>
</ul>
</div>
</template>
<script>
let course_list = [
{
id: 1,
title: '水浒传'
},
{
id: 2,
title: '西游记'
},
];
export default {
name: "Course",
data () {
return {
courses: []
}
},
// 组件创建成功去获取数据
created () {
this.courses = course_list
},
methods: {
toDetail (id) {
// this.$router.push({path: 'course/detail?id=' + id});
this.$router.push({
name: 'course-detail',
// params: {
// id: id
// },
query: {
id: id
}
});
// this.$router.go(-1)
}
}
}
</script>
<style scoped>
li a {
display: block;
}
li, li a {
border: 1px solid pink;
background-color: rgba(123, 21, 56, 0.3);
margin-top: 10px;
line-height: 80px;
cursor: pointer;
}
</style>
渲染页面:CourseDetail.vue
created () {
let 参数的数据 = this.$route.query.参数的key 或者 this.$route.params.参数的key
}
6)go
this.$router.go(-1) //返回历史记录的前一页
仓库:vuex
1. 仓库配置:store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store({
// 全局可以访问的变量 - 获取值
// 组件内:this.$store.state.title
state: {
title: '主页'
},
// 全局可以访问的方法 - 修改值
// 组件内:this.$store.commit('UpdateTitle', '新值')
mutations: {
UpdateTitle (state, newvalue) {
state.title = newvalue
}
},
actions: {
},
})
2. 组件调用 homesubsub.vue
<template>
<div class="homesubsub">
<input type="text" v-model="val">
<button @click="btnClick">修改</button>
</div>
</template>
<script>
export default {
name: "HomeSubSub",
data () {
return {
val: ""
}
},
methods: {
btnClick() {
this.$store.commit('UpdateTitle', this.val)
console.log(this.$store.state.title)
}
}
}
</script>
<style scoped>
</style>
3. 属性计算 homesub.vue ( computed)
computed: 调用仓库中的变量,使得页面展示的数据实时更新
<template>
<div class="homesub">
<h1>{{ title }}</h1>
<hr>
<HomeSubSub></HomeSubSub>
</div>
</template>
<script>
import HomeSubSub from "@/components/HomeSubSub";
export default {
name: "HomeSub",
components: {
HomeSubSub
},
computed: {
title () {
return this.$store.state.title
}
}
}
</script>
<style scoped>
</style>
4. 主页面展示
<template>
<div class="home">
<Header></Header>
<div class="wrapper">
<HomeSub></HomeSub>
</div>
</div>
</template>
<script>
// @ is an alias to /src
import Header from '@/components/Header'
import HomeSub from '@/components/HomeSub'
export default {
components: {
Header,
HomeSub
},
created () {
console.log(this.$axios)
}
}
</script>
<style>
.wrapper {
padding-top:116px;
}
</style>
前后台交互:axios
1.安装
>: cd 项目目录
>: cnpm install axios --save
2.配置:main.js
import Axios from 'axios'
Vue.prototype.$axios = Axios;
3.跨域问题(同源策略):Access-Control-Allow-Origin => CORS
前提:前台向后跳请求数据
1)服务器不一致 - ip
2)应用不一致 - 端口
3)协议不一致 - http <-> https
1. django解决跨域
- 安装django-cors-headers模块
pip install django-cors-headers
-
在settings.py中配置
注册app
INSTALLED_APPS = [
...
'corsheaders'
]
- 添加中间件
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware'
]
- 允许跨域源
CORS_ORIGIN_ALLOW_ALL = True
4. axios请求方式
get
// this.$axios({
// url: 'http://127.0.0.1:8000/data/',
// method: 'get',
// }).then( (response) => {
// console.log(response)
// })
this.$axios.get('http://127.0.0.1:8000/data/', {params: {usr: 'zero', pwd: '000'}}).then(response => {
console.log(response)
});
post (不使用DRF只能从request.body中取得post请求的响应值)
this.$axios.post('http://127.0.0.1:8000/data/', {username: 'zero', password: '0000', headers: {'Content-Type': 'urlencoded'}}).then(response => {
console.log(response)
})
5. 前台操作Cookie:vue-cookie
安装
>: cd 项目目录
>: cnpm install vue-cookie --save
配置:main.js
import cookie from 'vue-cookie'
Vue.prototype.$cookie = cookie;
使用:在任何方法中
export default {
name: 'Home',
components: {
HelloWorld
},
created() {
this.$axios.post('http://127.0.0.1:8000/data/', {username: 'zero', password: '0000', headers: {'Content-Type': 'urlencoded'}}).then(response => {
console.log(response)
// let token = response.data.token
// 设置cookie
// this.$cookie.set('token', token, 1)
//取出cookie
console.log(this.$cookie.get('token'))
//删除cookie
this.$cookie.delete('token')
})
}
}
element UI 使用
https://element.eleme.cn/#/zh-CN
1. 安装
首先切换到项目目录下
cnpm i element-ui -S
2. 配置main.js
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI) //全局用
3. 使用element
3.1.按钮
<template>
<div class="about">
<h1>This is an about page</h1>
<el-row>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
</el-row>
</div>
</template>
3.2. 布局 (element布局为24等分)
<el-row>
<el-col :span="6">1</el-col>
<el-col :span="12">2</el-col>
<el-col :span="6">3</el-col>
</el-row>
3.3.消息提示
<template>
<div class="about">
<h1>This is an about page</h1>
<el-row>
<el-button :plain="true" @click="open2">成功</el-button>
<el-button :plain="true" @click="open3">警告</el-button>
<el-button :plain="true" @click="open1">消息</el-button>
<el-button :plain="true" @click="open4">错误</el-button>
</el-row>
</div>
</template>
<script>
export default {
methods: {
open1() {
this.$message('这是一条消息提示');
},
open2() {
this.$message({
message: '恭喜你,这是一条成功消息',
type: 'success'
});
},
open3() {
this.$message({
message: '警告哦,这是一条警告消息',
type: 'warning'
});
},
open4() {
this.$message.error('错了哦,这是一条错误消息');
}
}
}
</script>