76、解析vue项目、在页面组件中使用小组件、解决跨域问题、登陆小案列、scoped作用、ref属性、props其他、混入mixin、插件、Elementui

67 阅读5分钟

解析vue项目

1.为什么浏览器中访问某个地址,会显示某个页面组件
	1.根组件:App.vue  必须是
        <template>
          <div id="app">
            <router-view></router-view>
          </div>
    	</template>
	2.配置路由
    	router---->index.js--->const routes = [
                {
                path: '/ln',
                name: 'ln',
                component: Ln  # 组件,需要导入
            },
        ]
	3.放心大胆的写页面组件  -src---->views文件夹--->xxx.vue
    
    

解析vue.png

在页面组件中使用组件

	1.写一个小组件,eg:写个Child.vue(components文件下写的)
  2.在父组件中,导入组件
		@代指src路径
		import Child from "@/components/Child";
	3.父组件中,注册组件
    	  components: {
            Child
          }
	4.父组件中使用组件
	    <Child :msg="msg" @myevent="handleEvent"></Child>
	5.自定义属性,自定义事件,插槽,跟之前一模一样

基本使用

Child.vue

<template>
  <div>
      <h1>子组件child</h1>
      <button @click="back">后退</button>
      {{title}}
      <button @click="forward">前进</button>
  </div>
</template>
<script>
export default {
    name: "Child",
    data(){
        return {
            title:'首页',
        }
    },
    methods:{
        back(){
            alert('后退了')
        },
        forward(){
            alert('前进了')
        }
    },

}
</script>
<style scoped>
</style>

Ln.vue

<template>
  <div>
      <h1>Ln.Vue的组件</h1>
      <hr>
      <Child></Child>
  </div>
</template>
<script>
import Child from "@/components/Child.vue";
export default {
    name: "Ln.vue",
    components:{Child}
}
</script>
<style scoped>
</style>

组件间数据传递

父传子

Child.vue

<template>
  <div>
      <h1>子组件child</h1>

      <button @click="back">后退</button>
      {{title}}
      <button @click="forward">前进</button>
      <br>
      <h2>数据传递--子组件接收父组件</h2>
      父组件传递给我的:{{name1}}
  </div>
</template>
<script>
export default {
    name: "Child",
    data(){
        return {
            title:'首页',
        }
    },
    methods:{
        back(){
            alert('后退了')
        },
        forward(){
            alert('前进了')
        }
    },
    props:["name1"]

}
</script>
<style scoped>
</style>

Ln.vue

<template>
  <div>
      <h1>Ln.Vue的组件</h1>
      我传递给子组件的:{{username}}
      <hr>
      <Child :name1="username"></Child>
  </div>
</template>
<script>
import Child from "@/components/Child.vue";
export default {
    name: "Ln.vue",
    components:{Child},
    data(){
        return {
            username:'hello nana'
        }
    }
}
</script>
<style scoped>
</style>

子传父

Child.vue

<template>
  <div>
      <h1>子组件child</h1>
      <button @click="back">后退</button>
      {{title}}
      <button @click="forward">前进</button>
      <br>
      <h2>数据传递--子组件接收父组件</h2>
      父组件传递给我的:{{name1}}
      <br>
      <h2>数据传递--子组件给父组件传递消息</h2>
      <p><input type="text" v-model="name2">-->{{name2}}&nbsp;&nbsp; <button @click = 'handleSend'>给父组件发送消息</button></p>

  </div>
</template>
<script>
export default {
    name: "Child",
    data(){
        return {
            title:'首页',
            name2:''

        }
    },
    methods:{
        back(){
            alert('后退了')
        },
        forward(){
            alert('前进了')
        },
        handleSend(){
            this.$emit('myevent',this.name2)
        }
    },
    props:["name1"]
}
</script>
<style scoped>
</style>

Ln.vue

<template>
  <div>
      <h1>Ln.Vue的组件</h1>
      我传递给子组件的:{{username}}
      <hr>
      <Child :name1="username" @myevent = 'handevent' ></Child>

  </div>
</template>
<script>
import Child from "@/components/Child.vue";
export default {
    name: "Ln.vue",
    components:{Child},
    data(){
        return {
            username:'hello nana'
        }
    },
    methods:{
        handevent(name){
            alert('接收到子组件传递的消息----->'+name)

        }
    }
}
</script>
<style scoped>
</style>

