75、练习、动态组件、插槽 、Vue-cli创建项目、vue项目目录结构、vue项目编写规范、es6导入导出语法

99 阅读6分钟

练习

写一个books接口

带按价格排序,前端页面创建完成,向后端发送请求,获取图书属性,表格显示在前端,前端使用监听属性实现点击价格正序和倒序排列

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='./js/vue.js'></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id='app'>
    <button @click="handelClick">价格排序</button>
    <ul v-for="book in book_list">
        <li>书名:{{book.name}}</li>
        <li>价格:{{book.price}}</li>
    </ul>
</div>
</body>
<script>
    var vue = new Vue({
        el: '#app',
        data: {
            book_list: [],
            ordering: 'price'
        },
        methods: {
            handelClick() {
                if ('-'.indexOf(this.ordering) >= 0) {
                    //降序
                    axios.get('http://127.0.0.1:8000/books/?ordering=' + this.ordering).then(res => {
                        console.log(res.data)
                        this.book_list = res.data.data
                    })

                    this.ordering = 'price'
                } else {
                    //升
                    axios.get('http://127.0.0.1:8000/books/?ordering=' + this.ordering).then(res => {
                        console.log(res.data)
                        this.book_list = res.data.data
                    })
                    this.ordering = '-price'
                }
            }
        },
        created() {
            axios.get('http://127.0.0.1:8000/books/').then(res => {
                console.log(res.data)
                this.book_list = res.data.data
            })
        },
    })
</script>
</html>

view.py


from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from .models import Book
from .serilizer import BookSerializer
from rest_framework.response import Response
from rest_framework.filters import OrderingFilter

