Vue項目環境搭建css
1) 安裝node
官網下載安裝包,傻瓜式安裝:https://nodejs.org/zh-cn/
2) 換源安裝cnpm
>: npm install -g cnpm --registry=https://registry.npm.taobao.org
3) 安裝vue項目腳手架
>: cnpm install -g @vue/cli
注:2或3終端安裝失敗時,能夠清空 npm緩存 再重複執行失敗的步驟
npm cache clean --force前端
Vue項目建立vue
1) 進入存放項目的目錄 d: 切換D盤 cd D:\python_workspace\day66\代碼node
2) 建立項目 vue create v-projpython
3) 項目初始化 選擇 Manually select features
默認選擇的有Babel Linter / Formatter 在添加Router 和 Vuex
選擇YES
選擇第一個,直接進入
直接第一個進入
選擇第一個In dedicated config files,第一個本身處理
選擇NOT ios
加載環境ajax
選擇改變端口號的地方,而後點擊左邊加號,選擇npm,而後在右邊Name中填寫v-proj,vue-router
在pycharm中選擇settings文件夾,選擇Plugins,在右側搜索框中搜索VUE,下載vuex
pycharm配置並啓動vue項目npm
1) 用pycharm打開vue項目
2) 添加配置npm啓動
終端啓動vue cd D:\python_workspace\day66\代碼\v-proj cnpm run serve
vue組件(.vue文件)
# 1) template:有且只有一個根標籤
# 2) script:必須將組件對象導出 export default {}
# 3) style: style標籤明確scoped屬性,表明該樣式只在組件內部起做用(樣式的組件化)
App.vue
<template> <div id="app"> <!--url路徑會加載不一樣的組件 /red => RegPage | /blue => BluePage 替換router-view標籤,完成也買你切換--> <router-view/> </div> </template>
全局腳本文件main.js(項目入口)
import Vue from 'vue' //加載vue環境 import App from './App.vue' //加載根組件 import router from './router' //加載路由環境 import store from './store' //加載數據倉庫環境 Vue.config.productionTip = false; //配置全局樣式 import '@/assets/css/global.css' new Vue({ el: '#app', router, store, render: function (readFn) { return readFn(App); }, });
vue項目啓動生命週期
1) 加載mian.js啓動項目
i) import Vue from 'vue' 爲項目加載vue環境
ii) import App from './App.vue' 加載根組件用於渲染替換掛載點
iii) import router from './router' 加載路由腳本文件,進入路由相關配置
2) 加載router.js文件,爲項目提供路由服務,並加載已配置的路由(連接與頁面組件的映射關係)
注:無論當前渲染的是什麼路由,頁面渲染的必定是根組件,連接匹配到的頁面組件只是替換根組件中的
<router-view></router-view>
新增頁面三步驟
1) 在views文件夾中建立視圖組件
2) 在router.js文件中配置路由
3) 設置路由跳轉,在指定路由下渲染該頁面組件(替換根組件中的router-view標籤)
組件生命週期鉤子
# 1)一個組件從建立到銷燬的整個過程,就稱之爲組件的生命週期
# 2)在組件建立到銷燬的過程當中,會出現衆多關鍵的時間節點,如 組件要建立了、組件建立完畢了、組件數據渲染完畢了、組件要被銷燬了、組件銷燬完畢了 等等時間節點,每個時間節點,vue都爲其提供了一個回調函數(在該組件到達該時間節點時,就會觸發對應的回調函數,在函數中就能夠完成該節點須要完成的業務邏輯)
# 3)生命週期鉤子函數就是 vue實例 成員
views\Home.vue
<template> <div class="home"> <Nav /> <div class="router"> <button type="button" @click="goPage('/')">主頁</button>
<button type="button" @click="goPage('/red')">紅頁</button>
<button type="button" @click="goPage('/blue')">藍頁</button> <button type="button" @click="goBack('/')">返回上一頁</button> </div> </div> </template> <script> import Nav from '@/components/Nav.vue' export default { name: 'home', components: { Nav }, methods: { goPage(page) { let currentPage = this.$route.path; if (currentPage !== page){ this.$router.push(page); } }, goBack(){ this.$router.go(-1) }, goPageName(pageName) { // alert(name) this.$router.push({ name: pageName }) } } } </script>
views\BluePage.vue
<template> <div class="blue-page"> <Nav></Nav> </div> </template> <script> import Nav from '@/components/Nav' export default { name: "BluePage", components: { Nav } } </script> <style scoped> .blue-page { width: 100vw; height: 100vh; background-color: blue; } </style>
views\RedPage.vue
<template> <div class="red-page"> <Nav></Nav> <h1 class="title" @click="alterTitle">{{ title }}</h1> </div> </template> <script> import Nav from '@/components/Nav' export default { name: "RedPage", data() { return { title: '紅頁' } }, methods: { alterTitle() { alert(this.title) } }, components: { Nav }, beforeCreate() { console.log('組件建立了,但數據和方法還未提供'); // console.log(this.$data); // console.log(this.$options.methods); console.log(this.title); console.log(this.alterTitle); }, // 該鉤子須要掌握,通常該組件請求後臺的數據,都是在該鉤子中完成 // 1)請求來的數據能夠給頁面變量進行賦值 // 2)該節點還只停留在虛擬DOM範疇,若是數據還須要作二次修改再渲染到頁面, // 能夠在beforeMount、mounted鉤子中添加邏輯處理 created() { console.log('組件建立了,數據和方法已提供'); // console.log(this.$data); // console.log(this.$options.methods); console.log(this.title); console.log(this.alterTitle); console.log(this.$options.name); }, destroyed() { console.log('組件銷燬完畢') } } </script> <style scoped> .red-page { width: 100vw; height: 100vh; background-color: red; } .title { text-align: center; cursor: pointer; } </style>
components/Nav.vue
<template> <div class="nav"> <ul> <li :class="{active: currentPage === '/'}"> <router-link to="/">主頁</router-link> </li> <li :class="{active: currentPage === '/red'}"> <router-link to="/red">紅頁</router-link> </li> <li :class="{active: currentPage === '/blue'}"> <router-link to="/blue">藍頁</router-link> </li> </ul> </div> </template> <script> export default { name: "Nav", data(){ return { currentPage:'' } }, created() { this.currentPage = this.$route.path; } } </script> <style scoped> .nav { width: 100%; height: 60px; background-color: orange; } .nav li { float: left; font: normal 20px/60px '微軟雅黑'; } .nav li:hover { cursor: pointer; background-color: aquamarine; } .nav li.active { cursor:pointer; background-color: aquamarine; } .nav li a { display: block; height: 60px; padding: 0 20px; } </style>
router.js
import Vue from 'vue' import Router from 'vue-router' import Home from './views/Home.vue' import RedPage from './views/RedPage.vue' import BluePage from './views/BluePage.vue' Vue.use(Router); export default new Router({ mode: 'history', base: process.env.BASE_URL, routes: [ { path: '/', name: 'home', component: Home }, { path: '/red', name: 'red', component: RedPage }, { path: '/blue', name: 'blue', component: BluePage }, ] })
路由跳轉
src/views/Home.vue
<template> <div class="home"> <Nav /> <h1>{{ hTitle }}</h1> <hr> <div class="router"> <button type="button" @click="goPage('/course')">課程頁</button> <!--<button type="button" @click="goPage('/red')">紅頁</button>--> <button type="button" @click="goPage('/')">主頁</button> <button type="button" @click="goBack('/')">返回上一頁</button> <button type="button" @click="goPageName('/course')">課程頁(name)</button> <router-link :to="{name: 'course'}">課程頁(name)</router-link> </div> </div> </template> <script> import Nav from '@/components/Nav.vue' export default { name: 'home', data(){ return { hTitle: '主頁' } }, components: { Nav }, methods: { goPage(page) { let currentPage = this.$route.path; if (currentPage !== page){ this.$router.push(page); } }, goBack(){ this.$router.go(-1); // this.$router.go(1); }, goPageName(pageName) { // alert(name) this.$router.push({ name: pageName }) } } } </script>
路由傳參
router.js 配置路由
routes: [ { path: '/course', name: 'course', component: Course }, { path: '/course/:id/detail', name: 'course-detail', component: CourseDetail }, ]
src/views/Course.vue
<template> <div class="course"> <Nav /> <h1>{{ cTitle }}</h1> <hr> <div class="main"> <CourseCard v-for="course in course_list" :key="course.name" :course="course" /> </div> </div> </template> <script> import Nav from '@/components/Nav' import CourseCard from '@/components/CourseCard' let course_list = [ { id: 1, name: 'Python入門到入土' }, { id: 2, name: '前端放棄攻略' }, { id: 3, name: '你最棒,他最強' }, { id: 4, name: '基佬修煉法則' }, ]; export default { name: "Course", components: { Nav, CourseCard, }, data() { return { course_list, cTitle: '課程頁', } }, } </script> <style scoped> </style>
src/views/CourseDetail.vue
<template> <div class="course-detail"> <h1>{{ course.name }}</h1> <p>{{ course.info }}</p> <p>{{ course.price }}</p> </div> </template> <script> let course_list = [ { id: 1, name: 'Python入門到入土', price: 6.66, info: '三分鐘入門,一分鐘入土!學了你不吃虧,不學你就廢了!' }, { id: 2, name: '前端放棄攻略', price: 3.66, info: '學習前端,忘掉全部痛苦!' }, { id: 3, name: '你最棒,他最強', price: 5.22, info: '別作夢了!' }, { id: 4, name: '基佬修煉法則', price: 80000, info: '就是他,錯不了!' }, ]; export default { name: "CourseDetail", data () { return { course: {}, cTitle: '', hTitle: '', } }, created() { let id = this.$route.params.id || this.$route.query.id || 1 ; // for of 遍歷的值 | for in 遍歷的是取值的依據(arr是索引,obj是key) for (let course of course_list) { if (id == course.id) { this.course = course; break } } } } </script> <style scoped> </style>
src/components/CourseCard.vue
<template> <div class="course-card"> <h1 @click="goDetail">{{ course.name }}</h1> </div> </template> <script> export default { name: "CourseCard", props: ['course'], methods: { goDetail() { this.$router.push({ name: 'course-detail', }); // 第一種傳參 // this.$router.push({ // name: 'course-detail', // params: { // id: this.course.id // } // }); // 第二種傳參 // this.$router.push({ // name: 'course-detail', // query: { // id: this.course.id // } // }); // 第三種 this.$router.push(`/course/${this.course.id}/detail`); } } } </script> <style scoped> .course-card h1, .course-card a { width: 200px; height: 200px; border-radius: 50%; background-color: coral; font: normal 20px/200px 'STSong'; float: left; text-align: center; cursor: pointer; display: block; } </style>
跨組件傳參
store.js
export default new Vuex.Store({ state: { cTitle: '課程頁' }, mutations: { //mutations 爲 state 中的屬性提供setter方法 //setter方法名隨意,可是參數列表固定兩個:state,newValue setCTitle(state, newValue) { state.cTitle = newValue; } }, actions: { } })
src/views/CourseDetail.vue
<template> <div class="course-detail"> <h1>課程詳情頁</h1> <hr> <p> 修改課程頁標題 <input type="text" v-model="cTitle"> <button @click="changeCTitle">修改</button> </p> <p> 修改主頁標題 <input type="text" v-model="hTitle"> <button @click="changeHTitle">修改</button> </p> <hr> <h1>{{ course.name }}</h1> <p>{{ course.info }}</p> <p>{{ course.price }}</p> </div> </template> <script> export default { methods: { changeCTitle() { // 經過一種存儲數據的方式,完成組件間的數據交互(組件能夠有父子關係,也能夠無關係) // 跨組件傳參能夠有4種方式 // 1) localStorage:永久存儲數據 // 2) sessionStorage:臨時存儲數據(刷新頁面數據不重置,關閉再從新開啓標籤頁數據重置) // 3) cookie:臨時或永久存儲數據(由過時時間決定) // 4) vuex的倉庫(store.js):臨時存儲數據(刷新頁面數據重置) // 1) // this.cTitle && (localStorage.cTitle = this.cTitle); // 4) // console.log(this.$store) // this.$store.state.cTitle = this.cTitle; this.$store.commit('setCTitle', this.cTitle); }, changeHTitle() { this.hTitle && (localStorage.hTitle = this.hTitle); } }, created() { console.log(this.$route); let id = this.$route.params.id || this.$route.query.id || 1 ; } } </script>
vue的cookie操做
安裝 cnpm install vue-cookies
main.js 配置
import cookies from 'vue-cookies' // 導入插件
Vue.prototype.$cookies = cookies; // 直接配置插件原型 $cookies
router.js
routes: [ { path: '/test', name: 'test', component: TestPage }, ]
src/views/TestPage.vue
<template> <div class="test-page"> <Nav /> <h1>測試頁面</h1> <hr> <p> <input type="text" v-model="tokenInput"> <button @click="setToken">設置token</button> </p> <p> <input type="text" v-model="token"> <button @click="getToken">獲取token</button> </p> <p> <button @click="deleteToken">刪除token</button> </p> <hr> </div> </template> <script> import Nav from '@/components/Nav.vue' export default { name: "TestPage", components: { Nav },
data () {
return {
tokenInput: '',
token: '',
}
}, }, methods: { setToken() { // 1) 什麼是token:安全認證的字符串 // 2) 誰產生的:後臺產生 // 3) 誰來存儲:後臺存儲(session表、文件、內存緩存),前臺存儲(cookie) // 4) 如何使用:服務器先生成反饋給前臺(登錄認證過程),前臺提交給後臺完成認證(須要登陸後的請求) if (this.tokenInput) { let token = this.tokenInput; // token的cookie存儲都須要前臺本身完成:增(改)、查、刪 => vue-cookies // 增(改): key,value,exp // 300 = '300s' | '1m' | '1h' | '1d' this.$cookies.set('token', token, '1y'); this.tokenInput = ''; } }, getToken() { // 查:key this.token = this.$cookies.get('token'); }, deleteToken() { // 刪:key this.$cookies.remove('token'); }, } } </script> <style scoped> </style>
cookie通常都是用來存儲token的
vue的ajax操做
axios插件: 在vue框架中安裝 cnpm install axios
main.js配置
import axios from 'axios' // 導入插件
Vue.prototype.$axios = axios; // 直接配置插件原型 $axios
src/views/TestPage.vue
<template> <div class="test-page"> <Nav /> <h1>測試頁面</h1> <div class="ajax"> <input type="text" v-model="username"> <button @click="ajaxAction">提交ajax</button> </div> </div> </template> <script> import Nav from '@/components/Nav.vue' export default { name: "TestPage", components: { Nav }, data () { return { tokenInput: '', token: '', username: '', } }, methods: { setToken() { // 1) 什麼是token:安全認證的字符串 // 2) 誰產生的:後臺產生 // 3) 誰來存儲:後臺存儲(session表、文件、內存緩存),前臺存儲(cookie) // 4) 如何使用:服務器先生成反饋給前臺(登錄認證過程),前臺提交給後臺完成認證(須要登陸後的請求) if (this.tokenInput) { let token = this.tokenInput; // token的cookie存儲都須要前臺本身完成:增(改)、查、刪 => vue-cookies // 增(改): key,value,exp // 300 = '300s' | '1m' | '1h' | '1d' this.$cookies.set('token', token, '1y'); this.tokenInput = ''; } }, getToken() { // 查:key this.token = this.$cookies.get('token'); }, deleteToken() { // 刪:key this.$cookies.remove('token'); }, ajaxAction() { if (this.username) { this.$axios({ url: 'http://127.0.0.1:8000/test/ajax/', method: 'get', params: { username: this.username } }).then(function (response) { console.log(response) }).catch(function (error) { console.log(error) }); this.$axios({ url: 'http://127.0.0.1:8000/test/ajax/', method: 'post', data: { username: this.username } }).then(function (response) { console.log(response) }).catch(function (error) { console.log(error) }); } } } } </script> <style scoped> </style>
新建 dg_proj django框架
跨站問題 後臺接收到前臺的請求,能夠接收前臺數據與請求信息,發現請求的信息不是自身服務器發來的請求,拒絕響應數據,這種狀況稱之爲 - 跨域問題(同源策略 CORS)
致使跨域狀況有三種:1) 端口不一致 2) IP不一致 3) 協議不一致
settings.py文件夾
Django如何解決 - django-cors-headers模塊
1) 安裝:pip3 install django-cors-headers
2) 註冊:
INSTALLED_APPS = [ 'corsheaders' ] 3) 設置中間件: MIDDLEWARE = [ ... 'corsheaders.middleware.CorsMiddleware' ] 4) 設置跨域: CORS_ORIGIN_ALLOW_ALL = True
dg_proj/urls.py
from django.conf.urls import url from django.contrib import admin from api import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^test/ajax/$', views.test_ajax), ]
vue的element-ui插件
安裝 cnpm i element-ui -S
main.js配置
import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI);
router.js
routes: [ { path: '/eleui', name: 'eleui', component: EleUIPage }, ]
src/views/ElePage.vue
<template> <div class="ele-ui-page"> <el-container> <el-aside width="200px"> <el-menu :default-openeds="['1', '3']"> <el-submenu index="1"> <template slot="title"><i class="el-icon-message"></i>導航一</template> <el-menu-item-group> <template slot="title">分組一</template> <el-menu-item index="1-1">選項1</el-menu-item> <el-menu-item index="1-2">選項2</el-menu-item> </el-menu-item-group> <el-menu-item-group title="分組2"> <el-menu-item index="1-3">選項3</el-menu-item> </el-menu-item-group> <el-submenu index="1-4"> <template slot="title">選項4</template> <el-menu-item index="1-4-1">選項4-1</el-menu-item> </el-submenu> </el-submenu> <el-submenu index="2"> <template slot="title"><i class="el-icon-menu"></i>導航二</template> <el-menu-item-group> <template slot="title">分組一</template> <el-menu-item index="2-1">選項1</el-menu-item> <el-menu-item index="2-2">選項2</el-menu-item> </el-menu-item-group> <el-menu-item-group title="分組2"> <el-menu-item index="2-3">選項3</el-menu-item> </el-menu-item-group> <el-submenu index="2-4"> <template slot="title">選項4</template> <el-menu-item index="2-4-1">選項4-1</el-menu-item> </el-submenu> </el-submenu> <el-submenu index="3"> <template slot="title"><i class="el-icon-setting"></i>導航三</template> <el-menu-item-group> <template slot="title">分組一</template> <el-menu-item index="3-1">選項1</el-menu-item> <el-menu-item index="3-2">選項2</el-menu-item> </el-menu-item-group> <el-menu-item-group title="分組2"> <el-menu-item index="3-3">選項3</el-menu-item> </el-menu-item-group> <el-submenu index="3-4"> <template slot="title">選項4</template> <el-menu-item index="3-4-1">選項4-1</el-menu-item> </el-submenu> </el-submenu> </el-menu> </el-aside> <el-container> <el-header> <el-row> <Nav/> </el-row> </el-header> <el-main> <i @click="clickAction" class="elm el-icon-platform-eleme"></i> </el-main> <el-footer>Footer</el-footer> </el-container> </el-container> </div> </template> <script> import Nav from '@/components/Nav.vue' export default { components: { Nav }, methods: { clickAction() { // this.$message({ // message: '恭喜你,這是一條成功消息', // type: 'warning', // duration: 1000, // }); this.$confirm('此操做將永久刪除該文件, 是否繼續?', '提示', { confirmButtonText: '肯定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.$message({ type: 'success', message: '刪除成功!' }); }).catch(() => { this.$message({ type: 'info', message: '已取消刪除' }); }); } } } </script> <style scoped> .elm { font-size: 50px; color: tomato; } .el-row { margin: 0 -20px; } .el-header, .el-footer { background-color: #B3C0D1; color: #333; text-align: center; line-height: 60px; } .el-aside { background-color: #D3DCE6; color: #333; text-align: center; line-height: 200px; } .el-main { background-color: #E9EEF3; color: #333; text-align: center; line-height: 160px; } body > .el-container { margin-bottom: 40px; } .el-container:nth-child(5) .el-aside, .el-container:nth-child(6) .el-aside { line-height: 260px; } .el-container:nth-child(7) .el-aside { line-height: 320px; } </style>