插槽的使用

Child.vue

<template>
  <div>
      <h1>子组件child</h1>

      <button @click="back">后退</button>
      {{title}}
      <button @click="forward">前进</button>
      <br>
      <h2>数据传递--子组件接收父组件</h2>
      父组件传递给我的:{{name1}}
      <br>
      <h2>数据传递--子组件给父组件传递消息</h2>
      <p><input type="text" v-model="name2">-->{{name2}}&nbsp;&nbsp; <button @click = 'handleSend'>给父组件发送消息</button></p>
      <h2>插槽---无名</h2>
      <slot></slot>
      <h2>插槽---有名</h2>
      <slot name = 'middle'></slot>
      <slot name = 'min'></slot>


  </div>
</template>
<script>
export default {
    name: "Child",
    data(){
        return {
            title:'首页',
            name2:''
        }
    },
    methods:{
        back(){
            alert('后退了')
        },
        forward(){
            alert('前进了')
        },
        handleSend(){
            this.$emit('myevent',this.name2)
        }
    },
    props:["name1"]

}
</script>
<style scoped>
</style>

Ln.vue

<template>
  <div>
      <h1>Ln.Vue的组件</h1>
      我传递给子组件的:{{username}}
      <hr>
      <Child :name1="username" @myevent = 'handevent' >
          <div>无名的插槽</div>
          <div slot="min">有名插槽--min</div>
          <div slot="middle">有名插槽--middle</div>
      </Child>

  </div>
</template>
<script>
import Child from "@/components/Child.vue";
export default {
    name: "Ln.vue",
    components:{Child},
    data(){
        return {
            username:'hello nana'
        }
    },
    methods:{
        handevent(name){
            alert('接收到子组件传递的消息----->'+name)
        }
    }
}
</script>
<style scoped>
</style>

解决后端跨域问题

针对在vue中向后端django中发起post请求

"""
Network Error
AxiosError: Network Error at XMLHttpRequest.handleError 
"""

1.安装
	pip3.8 install django-cors-headers
2.注册app
        INSTALLED_APPS = (
            ...
            'corsheaders',
            ...
        )
3.配置中间件
        MIDDLEWARE = [  
            ...
            'corsheaders.middleware.CorsMiddleware',
            ...
        ]
    
4. 配置文件中加入:setting下面添加下面的配置
        CORS_ORIGIN_ALLOW_ALL = True
        CORS_ALLOW_METHODS = (
            'DELETE',
            'GET',
            'OPTIONS',
            'PATCH',
            'POST',
            'PUT',
            'VIEW',
        )

        CORS_ALLOW_HEADERS = (
            'XMLHttpRequest',
            'X_FILENAME',
            'accept-encoding',
            'authorization',
            'content-type',
            'dnt',
            'origin',
            'user-agent',
            'x-csrftoken',
            'x-requested-with',
            'Pragma',
            'token'
        )

登陆小案例

步骤

1.登录页面:LoginView.vue
2.访问/login 显示这个页面组件
3.在LoginView.vue写html,和js,axios
	ps:安装 axios
  		cnpm install -S axios --->S:把安装的axios放到package.json中
4.写ajax,向后端发送请求,给按钮绑定一个事件
		eg:
	    handleSubmit() {
          console.log(this.name, this.password)
          axios.post('http://127.0.0.1:8000/login/', {
            name: this.name,
            password: this.password
          }).then(res => {
            # console.log(res.data)
            if (res.data.code == 100) {
              # 跳转到百度
              location.href = 'http://www.baidu.com'
            } else {
              alert(res.data.msg)
            }
          })
        }
5.写个后端的登录接口,处理好跨域问题,处理跨域如下

代码

LoginView.vue

<template>
    <div>
        <h1>登陆</h1>
        <div>
            用户名:<input type="text" v-model="username">
        </div>
        <div>
            密码:<input type="password" v-model="password">
        </div>
        <div>
            <button @click="handleClick">登陆</button>
        </div>


    </div>
</template>

<script>
import axios from "axios"
export default {
    name: "LoginView",
    data(){
        return {
            username:'',
            password:''
        }
    },
    methods:{
        handleClick(){
           axios.post('http://127.0.0.1:8000/login/',{
               username:this.username,
               password:this.password
            }).then(res=>{
                // console.log(res.data) //{code: 100, msg: '登陆成功'}
               if (res.data.code == 100){
                   location.href='https://www.baidu.com'
               }else {
                   //失败
                   alert(res.data.msg)
               }
           })
        }
    }
}
</script>
<style scoped>
</style>

