• vue3.0 学习使用记录


    vue学习

    在最近的一次项目中,前端js框架里使用了vue。vue的编程思想比较新颖,用起来也感觉高效便捷。由于个人原因,做完这个项目之后可能就接触不到前端的内容了,所以记录这个项目中对vue的学习和理解。对自己的要求是可以不记得具体的技术,但是要记住这个框架的思想。

    vue简介

    vue是一个JavaScript框架,最大的特点是响应式
    响应式原理:意思就是在改变数据的时候,视图会跟着更新
    对比jquery来说,jquery是通过语法操作html中的标签,从而改变标签的属性,值等。而vue是需要改变的html标签绑定一个变量,当变量发生变化时html中的标签的值也发生变化。

    vue3.0安装

    1. 安装node

    sudo tar xf node-v14.16.1-linux-x64.tar.xz -C /opt
    
    cd /opt/node-v14.16.1-linux-x64/bin
    sudo ln -s /opt/node-v14.16.1-linux-x64/bin/node /usr/local/bin/node
    sudo ln -s /opt/node-v14.16.1-linux-x64/bin/npm /usr/local/bin/npm
    
    # 验证版本
    node -v
    npm -v
    

    2. 装淘宝镜像

    npm install -g cnpm --registry=https://registry.npm.taobao.org
    sudo ln -s /opt/node-v14.16.1-linux-x64/bin/cnpm /usr/local/bin/cnpm
    
    cnpm -v
    

    3. vue环境安装

    cnpm -g vue @vue/cli
    sudo ln -s /opt/node-v14.16.1-linux-x64/bin/vue /usr/local/bin/vue
    
    vue -V
    

    vue3.0要求4.5以上的版本

    4. 创建新项目

    vue create todolist
    

    启动项目

    访问页面

    vue 项目架构

    一个新建的vue项目架构如下:

    assets: 存放静态资源、图标、图片
    components:存放一般组件,公共组件,通用组件
    router:配置路由。vue中实现页面跳转需要定义的路由
    sotre: 配置状态管理
    views:vue 主要业务实现的位置
    App.vue:页面的入口文件,通常是入口页面。上面的首页就是该文件中的。

    组件

    组件是vue功能的集合。可以把每一个.vue文件看成一个组件,包括App.vue也是一个组件,一个关于主页面的组件。组件的结构由三部分组成:

    1. template
    2. script
    3. style
    <template>
        
    </template>
    
    
    <script>
        
    </script>
    
    
    <style scoped lang="scss">
        
    </style>
    

    组件结构

    一个组件包括很多内容,大体上可以分为:

    1. defineComponent 引入
    2. 子组件引入(可选)
    3. 组件定义
    • 组件名称
    • 接收父组件的数据(可选)
    • 定义子组件(可选)
    • setup 定义变量和函数

    setup中定义变量和函数,最后都要通过return返回,只有return中返回的变量才能被页面上响应。

    //------------------------数据的展示------------------------
    <template>
      
    </template>
        
    
    //--------------------------数据的定义和返回---------------------
    <script>
    
    // 所有的组件都需要从vue中定义
    import {defineComponent} from 'vue'
    import NavHeader from '@/components/navHeader/NavHeader'
    
    // 调用defineComponent中的组件
    export default defineComponent({
        name: 'Home', // 组件名称
        
        // 接收父组件的数据
        props: {
    
        },
        // 定义子组件
        components:{
           
        },
        setup(props, ctx) {
            
            // 数字
            let num = ref(10)
            
            return {
                num
            }
        }
    })
    
    </script>
    
    
    <style scoped lang='scss'>    
    </style>
    

    数据结构

    vue中常见的数据结构包括:

    • 数字
    • 字符串
    • 字典
    • 数组

    ref 用来定义响应式变量,只可以定义单个变量
    reactive 用来打包定义变量,可以定义多个变量

    数据定义
    
    //------------------------数据的展示------------------------
    <template>
        <div>
            <nav-header></nav-header>
            <nav-main></nav-main>
            <nav-footer></nav-footer>
            {{ data.num }}
            {{ data.name }}
            {{ data.arr.slice(0,2) }}
            {{ data.obj }}
        </div>
    </template>
        
    
    //--------------------------数据的定义和返回---------------------
    <script>
    
    // 所有的组件都需要从vue中定义
    import {defineComponent, ref, reactive} from 'vue'
    
    
    // 调用defineComponent中的组件
    export default defineComponent({
        name: 'Home', // 组件名称
        
        // 接收父组件的数据
        props: {
    
        },
        // 定义子组件
        components:{
            NavHeader,
            NavMain,
            NavFooter
        },
        setup(props, ctx) {
            
            // 数字
            let num = ref(10)
            
            // 字符串
            let name = ref('jack')
           
            // 数组  
            let arr = ref(['a', 'b', 'c', 'd'])
            
            // 字典
            let obj = ref({age: 20})
    
            // reactive 方法 
            let data = reactive({
                name: 'jack',
                age: 20,
                ojb: {
                    price: 20
                },
                arr: ['a', 'b', 'c', 'd']
            })
            return {
                data
            }
        }
    })
    
    </script>
    
    
    
    <style scoped lang='scss'>    
    </style>
    

    在实际的编程过程中,似乎不需要用关键字refreactive。如在未来网络学院的开发过程中,一个vue文件定义的相应式变量如下:

     return {
            tableConfig: {
              config: tableConfigBase(),
              tableData: [],
              selectedRows: [],
            },
            createModal: {
              visible: false
            },
            createForm: {
              dialog_title: '添加讲师',
              name: '',
              title: '',
              profile: '',
              img: [],
            },
            searchForm: {
              keywords: ''
            },
            createRules: {
              name: [
                { required: true, message: '请输入名称', trigger: 'change' },
                { min: 2, max: 20, message: '长度在 2~20 个字符内', trigger: 'change' },
                {validator: nameUniqueAcq, trigger: 'blur'},
                {validator: urlAcq, trigger: 'blur'},
              ],
              title: [
                { required: true, message:'请输入头衔', trigger: 'change' },
                { min: 1, max: 500, message: '长度在 2~500 个字符内', trigger: 'change' },
              ],
              profile: [
                { required: false, message: '长度在 200 个字符内', trigger: 'change' },
              ],
              img: [
                { required: true, message: '请上传图片', trigger: 'change'}
              ],
            },
            pager:{},
            disabledDel: 'disabled',
            disableDis: 'disabled',
            disableEn: 'disabled',
          }
    

    vue基础语法

    指令

    Vue.js的指令是以v-开头的,它们作用于HTML元素,指令提供了一些特殊的特性,将指令绑定在元素上时,指令会为绑定的目标元素添加一些特殊的行为,我们可以将指令看作特殊的HTML特性(attribute)。

    作用
    指令的作用是当表达式的值改变时,相应地将某些行为应用到 DOM 上。

    v-if
    v-if可以实现条件渲染,Vue会根据表达式的值的真假条件来渲染元素。

    <a v-if="ok">yes</a>
    

    如果属性值ok为true,则显示。否则,不会渲染这个元素。

    v-else
    v-else是搭配v-if使用的,它必须紧跟在v-if或者v-else-if后面,否则不起作用。

    <div>ok的值为:{{ ok }}</div>
    <div v-if='ok'>如果值为true显示</div>
    <div v-else>如果值为false显示</div>
    

    v-for
    用v-for指令根据遍历数组来进行渲染

    两种渲染方式

    <div v-for="(item,index) in items"></div>   //使用in,index是一个可选参数,表示当前项的索引
    <div v-for="item of items"></div>   //使用of
    
     let list = ref([11,23,34,45,56])
     
    <div v-for='(index, item) in list'>
        <span>{{ item }}--{{ index }}</span>
    </div>
    

    v-model
    这个指令用于在表单上创建双向数据绑定。限制在<input><select><textarea>components中使用

     <input v-model='input_value'  @keydown.enter="enter"/>
    
    let input_value = ref('')
    let enter = () => {
        console.log(input_value.value)
    }
    

    ![image_1f5i6uiup1irig8hr8pdd4fr2q.png-21.3kB][15]

    <1> lazy 默认情况下,v-model同步输入框的值和数据。可以通过这个修饰符,转变为在change事件再同步。

    <input v-model.lazy="msg">
    

    <2> number 自动将用户的输入值转化为数值类型

    <input v-model.number="msg">
    

    <3> trim:自动过滤用户输入的首尾空格

    <input v-model.trim="msg">
    

    v-on
    v-on主要用来监听dom事件,以便执行一些代码块。表达式可以是一个方法名。
    简写为:@

    <button @click='change_ok'>点击按钮</button>
    
    let change_ok = () => {
        console.log('00000')
        ok.value = !ok.value
    }
    

    <!-- 阻止单击事件继续传播 -->
    <a v-on:click.stop="doThis"></a>
    
    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>
    
    <!-- 修饰符可以串联 -->
    <a v-on:click.stop.prevent="doThat"></a>
    
    <!-- 只有修饰符 -->
    <form v-on:submit.prevent></form>
    
    <!-- 添加事件监听器时使用事件捕获模式 -->
    <!-- 即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理 -->
    <div v-on:click.capture="doThis">...</div>
    
    <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
    <!-- 即事件不是从内部元素触发的 -->
    <div v-on:click.self="doThat">...</div>
    
    <!-- 点击事件将只会触发一次 -->
    <a v-on:click.once="doThis"></a>
    
    <!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
    <!-- 而不会等待 `onScroll` 完成  -->
    <!-- 这其中包含 `event.preventDefault()` 的情况 -->
    <div v-on:scroll.passive="onScroll">...</div>
    

    v-bind
    v-bind用来动态的绑定一个或者多个特性。没有参数时,可以绑定到一个包含键值对的对象。常用于动态绑定class和style。以及href等。
    简写为一个冒号

     <a v-bind:href='herf'>百度</a>
    

    <img :src='img_url' alt='leishen'>
    
    let img_url = ref('https://image-1300284638.cos.ap-nanjing.myqcloud.com/leishen.jpeg')
    

    常用的v-bind标签

    • v-bind:style
    • v-bind:title
    • v-bind:src

    v-html
    双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML ,你需要使用 v-html 指令:

    <div v-html="rawHtml"></div>
    

    这个 div 的内容将会被替换成为属性值 rawHtml,直接作为 HTML——会忽略解析属性值中的数据绑定。

    动作监听

    动作监听的流程:

    1. 标签上定义监听函数 @click='监听函数名'
    2. setup中实现监听函数
    3. setup中return监听函数
    <template>
        <!-- <one></one> -->
        <button @click='alert_action'>点击事件</button>
    </template>
    
    
    <script>
        import {defineComponent, ref, reactive, computed} from 'vue'
        import one from '@/components/one/One'
    
        export default defineComponent({
            name: 'Main', // 组件名称
            
            components:{
                 one
            },
            setup() {
               
               let alert_action = () => {
                    alert('你点击了我')
               }
    
               return {
                    alert_action
               }
            }
    
        })
    </script>
    
    
    <style scoped lang="scss">
        
    </style>
    

    vue全局使用

    引用组件

    子组件可以定义在components中,而views中往往定义父组件。在父组件中使用子组件的流程为:

    1. 子组件定义
    
    <template>
        <div>这是子组件</div>
    </template>
    
    
    <script>
        import {defineComponent, ref, reactive, computed} from 'vue'
        export default defineComponent({
            name: 'One', // 组件名称
    
            setup() {
    
            }
    
        })
    </script>
    
    
    <style scoped lang="scss">
        
    </style>
    
    1. 父组件定义
    
    <template>
        <one></one>
    </template>
    
    
    <script>
        import {defineComponent, ref, reactive, computed} from 'vue'
        
        // 从components中的one文件夹下的One.vue中引入
        import one from '@/components/one/One'
    
        export default defineComponent({
            name: 'Main', // 组件名称
            
            // 组件本地化
            components:{
                 one
            },
            setup() {
    
            }
    
        })
    </script>
    
    
    <style scoped lang="scss">
        
    </style>
    

    父子组件中传递数据

    1. 父组件传递给子组件

    在父组件使用的子组件中加入参数传递:num='num'

    
    <template>
        <one :num='num'></one>
    </template>
    
    
    <script>
        import {defineComponent, ref, reactive, computed} from 'vue'
        import one from '@/components/one/One'
    
        export default defineComponent({
            name: 'Main', // 组件名称
            
            components:{
                 one
            },
            setup() {
               
               let alert_action = () => {
                    alert('你点击了我')
               }
    
               let num = ref(100)
    
               return {
                    alert_action,
                    num
               }
            }
    
        })
    </script>
    
    
    <style scoped lang="scss">
        
    </style>
    
    

    子组件中props用来接收父组件的传参,定义好变量,然后直接使用

    
    <template>
        <div>这是子组件</div>
        <div>父组件传递过来的是: {{ num }}</div>
    </template>
    
    
    <script>
        import {defineComponent, ref, reactive, computed} from 'vue'
        export default defineComponent({
            name: 'One', // 组件名称
            
            props: {
                num:{
                    type: Number
                }
            },
            setup(props) {
                 
            }
    
        })
    </script>
    
    
    <style scoped lang="scss">
        
    </style>
    

    1. 子组件传递给父组件

    子组件传值给父组件叫事件分发。通过ctx.emit分发事件

    1. 子组件
    <template>
        <div>这是子组件</div>
        <div>父组件传递过来的是: {{ num }}</div>
        <button @click='send'>点击传递参数</button>
    </template>
    
    
    <script>
        import {defineComponent, ref, reactive, computed} from 'vue'
        export default defineComponent({
            name: 'One', // 组件名称
            
            props: {
                num:{
                    type: Number
                }
            },
            setup(props, ctx) {
                let send = () => {
                     // 使用事件分发
                     ctx.emit("send", 200)   
                }
                return {
                    send
                }
            }
    
        })
    </script>
    
    
    <style scoped lang="scss">
        
    </style>
    
    

    父组件

    
    <template>
        // 父组件接收send事件,将其在send_father函数中处理
        <one :num='num' @send='send_father'></one>
        <div>父组件收到的子组件的传参: {{ recv_value }}</div>
    </template>
    
    <script>
        import {defineComponent, ref, reactive, computed} from 'vue'
        import one from '@/components/one/One'
    
        export default defineComponent({
            name: 'Main', // 组件名称
            
            components:{
                 one
            },
            setup() {
               
               let alert_action = () => {
                    alert('你点击了我')
               }
    
               let num = ref(100)
               
               let recv_value = ref(0)
               let send_father = (val) => {
                   recv_value.value = val
               }
    
               return {
                    alert_action,
                    num,
                    send_father,
                    recv_value
               }
            }
    
        })
    </script>
    
    
    <style scoped lang="scss">
        
    </style>
    
    

    全局共享变量之状态管理

    在store中的index.js中可以定义全局使用的变量和方法。全局使用指的是所有组件可以修改,共享使用。

    使用这些变量或者函数的方法是:

    import {useStore} from 'vuex'
    
    setup(props, ctx) {
            
        let  store = useStore()
        //
        store.commit('addTodo',{
            title: value.value,
            complete: false
        }
    
    

    路由

    在router文件夹下存放着vue的路由信息

    路由就是页面的静态路由。

    根路由:每一个vue项目都有一个根路由,该路由的主要作用是页面的默认路由。

     {
        path: '/',
        name: 'Start',
        component: Start
      },
    

    path: 路由路径
    name:路由的名字
    component: 该路由对应的组件。该组件必须先引入进来,并且是只需要显示引入的。其他组件由于不需要立刻显示,所以使用懒加载,即不立即加载到vue项目中。

    其他路由的加载

    {
        path: '/home',
        name: 'Home',
        component: () => import('../views/Home.vue')
      },
    

    路由的使用

    import {useRouter} from 'vue-router'
    
     setup(props, ctx) {
        // router是全局路由对象
        let router = useRouter()
        let start = () =>{
                 // 使用push的方式,跳转路由
                 router.push({
                    // 路由的目的地可以用name:模块
                    name:'Home',
                    // 也可以是path:路径。两者二选一
                    path: '/home'
                })
            }
     }
    

    路由的传参

    路由的传参有两种方式,分别是

    1. query 类似于get,显示传参,地址栏可以看到参数,刷新保存参数
    2. params 类似于post,地址栏看不到参数,刷新不保存参数

    query

     setup(props, ctx) {
        // router是全局路由对象
        let router = useRouter()
        let start = () =>{
                 // 使用push的方式,跳转路由
                 router.push({
                    name:'Home',
                    query:{
                        name: name.value,
                        num: num.value,
                    }
                    
                })
            }
     }
    

    使用

    import {useRouter, useRoute} from 'vue-router'
    
    // route是当前路由对象
    let route = useRoute()
    
    console.log(route.query)
    

    有一点需要注意数字类型的参数会变成字符串类型

    params
    params传参只能用name来路由

    let start = () =>{
             router.push({
                name:'Home',
                params:
                    {
                     name: name.value,
                     num: num.value,
                    }
            })
            }
    

    接收参数:

    import {useRouter, useRoute} from 'vue-router'
    
    // route是当前路由对象
    let route = useRoute()
    
    console.log(route.params)
    

    插槽

    定义
    插槽就是子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的标签。

    https://www.cnblogs.com/mandy-dyf/p/11528505.html
    

    vue2 和vue3的区别

    建立数据 data
    这里就是Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)

    选项类型
    旧的选项型API在代码里分割了不同的属性(properties):data,computed属性,methods
    合成类型
    新的合成型API能让我们用方法(function)来分割,相比于旧的API使用属性来分组,这样代码会更加简便和整洁。

    vue2

    export default {
      props: {
        title: String
      },
      data () {
        return {
          username: '',
          password: ''
        }
      },
      methods: {
        login () {
          // 登陆方法
        }
      }
    }
    

    Vue2 的选项型API是把methods分割到独立的属性区域的。我们可以直接在这个属性里面添加方法来处理各种前端逻辑。

    vue3

    export default {
      props: {
        title: String
      },
      setup () {
        const state = reactive({
          username: '',
          password: ''
        })
    
        const login = () => {
          // 登陆方法
        }
        return { 
          login,
          state
        }
      }
    }
    

    Vue3 的合成型API里面的setup()方法也是可以用来操控methods的。创建声名方法其实和声名数据状态是一样的。— 我们需要先声名一个方法然后在setup()方法中返回(return), 这样我们的组件内就可以调用这个方法了。

    项目代码结构

    所有的vue代码都写在views当中
    公共组件存放在components中
    有关网络请求的axios都存放在network中
    页面跳转路由存放在router中

    vue在实际项目中的使用技巧

    vue与后端交互

    vue通过 axios 与后端交互。通过引入axios中的各种方法,完成网络请求

    import { fetch, post, del, postForm } from '../base/axios'
    
    const URL = {
      listUrl: '/page/list/',
      createUrl: '/page/create/',
      delUrl: '/page/delete/',
      disableUrl: '/page/disable/',
      enableUrl: '/page/enable/',
      pageStateChange: '/page/page_state_change/',
      getFiles: '/page/get_files/'
    }
    
    export function pageList (data) {
      return fetch(URL.listUrl, data)
    }
    
    export function pageCreate(form) {
        return postForm(URL.createUrl, form)
    }
    
    export function pageDelete(page_id) {
        return del(URL.delUrl + page_id + '/')
    }
    
    export function pageDisable(data) {
        return fetch(URL.disableUrl, data)
    }
    
    export function pageEnable(data) {
      return fetch(URL.enableUrl, data)
    }
    
    export function pageStateChange(data) {
      return fetch(URL.pageStateChange, data)
    }
    
    export function pageGetFiles(page_id) {
        return fetch(URL.getFiles + page_id + '/')
    }
    

    普通post请求:

    export function post (url, data = {}) {
      return new Promise((resolve, reject) => {
      // var qs = require('querystring')
        axios.create({
          headers: {'X-CSRFToken': getCookie('csrftoken'), 'Content-Type': 'application/x-www-form-urlencoded'},
        }).post(url, data).then(response => {
          resolve(response.data)
        }, err => {
          reject(err)
        })
      })
    }
    

    form-data的请求

    export function postForm (url, data= {}) {
      return new Promise((resolve, reject) => {
        axios.create({
          withCredentials: true,
          headers: {'X-CSRFToken': getCookie('csrftoken'), 'Content-Type':  "multipart/form-data"},
        }).post(url, data).then(response => {
          resolve(response.data)
        }, err => {
          reject(err)
        })
      })
    }
    

    在vue文件中的网络请求为:

    import { pageList, pageDelete, pageDisable, pageEnable, pageCreate, pageStateChange, pageGetFiles } from 'api/page/index'
    
    pageList(data).then((res =>{
                this.tableConfig.tableData = res.data;
                this.pager.total = res.total
            })).catch(err => {
              this.$alert(`${ err }`, '提示', {
                confirmButtonText: '确定',
              });
          });
    

    vue 导入组件和方法

    vue使用的过程中需要导入组件或者方法,方法如axios请求。导入的语法是:

    • 导入组件需要使用大括号
    • 导入方法需要用大括号包裹
     import { useRouter } from 'vue-router'
     import { tableConfigBase } from 'utils/common.js'
     import { pageList, pageDelete, pageDisable, pageEnable, pageCreate, pageStateChange, pageGetFiles } from 'api/page/index'
     import {  showConfirmMessageBox, showMessage } from 'api/base/message'
     import UploadFile from 'components/common/UploadFile'
     import Pagination  from 'components/common/Pagination'
    

    导入组件是从别的文件中导入组件,除需要使用大括号之外,还需要本地引入

     export default {
        components: {
          UploadFile,
          Pagination
        },
        .....
    }
    

    导入方法指的是从js文件中能够导入一个函数。如 showConfirmMessageBox,就是:

    export function showConfirmMessageBox (message) {
      return ElMessageBox.confirm(message, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
        center: true
      })
    }
    

    vue属于js的一个库,理所当然可以使用js。想要引用一个js,需要js的函数export

    vue异步变同步的方法

    axios是异步请求,如果想要将异步变成同步,使用asyncawait两个关键字即可。
    async 修饰 vue函数
    await 修饰 axios请求方法

     async editRow(index, row){
            this.createForm.name = row.name
            this.createForm.desc = row.desc
            this.createForm.page_url = row.page_url
            this.createForm.edit = true
            this.createForm.page_id = row.id
            await pageGetFiles(row.id).then((res => {
              if (res.result == 0) {
                for (var i = 0; i < res.page_files.length; i++) {
                  this.createForm.file.push({'page_file_id': res.page_files[i].id, 'name': res.page_files[i].name})
                }
              }
            }))
            this.createModal.visible = true
          },
    

    vue中formdata的使用

    formdata 用于有静态资源从vue传输到django中,如图片和文件等。使用如下:
    创建: var data = new FormData()
    添加:

        data.append('name', this.createForm.name)
        data.append('desc', this.createForm.desc)
        data.append('page_url', this.createForm.page_url)
        data.append('edit', this.createForm.edit)
        data.append('page_id', this.createForm.page_id)
    

    特别注意,如果添加文件也是使用中格式
    data.append('new_files', file.raw)
    如果添加多个文件,那么直接用同一个key,会被打包成列表
    取值:data.get(key)
    如果value是一个数组,取值方法: data.getAll(key)

    vue代码

     var data = new FormData();
    data.append('name', this.createForm.name)
    data.append('desc', this.createForm.desc)
    data.append('page_url', this.createForm.page_url)
    data.append('edit', this.createForm.edit)
    data.append('page_id', this.createForm.page_id)
    this.createForm.file.forEach((file) => {
      if (file.raw) {
        data.append('new_files', file.raw)
      }else{
        data.append('old_files', file.page_file_id)
      }
    })
    
    export function postForm (url, data= {}) {
      return new Promise((resolve, reject) => {
        axios.create({
          withCredentials: true,
          headers: {'X-CSRFToken': getCookie('csrftoken'), 'Content-Type':  "multipart/form-data"},
        }).post(url, data).then(response => {
          resolve(response.data)
        }, err => {
          reject(err)
        })
      })
    }
    
    export function pageCreate(form) {
        return postForm(URL.createUrl, form)
    }
    
    pageCreate(data)
    

    django的接收:

    # 接收到formdata的出文件之外的数据
    data = request.POST
    # 接收文件,getlist是接收多个文件  get是接收单个文件
    new_files = request.FILES.getlist('new_files')
    

    vue校验

    在input输入框中需要一些校验,以下面的demo为例

     <el-dialog title="添加页面" v-model="createModal.visible" width="800px" :before-close="closeDialog">
          <div class="demo-dialog">
            <el-form :model="createForm" :rules="createRules" ref="createForm" label-width="100px">
              <el-form-item label="名称" prop="name">
                <el-input v-model="createForm.name"></el-input>
              </el-form-item>
              <el-form-item label="描述" prop="desc">
                <el-input v-model="createForm.desc"></el-input>
              </el-form-item>
              <el-form-item label="网址" prop="page_url">
                <el-col>
                  <el-input v-model="createForm.page_url" >
                     <template #prepend>page/</template>
                  </el-input>
                </el-col>
              </el-form-item>
              <el-form-item label="页面文件" prop="file">
                <upload-file :allowed-type="['html']"
                             v-model:file-list="createForm.file"
                             :multiple="true">支持上传单个或多个html文件
                </upload-file>
              </el-form-item>
            </el-form>
          </div>
          <template #footer>
              <span class="dialog-footer">
                <el-button @click="submitCancel">取 消</el-button>
                <el-button type="primary" @click="submitForm('createForm')">确 定</el-button>
              </span>
          </template>
        </el-dialog>
    

    校验规则

    createRules: {
      position: [
        { required: true, message: '请选择位置', trigger: 'change' },
      ],
      name: [
        { required: true, message: '请输入认证名称', trigger: 'change' },
        { min: 2, max: 50, message: '长度在 2~50 个字符内', trigger: 'change' },
      ],
      desc: [
        { required: false, max: 200, message: '长度在 200 个字符内', trigger: 'change' },
      ],
      page_url: [
        { required: true, message: '请填写链接', trigger: 'change' },
        { min: 1, max: 50, message: '长度在 1~50 个字符内', trigger: 'change' },
         {validator: urlAcq, trigger: 'change'}
      ],
      file: [
        { required: true, message: '请上传html文件', trigger: 'change' },
        {validator: indexHtmlAcq, trigger: 'change'}
      ]
    },
    

    自定义校验 上传文件包含index.html

    const indexHtmlAcq = (rule, files, callback) => {
            let index_html_num = 0
            files.forEach((file) =>{
                if(file.name == 'index.html'){
                     index_html_num = index_html_num + 1
                }
            })
            if(index_html_num == 0){
                callback(new Error('必须添加一个index.html文件'))
            }else if(index_html_num > 1){
                 callback(new Error('只能添加一个index.html文件'))
            }
            return callback()
          }
    

    自定义校验 输入框中只允许输入数字字母-_

          const urlAcq = (rule, str, callback) =>{
            const reg =/^[-_a-zA-Z0-9]+$/;
            if(!reg.test(str)){
                callback(new Error('url中包含特殊字符'))
            }
            return callback()
          }
    

    清空校验的红色提示

    this.$nextTick(() => {
              this.$refs["createForm"].clearValidate()
            })
    
  • 相关阅读:
    关于button去掉自带阴影效果的方法
    关于含RecyclerView的fragment来回切换时页面自动滑动到底部的解决方法
    关于简单的安卓APP状态栏设置(类似沉浸式状态栏)
    关于TabLayout与ViewPager在Fragment中嵌套Fragment使用或配合使用的思考
    关于安卓一些报错的解决方法(随时更新)
    react与微信小程序
    微信小程序js学习心得体会
    网络流学习笔记
    git 错误 RPC
    LeetCode 翻转链表
  • 原文地址:https://www.cnblogs.com/goldsunshine/p/14892580.html
Copyright © 2020-2023  润新知