vue学习

vue 官网 https://cn.vuejs.org/


Vue项目开发


环境搭建

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/>


image-20201127092737433


主脚本文件

原内容

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)
    })


安装

>: 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>

posted @ 2020-11-27 09:33  cjw1219  阅读(275)  评论(0编辑  收藏  举报