views.py-->django后端

from django.http import JsonResponse

import json

def login(request):
    # print(request.body)  # b'{"username":"nana","password":"123"}'
    data = json.loads(request.body)
    name = data.get('username')
    pwd = data.get('password')
    if name == 'nana' and pwd == '123':
        return JsonResponse({'code':100,'msg':'登陆成功'})
    else:
        return JsonResponse({'code': 101, 'msg': '登陆失败'})

scoped

1.新建的组件加了scoped,表示样式只在当前组件生效,如果不加,子组件都会使用这个样式
  <style scoped>
  </style>

2.作用:让样式在局部生效,防止冲突。

ref属性

1.ref属性
	1.放在普通标签上,通过  this.$refs.名字--->取到的是dom对象,可以直接操作dom
  2.放在组件上,通过该this.$refs.名字--->取到的是组件对象,这样在父组件中,就拿到了子组件对象,对象属性和方法直接用即可

ref放在普通标签上

<template>
<div class = 'home '>
   <h1>refs的使用---原生标签</h1>
    <input type="text" v-model="name" ref="myinput">-->{{name}}
    <p>
            <img :src="img" alt="" height="300px" ref="myimg">
    </p>

    <p>
        <button @click="handleClick">点我看控制台输出</button>
    </p>
    <hr>
     <h1>refs的使用---组件</h1>
</div>
</template>
<script>
import axios from 'axios'
export default {
    name: 'HomeView',
    data(){
        return {
            name:'',
            img:'https://p2.itc.cn/images01/20210315/f7d1d8fe2aae4243bc5a800515c7a515.png'
        }
    },
    methods:{
        handleClick(){
            console.log(this.$refs) //{myinput: input, myimg: img}
            this.$refs.myinput.value='okk'
            console.log(this.name) //nanan-->input框显示'okk'
        }
    }
}
</script>
<style>
</style>

ref放在组件上

HomeView.vue

<template>
<div class = 'home '>
     <h1>refs的使用---组件</h1>
    <HelloWorld :myname="name1" :myage="age" ref="myhello"></HelloWorld>
    <button @click="handleClick1">点我看控制台输出</button>

</div>
</template>
<script>
import HelloWorld from "@/components/HelloWorld.vue";
export default {
    name: 'HomeView',
    data(){
        return {
            name1:'nana',
            age:18
        }
    },
    methods:{
        handleClick1(){
            console.log(this.$refs) //{myhello: VueComponent}
            console.log(this.$refs.myhello) //VueComponent
            console.log(this.$refs.myhello.hobby) //read
            this.$refs.myhello.hobby='play'
            
        }
    },
    components:{HelloWorld},
}
</script>
<style>
</style>

HelloWorld.vue

<template>
  <div class="hello">
      <h2>我是helloworld组件</h2>
      <div>我的名字:{{myname}}</div>
      <div>我的年龄:{{myage}}</div>
      <div>我的爱好:{{hobby}}</div>
  </div>
</template>
<script>
export default {
  name: 'HelloWorld',
    props:['myname','myage'],
    data(){
      return {
          hobby:'read'
      }
    }
}
</script>
<style scoped>
</style>

props

props:父传子之自定义属性

1.功能:让组件接收外部传过来的数据

2.方式:
  1.基本使用
      props: ['msg'],
  2.限制类型:
      props: {'msg': Boolean},
  3.限制类型,必填,默认值
       props: {
          msg: {
            type: String, # 限制类型
            required: true, # 限制必要性
            default: '老王' # 指定默认值
          }
        }  

混入mixin

1.包下的 index.js有特殊含义
	-之前导入 
    import xx from './mixin/index.js'
    -可以写成
		import xx from './mixin'
    ps:类似于包下面的__init__.py

2.mixin(混入)
	功能:可以把多个组件共用的配置提取成一个混入对象

3.使用步骤
	1.定义混入对象:mixin--->index.js中写
		"""
		        export const lqz = {
            data() {
                return {
                    name: 'lqz'
                }
            },
            methods: {
                handleName() {
                    alert(this.name)
                }
            }
        }
		"""