class BookView(GenericViewSet,ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [OrderingFilter]
    ordering_fields = ['price']
    def list(self, request, *args, **kwargs):
        obj = super().list(request, *args, **kwargs)

        return Response({'code':100,'msg':'成功','data':obj.data},headers={'Access-Control-Allow-Origin':'*'})

urls.py

from django.contrib import admin
from django.urls import path
from app01.views import BookView
from    rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('books',BookView,'books')

urlpatterns = [
    path('admin/', admin.site.urls),
]
urlpatterns +=router.urls

定义组件

组件创建成功,向后端发送请求,后端返回一张图片地址,显示在组件上(网络图片, media下的图片)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='./js/vue.js'></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id = 'app'>

    <child ></child>

</div>

</body>

<script>

    var child = {
        template:`
        <div>
        <h1>子组件</h1>
        <img :src="url" alt="" height="300px">
        </div>
        `,
        data(){
            return {
                url:'',
            }
        },
        methods:{},
        created(){
            axios.get('http://127.0.0.1:8000/img/').then(res=>{
                console.log(res.data)
                this.url = res.data.url
            })

        }
    }
    var vue =new Vue({
        el:'#app',
        data:{},
        methods:{},
        components:{child}
    })
</script>
</html>
from rest_framework.viewsets import ViewSet

class GetImg(ViewSet):
    def list(self,request):
        url = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F5da5a7c4-e8ef-4975-8581-81e42fdba317%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1688648650&t=cfe8b5c2fa170e2a7d4815454cd7956a'
        return Response({'code':100,'msg':'成功','url':url},headers={'Access-Control-Allow-Origin':'*'})
from django.contrib import admin
from django.urls import path
from app01.views import BookView,GetImg
from    rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('books',BookView,'books')
router.register('img',GetImg,'img')

urlpatterns = [
    path('admin/', admin.site.urls),
]
urlpatterns +=router.urls

media文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='./js/vue.js'></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id = 'app'>
    <child ></child>
</div>
</body>
<script>
    var child = {
        template:`
        <div>
        <h1>子组件</h1>
        <img :src="url" alt="" height="300px">
        </div>
        `,
        data(){
            return {
                url:'',
            }
        },
        methods:{},
        created(){
            this.url = 'http://127.0.0.1:8000/media/img/1.jpg'
        }
    }
    var vue =new Vue({
        el:'#app',
        data:{},
        methods:{},
        components:{child}
    })
</script>
</html>
from django.contrib import admin
from django.urls import path
from django.views.static import serve
from django.conf import settings

urlpatterns = [
    path('admin/', admin.site.urls),
    path('media/<path:path>', serve,{"document_root":settings.MEDIA_ROOT}),
]

在上面的子组件就中写一个按钮,点击按钮,把子组件的图片地址,传递到父组件中打印出来(alert)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='./js/vue.js'></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id = 'app'>
    <child  @myevent="handelEvent"></child>
    <br>
    <h1>父组件</h1>
    <img :src="url" alt="">

</div>
</body>
<script>
    var child = {
        template:`
        <div>
        <button @click="SendClick">将图片给父组件</button>
        <h1>子组件</h1>
        <img :src="url" alt="" height="300px">
        </div>
        `,
        data(){
            return {
            }
        },
        methods:{
            SendClick(){
                this.$emit('myevent',this.url)
            }
        },
        created(){
            this.url = 'http://127.0.0.1:8000/media/img/1.jpg'
        }
    }
    var vue =new Vue({
        el:'#app',
        data:{
            url:''
        },
        methods:{
            handelEvent(url){
                alert(url)
                this.url = url
            }
        },
        components:{child}
    })
</script>
</html>

动态组件

效果:有三个按钮,分别是首页、订单、商品,点击某一个按钮,展示该页面

笨办法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='./js/vue.js'></script>
</head>
<body>
<div id='app'>
    <button @click = "who='home'">首页</button>
    <button @click = "who='ordering'">订单</button>
    <button @click = "who='goods'">商品</button>
    <hr>
    <home v-if ='who=="home"'></home>
    <ordering v-else-if='who=="ordering"'></ordering>
    <goods v-else = 'who=="ordering"'></goods>
</div>
</body>
<script>
    var home = {
        template: `
          <div>
          <h1>首页</h1>
          </div>`,
        data() {
            return {}
        },
        methods: {},
    }
    var goods = {
        template: `
          <div>
          <h1>商品页面</h1>
          </div>`,
        data() {
            return {}
        },
        methods: {},
    }
    var ordering = {
        template: `
          <div>
          <h1>订单页面</h1>
          </div>`,
        data() {
            return {}
        },
        methods: {},
    }

    var vue = new Vue({
        el: '#app',
        data: {
            who:'home'
        },
        methods: {},
        components: {home,ordering,goods}

    })
</script>
</html>

动态组件-component


1.component标签的is属性等于组件名字,这里就会显示这个组件
		<conponent :is="who"></conponent>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='./js/vue.js'></script>
</head>
<body>
<div id='app'>
    <button @click = "who='home'">首页</button>
    <button @click = "who='ordering'">订单</button>
    <button @click = "who='goods'">商品</button>
    <hr>
    <conponent :is="who"></conponent>
    component标签的is属性等于组件名字,这里就会显示这个组件
</div>

</body>

<script>
    var home = {
        template: `
          <div>
          <h1>首页</h1>
          </div>`,
        data() {
            return {}
        },
        methods: {},
    }
    var goods = {
        template: `
          <div>
          <h1>商品页面</h1>
          </div>`,
        data() {
            return {}
        },
        methods: {},
    }
    var ordering = {
        template: `
          <div>
          <h1>订单页面</h1>
          </div>`,
        data() {
            return {}
        },
        methods: {},
    }

    var vue = new Vue({
        el: '#app',
        data: {
            who:'home'
        },
        methods: {},
        components: {home,ordering,goods}

    })
</script>
</html>

keep-alive的使用

keep-alive可以让输入框内有的内容一致保持,不会因为切换而重置

<keep-alive>
	<conponent :is="who"></conponent>
</keep-alive>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src='./js/vue.js'></script>
</head>
<body>
<div id='app'>
    <button @click = "who='home'">首页</button>
    <button @click = "who='ordering'">订单</button>
    <button @click = "who='goods'">商品</button>
    <hr>
    <keep-alive>
        <conponent :is="who"></conponent>
    </keep-alive>
    
</div>

</body>

<script>
    var home = {
        template: `
          <div>
          <h1>首页</h1>
          </div>`,
        data() {
            return {}
        },
        methods: {},
    }
    var goods = {
        template: `
          <div>
          <h1>商品页面</h1>
          </div>`,
        data() {
            return {}
        },
        methods: {},
    }
    var ordering = {
        template: `
          <div>
          <h1>订单页面</h1>
          输入搜索内容:<input type="text" v-model="search">
          </div>`,
        data() {
            return {
                search:'',
            }
        },
        methods: {},
    }

    var vue = new Vue({
        el: '#app',
        data: {
            who:'home'
        },
        methods: {},
        components: {home,ordering,goods}

    })
</script>
</html>

插槽-slot

1.一般情况下,编写完1个组件之后,组件的内容都是写死的,需要加数据 只能去组件中修改,扩展性很差;然后就出现了插槽这个概念,只需在组件中添加<slot></slot>,就可以在body的组件标签中添加内容
2.使用步骤:
	1.在组件的html的任意位置,放个标签
        <slot></slot>
	2.后期在父组件使用该组件时
        <lqz>
        放内容
    	</lqz>
	3.放的内容,就会被渲染到slot标签中

基本使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src = './js/vue.js'></script>
</head>
<body>
<div id = 'app'>

    <child>
        <div>
            动态的div
        </div>
    </child>
    <hr>
    <child>
        <div>动态的图片</div>
        <img src="http://5b0988e595225.cdn.sohucs.com/images/20190603/596657996e8f4f6097aeb69392c7813e.jpeg" alt="" height="300px">
    </child>

</div>
</body>
<script>
    var child  = {
        template:`
        <div>
        <h1>这是组件的h1</h1>
        <slot></slot>
        <h2>这是组件的h2</h2>
        </div>
        `,
        data(){return {}},
        methods: {},
    }
    var vue = new Vue({
        el:'#app',
        data:{},
        methods:{},
        components:{child},
    })
</script>
</html>

具名插槽

1.使用步骤:	
	1.组件中可以留多个插槽,命名
        <div>
            <h1>我是一个组件</h1>
            <slot name="middle"></slot>
            <h2>我是组件内部的h2</h2>
            <slot name="footer"></slot>
        </div>
	2.在父组件中使用时,指定某个标签渲染到某个插槽上
        <nana>
            <div slot="footer">
                我是div
            </div>
            <img src="https://scpic.chinaz.net/files/default/imgs/2023-05-12/23659b1edfc0a984.jpg" alt="" slot="middle">
        </nana>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src = './js/vue.js'></script>
</head>
<body>
<div id = 'app'>

    <child>
        <div slot="min">
            动态的div
        </div>
        <hr slot="min">
        <div slot="middle">
            <img src="http://5b0988e595225.cdn.sohucs.com/images/20190603/596657996e8f4f6097aeb69392c7813e.jpeg" alt="" height="300px">
        </div>
    </child>
</div>
</body>
<script>
    var child  = {
        template:`
        <div>
        <h1>这是组件的h1</h1>
        <slot name = 'middle'></slot>
        <h2>这是组件的h2</h2>
        <slot name = 'min'></slot>
        </div>
        `,
        data(){return {}},
        methods: {},
    }
    var vue = new Vue({
        el:'#app',
        data:{},
        methods:{},
        components:{child},
    })
</script>
</html>

vue-cli创建项目

简介

1.单页面应用:spa
	1.以后vue项目就只有一个 xx.html 页面
  2.定义很多组件,不可能都写在 xx.html中
	所以就引出:单文件组件(一个组件一个文件)
	学习文档:https://v2.cn.vuejs.org/v2/guide/single-file-components.html#ad
    
    
2.一个组件中有的东西
		1.html内容:以后html都放在  template标签中
    2.css内容 :以后都放在 style 标签中
    3.js内容:  以后都放在 script标签中
    
3.使用vue-cli创建vue项目才能使用单文件组件
		1.vue脚手架:创建出vue的项目,里面带了很多基础代码
    ps:类似于django-admim命令,可以创建出django项目
        
4.vue-cli脚手架,
    1.vue2中使用创建vue项目的软件必须用vue-cli
    2.vue3中可以使用vue-cli,也可也使用vite创建,vite号称新一代的构建工具
    

      

Vue-cli项目搭建

环境搭建

1.安装nodejs

1.vue-cli是个软件,运行在nodejs环境中,安装nodejs
2.下载地址:
		https://nodejs.p2hp.com/download/
		https://nodejs.org/zh-cn/		
3.安装nodejs       
  类似于python解释器,一路下一步安装--->选择安装位置--->添加到环境变量(以后再任意位置执行node或npm都会找到)
    """
    在cmd中/终端:
    查看node版本:node -v
    """
4.安装完,有两个可执行文件
	node  等同于  python
	npm   等同于  pip
  
  """
    >>>which node    # /usr/local/bin/node
    >>>node -v			 # v18.12.1
    >>>cd /usr/local/bin # 切换路径
    >>>ls  # 查看文件下的文件
  """

2.安装cnpm

1.npm安装第三方模块,速度很慢,淘宝做了个cnpm,以后可以使用cnpm替代npm,会去淘宝镜像站下载,速度快
	npm install -g cnpm --registry=https://registry.npm.taobao.org
  mac:sudo npm install -g cnpm --registry=https://registry.npm.taobao.org
	ps:以后 使用npm安装模块的命令全都换成 cnpm

3 在node环境中装vue-cli(类似于装django)

1.指令
  cnpm install -g @vue/cli
  mac:sudo cnpm install -g @vue/cli
2.装完脚手架,会多出一个命令vue,用来创建vue项目-->等同于djagno-admin命令

创建项目

1.使用脚手架,创建vue项目

vue create 项目名
eg:vue create  myfirstvue

2.选择yes

选择最后一个.png

3.选择Babel,Router,vuex

1.Babel:语法转换
2.Router:页面跳转 路由效果
3.vuex:状态管理器,存储数据的

选择Babel,Router,vuex.png

4.选vue版本

选择vue2版本.png

5.选package.json

选择packge.json.png

5 之前的设置,保存与不保存都可以

使用vue-cli-ui创建

在终端输入:vue ui  
启动出一个服务,直接在浏览器中点点击就可以创建

vue项目目录结构

编写vue项目,使用编辑器--->pycharm
使用pycharm打开vue项目

运行vue项目

1.方式一:命令行中 (一定要注意路径)
	npm run serve
  """
  终端
  cd /Users/na/Documents/myfirstvue
  npm run serve
  """
      
2.方式二:使用pycharm运行  --->点击绿色箭头
	配置一个启动脚本,以后点绿色箭头运行即可

启动vue.png

vue项目的目录结构

myfirstvue-------------------->项目名
	-node_modules--------------->文件夹,放了该项目所有的依赖,很小很多,以后把项目传给别人,这个要删除,别人拿到执行cnpm install安装依赖
	-public--------------------->文件夹
  	--favicon.ico------------->小图标,浏览器上面显示,可以替换
		--index.html-------------->spa,这个html是整个项目的一个html,你不要动
	-src------------------------>以后动这里面的东西,所有代码都在者
    --assets------------------>文件夹,放一些静态资源,图片,js,css
    	---logo.png
    --components-------------->以后小组件写在里面  xx.vue
    	---HelloWorld.vue------->默认提供了一个组件
    --router------------------>装了vueRouter就会有这个文件夹,如果不装就没有,现在不用管
    	---index.js
    --store------------------->装了vuex就会有,不装就没有  
    	---index.js
    --views-------------------->文件夹,里面放了所有页面组件
    	---AboutView.vue--------->关于组件
      ---HomeView.vue---------->首页组件 
    --App.vue------------------>根组件
    --main.js------------------>项目启动的入口文件,核心
	-.gitignore------------------>git相关,后面学了就会了
	-babel.config.js------------->babel的配置,不用管
	-jsconfig.json
	-package.json---------------->重要,存放依赖
	-package-lock.json----------->锁定文件
	-README.md------------------->项目介绍
	-vue.config.js--------------->vue项目的配置文件
  
  """
  总结:以后只需要关注src文件夹下的文件即可
  """

es6导入导出、导入语法

导出语法

1.在项目中:创建包  eg:ln   ps:在views文件下
2.在包下面创建文件夹 eg:package.js
3.在文件中写js代码
	eg:
    var name = 'nana'
    function add(a,b){
        return a+b
    }
    
4.导出
	4.1 默认导出对象
  eg:
  	export default {
    add:add,
    name:name}
    或:
    export default {
        add,
        name
    }
    
  4.2 命名导出,导出了两个变量
  	export const name='cx'
		export const add=(a,b)=>a+b

导入语法

1.默认导出的导入 
	1.在任意的js中导入:import 起个名字  from '路径'
		import ln from './ln/package'
  2.使用导入的包:起个名字.导出的字段
  	eg:
    var res = ln.add(1,2)
    console.log(res)
    console.log(ln.name)
    ps:样式在main.py中写
    
2.命名导出的导入
	1.在任意的js中
    import {name,add}  from './lqz/package'
  2.直接用即可
  eg:
    import {name,add} from './ln/package'
    console.log(add(2,3))
    console.log(name)

vue项目编写规范

修改项目

App.vue

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

HomeView.vue

<template>
  <div class="home">
  </div>
</template>

<script>
export default {
  name: 'HomeView',
}
</script>

AboutView.vue

<template>
  <div class="about">
    <h1>This is an about page</h1>
  </div>
</template>

作业

查询所有图书按价格排序的作业,写在HomeView.vue



<template>
    <div class="home">
    <button @click="handleClick">降序或升序</button>
        <ul v-for="book in book_list">
            <li>图书id:{{book.id}}</li>
            <li>图书名:{{book.name}}</li>
            <li>图书价格:{{book.price}}</li>
        </ul>
    </div>
</template>

<script>

import axios from 'axios'
export default {
    name: 'HomeView',
    methods: {
        handleClick(){
            if (this.ordering){
                //升序
             axios.get('http://127.0.0.1:8000/books/?ordering=price').then(res=>{
            console.log(res.data)
            this.book_list=res.data.data
        })
            }else {
                //降序
                axios.get('http://127.0.0.1:8000/books/?ordering=-price').then(res=>{
            console.log(res.data)
            this.book_list=res.data.data
        })
            }

        this.ordering =!this.ordering
        }
    },
    data(){
      return {
          book_list:[],
          ordering:true
      }
    },
    created() {
        axios.get('http://127.0.0.1:8000/books/').then(res=>{
            console.log(res.data)
            this.book_list=res.data.data
        })
    }
}
</script>
<style>
h1 {
    font-size: 80px;
}
</style>

补充

1.在vue项目中使用ajax获取数据:
  命令行:cnpm install -S axios

2.Vue.js中使用axios发送GET请求,你可以在HomeView.vue组件中的<script>标签中导入axios。通常,你可以将导入语句放在文件的顶部:
    <script>
  import axios from 'axios';

  export default {
    // 组件的其余部分
  }
  </script>