2.使用混入:局部使用,组件中使用
    	import {lqz} from '@/mixin'
         mixins: [lqz] # 注册混入
3.全局使用混入:每个组件都有效main.js中
        import {lqz} from '@/mixin'
        Vue.mixin(lqz)

背景

当有好几个页面,想使用相同的名字或者方法时,会出现代码冗余的情况

<template>
<div class = 'home '>
    <h1>首页</h1>
    <button @click="handleName">点我弹名字</button>
</div>
</template>
<script>
export default {
    name: 'HomeView',
    data(){
        return {
            name:'home'
        }
    },
    methods:{
        handleName(){
            alert(this.name)
        }

    },
}
</script>
<style>
</style>
<template>
  <div class="about">
      <h1>about</h1>
    <button @click="handleName">点我弹名字</button>
  </div>
</template>
<script >
export default {
    name:'AboutView',
    data(){
        return {
            name:'about'
        }
    },
    methods:{
        handleName(){
            alert(this.name)
        }
    },
}
</script>

使用mixin

局部使用

Mixin/index.js

export const ln={
        data(){
        return {
            name:'ln'
        }
    },
    methods:{
        handleName(){
            alert(this.name)
        }
    },
}

AboutView.vue

<template>
  <div class="about">
      <h1>about</h1>
    <button @click="handleName">点我弹名字</button>
  </div>
</template>
<script >
import {ln} from '@/mixin'
export default {
    name:'AboutView',
    data(){
        return {
            name:'about'
        }
    },
    //注册混入
    mixins:[ln]
}
</script>

HomeView.vue

<template>
  <div class="about">
      <h1>home</h1>
    <button @click="handleName">点我弹名字</button>
  </div>
</template>
<script >
import {ln} from '@/mixin'
export default {
    name:'AboutView',
    //注册混入
    mixins:[ln]
}
</script>

全局使用

main.js

import {ln} from '@/mixin'
Vue.mixin(ln)

插件

1.插件功能:用于增强Vue,有很多第三方插件
	(vuex,router,elemetui)

2.定义自己的插件
	本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据

3.使用步骤:
	1.定义插件:plugins--->index.js--->
        export default {
            install() {
            # 1.在vue实例中放属性
            # 2.定义混入,全局都可以使用混入
            # 3.自定义指令(不讲了)--->以后我们可能使用了一个第三方插件,它提供了一些指令  v-lq
            # 4.定义全局组件--->全局
        }
    }
	2.在main.js中 使用插件
        import lqz from '@/plugins'
        Vue.use(lqz)  # 这句话,就会执行lqz中得install,并且把vue传入

使用

定义插件

import Vue from "vue";

export default {
    install(a) {
        console.log('执行了插件', a)
        // 定义指令
        //定义全局指令:跟v-bind一样,获取焦点
        Vue.directive("fbind", {
            //指令与元素成功绑定时(一上来)
            bind(element, binding) {
                element.value = binding.value;
            },
            //指令所在元素被插入页面时
            inserted(element, binding) {
                element.focus();
            },
            //指令所在的模板被重新解析时
            update(element, binding) {
                element.value = binding.value;
            },
        });
        //定义混入,所有vc和vm上都有name和lqz
        Vue.mixin({
            data() {
                return {
                    name: '彭于晏',
                    age: 19,
                };
            },
        });
        // 原型上放方法,所有vc和vm都可以用hello
        Vue.prototype.hello = () => {
            alert("你好啊");
        };
    }
}

plugins/index.js

export default {
    install(vue){
        console.log('插件--->',vue)  //是一个vue对象
    }

}

main.js

import ln from '@/plugins'
Vue.use(ln) //这句话,就会执行lqz中得install,并且把vue传入
1.在vue实例中放属性

plugins/index.js

import Vue from 'vue'
import axios from "axios";
export default {
    install(){
        Vue.prototype.$ajax=axios
    }

}

//等同于:在main.js中写以下代码:
ps:往vue的原型中放axios对象,以后再组件中this.$ajax拿到的就是这个axios对象,直接用即可
import axios from "axios";
Vue.prototype.$ajax=axios

HomeView.vue


<template>
<div class = 'home '>
    <h1>首页</h1>
    <button @click="handleClick">点我看控制台 </button>

</div>
</template>

<script>
export default {
    name: 'HomeView',
    methods:{
        handleClick(){
            this.$ajax.get('http://www.baidu.com').then(res=>{

            })
        }
    }
}
</script>
<style>
</style>
2.定义混入,全局都可以使用混入

plugins/index.js

import Vue from 'vue'
import axios from "axios";
export default {
    install(){
        Vue.mixin({
            data(){
                return {
                    name:'nana',
                    age:18
                }
            },

        })
    }

}

HomeView.vue

<template>
<div class = 'home '>
    <h1>首页</h1>
    {{name}}-->{{age}}
    <button @click="handleClick">点我看控制台 </button>

</div>
</template>

<script>
export default {
    name: 'HomeView',
    methods:{
        handleClick(){
            this.$ajax.get('http://www.baidu.com').then(res=>{

            })
        }
    },
}
</script>
<style>
</style>

Elementui

1.ui 库,控制样式的,它就是vue的一个插件

2.在vue项目中引入   elementui
	1 在项目中安装:
    	cnpm install element-ui -S
	2.main.js配置
    import ElementUI from 'element-ui';       # 把对象引入
    import 'element-ui/lib/theme-chalk/index.css';  # 把样式引入
    Vue.use(ElementUI)
    
  3.看到好看的,直接复制
    1.html
    2.css
    3.js
    
3.文档:https://element.eleme.cn/#/zh-CN/component/installation

补充

1.vue届的ui库
	1.Element Plus - 经典中的经典,全面支持 Vue 3
	2.Vant 3 - 有赞团队开源移动 UI 组件库,全面支持 Vue 3
		https://vant-contrib.gitee.io/vant/#/zh-CN
	3.TDesign - 鹅厂优质 UI 组件,配套工具完满,设计工整,文档清晰
	4.Ant Design Vue - 阿里前端 UI 库,面向企业级中后台
	5.iView:

作业

编写 首页,登录页面,注册页面

LoginView.vue

<template>
    <div>
        <h1>登陆页面</h1>
        <div>用户名: <input type="text" v-model="username"></div>
        <div>密码: <input type="password" v-model="password"></div>

        <el-row>

          <el-button type="success" plain @click="LoginClick">登陆</el-button>

        </el-row>
    </div>
</template>
<script>
export default {
    data(){
        return {
            username:'',
            password:'',

        }

    },
    methods:{
        LoginClick(){
            this.$ajax.post('http://127.0.0.1:8000/login/',{
                username:this.username,
                password:this.password
            }).then(res=>{
                // console.log(res.data) {code: 100, msg: '登陆成功'}
                if (res.data.code==100){
                    alert('登陆成功')
                }else {
                    alert(res.data.msg)
                }
            })
        }
    }
}
</script>
<style scoped>
</style>

RegisterView.vue

<template>
      <div>
        <h1>注册页面</h1>
        <div>用户名: <input type="text" v-model="username"></div>
        <div>密码: <input type="password" v-model="password"></div>

        <el-row>

          <el-button type="success" plain @click="RegisterClick">注册</el-button>

        </el-row>



    </div>

</template>

<script>
export default {
    name: "RegiesterView",
    data(){
        return {
            username:'',
            password:''
        }
    },
    methods:{
        RegisterClick(){
            this.$ajax.post('http://127.0.0.1:8000/register/',{
                username:this.username,
                password:this.password
            }).then(res=>{
                // console.log(res.data) {code: 100, msg: '登陆成功'}
                if (res.data.code==100){
                    alert('注册成功')
                }else {
                    alert(res.data.msg)
                }
            })
        }
    }
}
</script>
<style scoped>

</style>

views.py

from rest_framework.viewsets import ViewSet
from .models import User
from rest_framework.response import Response

class LoginView(ViewSet):
    def login(self,request):
        print(request.data)
        name = request.data.get('username')
        password = request.data.get('password')
        user_obj = User.objects.filter(username=name,password=password).first()
        if not  user_obj:
            return Response({'code':101,'msg':'用户名或密码错误'})
        else:
            return Response({'code': 100, 'msg': '登陆成功'})

class RegisterView(ViewSet):
    def register(self,request):
        print(request.data)
        name = request.data.get('username')
        password = request.data.get('password')
        user_obj = User.objects.filter(username=name).first()
        if user_obj:
            return Response({'code':101,'msg':'用户已经存在'})
        user = User(username=name,password=password)
        user.save()
        return Response({'code': 100, 'msg': '注册成功'})