Vue基础(二)

计算属性与监视姓名案例

插值语法实现

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>姓名案例</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
        姓:<input type="text" v-model="firstName">
        名:<input type="text" v-model="lastName">
        姓名:<span>{{firstName}}-{{lastName}}</span>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    new Vue({
       el:'#root',
       data:{
        firstName:'zhang',
        lastName:'san'
       } 
    })
</script>
</html>

methods实现

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>姓名案例</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
        姓:<input type="text" v-model="firstName">
        名:<input type="text" v-model="lastName">
        姓名:<span>{{fullName()}}</span>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    new Vue({
       el:'#root',
       data:{
        firstName:'zhang',
        lastName:'san'
       },
       methods:{
        fullName(){
            return this.firstName+'-'+this.lastName
        }
       }
    })
</script>
</html>

计算属性

定义

要用的属性不存在,要通过已有的属性计算得来

原理

底层借助了Object.defineProperty方法提供的getter和setter

执行
  1. 初次读取时会执行一次
  2. 当依赖的数据发生改变时会再次被调用
html 复制代码
<body>
    <div id="root">
        姓:<input type="text" v-model="firstName">
        名:<input type="text" v-model="lastName">
        姓名:<span>{{fullName}}</span>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    Vue.config.devtools = true;
    const vm = new Vue({
       el:'#root',
      // 属性
       data:{
        firstName:'zhang',
        lastName:'san'
       },
    // 计算属性
    // 只调用一次,剩下的根据缓存
       computed:{
        fullName:{
            // get什么时候调用
            // 1.初次读取fullName时
            // 2.依赖的数据(firstName,lastName)发生变化时
            get(){
                console.log('get方法被调用了');
                return this.firstName+'-'+this.lastName
            },
            set(value){
                const arr = value.split('-')
                this.firstName=arr[0]
                this.lastName=arr[1]
            }
        }
       }
    })
</script>
优势

与methods实现相比,内部有缓存机制(复用),效率更高,调试方便

其他
  1. 计算属性最终会出现在vm上,直接读取使用即可
  2. 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变
简写
javascript 复制代码
// 简写
fullName(){
  return this.firstName+'-'+this.lastName
}

监视属性watch

  1. 当监视属性变化时,回调函数自动调用,进行相关操作
  2. 监视的属性必须存在,才能进行监视
  3. 监视的两种写法:
    (1)new Vue时传入watch配置
    (2)通过vm.$watch监视
简写


实例
html 复制代码
<script type="text/javascript">
    Vue.config.productionTip = false;
    Vue.config.devtools = true;
    new Vue({
        el:'#root',
        data:{
            isHot:true
        },
        computed:{
            info(){
                return this.isHot?'炎热':'凉爽'
            }
        },
        methods:{
            changeWeather(){
                this.isHot = !this.isHot
            }
            
        },
        // 配置监听
        watch:{
                isHot:{
                    // 初始化时让handler执行一次
                    // immediate:true,
                    // 当isHot发生变化时执行handler
                    handler(newValue,oldValue){
                         console.log(newValue,oldValue)
                    }
                }
        }
    })
</script>
html 复制代码
<script type="text/javascript">
    Vue.config.productionTip = false;
    Vue.config.devtools = true;
    const vm =new Vue({
        el:'#root',
        data:{
            isHot:true
        },
        computed:{
            info(){
                return this.isHot?'炎热':'凉爽'
            }
        },
        methods:{
            changeWeather(){
                this.isHot = !this.isHot
            }
            
        },
        // 配置监听
        // watch:{
        //         isHot:{
                    // // 初始化时让handler执行一次
                    // // immediate:true,
                    // // 当isHot发生变化时执行handler
                    // handler(newValue,oldValue){
                    //      console.log(newValue,oldValue)
                    // }
        //         }
        // }
    })
    vm.$watch('isHot',{
         // 初始化时让handler执行一次
         // immediate:true,
         // 当isHot发生变化时执行handler
         handler(newValue,oldValue){
            console.log(newValue,oldValue)
        }
    })
</script>
深度监视
  1. Vue中的watch默认不检测对象内部值的改变(一层)
  2. 配置deep:true;可以监测对象内布值改变(多层)
其他
  1. Vue自身可以监测对象内部值得改变,但Vue提供的watch默认不可以
  2. 使用watch时根据数据的具体结构,决定是否采用深度监视

watch和computed

区别

  1. computed完成的功能,watch都能完成
  2. watch能完成的功能,computed不一定能完成

原则

  1. 所被Vue管理的函数,最好写成普通函数,这样this指向才是vm或组件实例对象
  2. 所有不被vue管理的函数(定时器的回调函数,ajax的回调函数等),最好写成回调函数,这样this的指向才是vm或组件实例对象

绑定样式

绑定class样式

写法:class="xxx" xxx可以是字符串,对象,数组

字符串写法适用于:类名不确定,要动态获取

对象写法适用于:要绑定多个样式,个数确定,名字也不确定

数组写法适用于:要绑定多个样式,个数确定,名字也确定

绑定style样式

:style="{fontSize:xxx}"其中xxx是动态值

:style="a,b",其中a,b是样式对象

条件渲染

v-if

适用于:切换频率较低的场景

特点:不展示的DOM元素直接被移除

注意:v-if可以和v-else-if,v-else一起使用,但要求结构不能被打断

html 复制代码
 <h2 v-if="false">欢迎来到{{name}}</h2>
写法
  1. v-if="表达式"
  2. v-else-if="表达式"
  3. v-else="表达式"
html 复制代码
        <div v-if="num === 1">As</div>
        <div v-else-if="num === 2">Bs</div>
        <div v-else-if="num === 3">Cs</div>

v-show

适用于:切换频率较高的场景

特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉

html 复制代码
<div id="root">
        <h2 v-show="false">欢迎来到{{name}}</h2>
</div>
写法

v-show="表达式"

其他

使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到

template不显示在页面上,只能配合v-if使用

列表渲染

v-for指令

  1. 用于列表展示数据
  2. 语法:v-for="(item,index) in xxx" :key="yyy"
  3. 可遍历:数组,对象,字符串(用的很少),指定次数(用的很少)
html 复制代码
<body>
    <div id="root">
        <!-- 遍历数组 -->
        <ul>
            <li v-for="(p,index) in persons" :key="index">
                {{p.id}}-{{p.name}}-{{p.age}}
            </li>
        </ul>
        <!-- 遍历对象 -->
         <ul>
            <li v-for="(value,key) of car" :key="key">
                {{key}}-{{value}}
            </li>
         </ul>
         <!-- 遍历字符串 -->
         <ul>
            <li v-for="(char,index) of str" :key="index">
                {{char}}-{{index}}
            </li>
         </ul>
         <!-- 遍历指定次数 -->
         <ul>
            <li v-for="(number,index) of 5" :key="index">
                {{index}}-{{number}}
            </li>
         </ul>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    new Vue({
        el:'#root',
        data:{
            persons:[
                {id:'001',name:'aaa',age:18},
                {id:'002',name:'bbb',age:19},
                {id:'003',name:'ccc',age:20}
            ],
            car:{
                name:'奔驰',
                price:'100000',
                color:"black"
            },
            str:'hello'
        }
    })
</script>

key的原理

html 复制代码
<body>
    <div id="root">
        <!-- 遍历数组 -->
         <button @click.once="add">添加一个</button>
        <ul>
            <li v-for="(p,index) in persons" :key="index">
                {{p.id}}-{{p.name}}-{{p.age}}
            </li>
        </ul>
       
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    new Vue({
        el:'#root',
        data:{
            persons:[
                {id:'001',name:'aaa',age:18},
                {id:'002',name:'bbb',age:19},
                {id:'003',name:'ccc',age:20}
            ],
        },
        methods:{
            add(){
                const p ={id:'004',name:'ddd',age:21}
                this.persons.unshift(p)
            }
        }
    })
</script>

遍历列表时key的作用(index作为key)

遍历列表时key的作用(id作为key)

虚拟DOM中key的作用

key是虚拟DOM对象的标识,当状态中的数据发生变化时 ,Vue会根据新数据生成新虚拟DOM,随后Vue进行新虚拟DOM与旧虚拟DOM的差异比较,比较规则如下:

列表过滤

html 复制代码
<body>
    <div id="root">
    <h2>人员列表</h2>
    <input type="text" placeholder="请输入名字" v-model="keyword">
        <ul>
            <li v-for="(p,index) in persons" :key="index">
                {{p.id}}-{{p.name}}-{{p.age}}
            </li>
        </ul>
       
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    //用watch实现
    // new Vue({
    //     el:'#root',
    //     data:{
    //         keyword:'',
    //         persons:[
    //             {id:'001',name:'aaa',age:18},
    //             {id:'002',name:'bbb',age:19},
    //             {id:'003',name:'ccc',age:20}
    //         ],
    //         filPerson:[]
    //     },
    //     watch:{
    //         keyword:{
    //             //immediate:true,立即执行handler
    //             immediate:true,
    //             handler(val){
    //                 this.filPerson=this.persons.filter((p)=>{
    //                 return p.name.indexOf(val)!== -1
    //             })
    //             }
    //         }
    //     }
    // })

    
    //用computed实现
    new Vue({
        el:'#root',
        data:{
            keyword:'',
            persons:[
                {id:'001',name:'aaa',age:18},
                {id:'002',name:'bbb',age:19},
                {id:'003',name:'ccc',age:20}
            ],
            
        },
       computed:{
        filPerson(){
            return this.persons.filter((p)=>{
                return p.name.indexOf(this.keyword)!== -1
            })
        }
       }
    })


</script>

列表排序

javascript 复制代码
new Vue({
        el:'#root',
        data:{
            keyword:'',
            sortType:0,//0:原顺序,1:升序,2:降序
            persons:[
                {id:'001',name:'aaa',age:18},
                {id:'002',name:'bbb',age:19},
                {id:'003',name:'ccc',age:20}
            ],
            
        },
       computed:{
        filPerson(){
            const arr = this.persons.filter((p)=>{
                return p.name.indexOf(this.keyword)!== -1
            })
            //判断下一个是否需要排序
            if(this.sortType){
                arr.sort((p1,p2)=>{
                    return this.sortType==1?p1.age-p2.age:p2.age-p1.age
                })
            }
            return arr
        }
       }
    })

监测数据

原理

  1. Vue会监视data中所有层次的数据

  2. 如何监测对象中的数据

    (1)对象中后追加的属性,Vue默认不做响应式处理

    (2)如需给后添加的属性做响应式,请使用如下API:

    Vue.set(target,propertyName/index,value)

    Vue.$set(target,propertyName/index,value

  3. 如何监测数组中的数据

    通过包裹数组更新元素的方法实现,本质就是做了两件事:

    (1)调用原生对应的方法对数组进行更新

    (2)重新解析模板,进而更新页面

  4. 在Vue中修改数组中的某个元素一定要用如下方法:

    (1)使用这些API:push(),shift(),unshift(),splice(),sort(),reverse()

    (2)Vue.set()或vm. s e t ( ) 特别注意: V u e . s e t ( ) h 和 v m . set() 特别注意:Vue.set()h和vm. set()特别注意:Vue.set()h和vm.set()不能给vm或vm的根数据对象添加属性

对象

不用Vue来模拟一个数据监测

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模拟数据监测</title>
</head>
<body>
    <script type="text/javascript" >
        let data={
            names:'清华大学',
            address:'北京'
        }
        //创建一个监视对象用于监视data中数据的变化
        const obs =new Observer(data)
        console.log(obs);
        
        //准备一个vm实例对象
        let vm ={}
        vm._data=data=obs

        function Observer(obj){
            //汇总对象中所有的属性形成一个数组
            const keys =Object.keys(obj)
            //遍历
            keys.forEach((k)=>{
                Object.defineProperty(this,k,{
                    get(){
                        return obj[k]
                    },
                    set(val){
                        console.log(`${k}被改了`);
                        
                        obj[k] = val
                    }
                })
            })
        }
    </script>
</body>
</html>

有一个问题是,如果data数据里面还包含着一个对象时,这个对象并不能监测到

如果用Vue来测试

html 复制代码
<body>
    <div id="root">
        <h2>学校名称:{{names}}</h2>
        <h2>学校地址:{{address}}</h2>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    const vm =new Vue({
        el:'#root',
        data:{
            names:'清华大学',
            address:'北京',
            student:{
                name:'tom',
                age:{
                    rAge:40,
                    sAge:29
                }
            },
            friends:[
                {name:'jerry',age:30}
            ]
        }
    })
</script>
数组

当监测的数据是数组是,vm._data里并没有getter和setter方法,所以可以用引起数组发生变化的几个数组API方法

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue监测数据改变的原理</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
        <h2>学校名称:{{names}}</h2>
        <h2>学校地址:{{address}}</h2>
        <!--Vue.set()方法只能修改数组中的元素,不能添加元素,不能删除元素 -->
        <hr/>
        <h1>学生信息</h1>
        <button @click="addSex">添加性别</button>
        <h2>学生姓名:{{student.name}}</h2>
        <h2 v-if="">性别:{{student.sex}}</h2>
        <h2>学生年龄:{{student.age.rAge}},对外{{student.age.sAge}}</h2>
        <h2>朋友们</h2>
        <ul>
            <li  v-for="(f,index) in student.friends" :key="index">{{f.name}}--{{f.age}}</li>
        </ul>
        <h2>爱好</h2>
        <ul>
            <li  v-for="(h,index) in student.hobby" :key="index">{{h}}</li>
        </ul>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    const vm =new Vue({
        el:'#root',
        data:{
            names:'清华大学',
            address:'北京',
            student:{
                name:'tom',
                age:{
                    rAge:40,
                    sAge:29
                },
                friends:[
                   {name:'jerry',age:30},
                   {name:'lucy',age:28}
                ],
                hobby:[
                    '电视','读书','玩'
                ]
               
            },
            
        },
        methods:{
            addSex(){
                Vue.set(this.student,'sex','男')
            }
        }
    })
</script>
</html>

Vue.set()

在Vue中如果是undefined,不会显示在页面上

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue监测数据改变的原理</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
        <h2>学校名称:{{names}}</h2>
        <h2>学校地址:{{address}}</h2>
        <!--Vue.set()方法只能修改数组中的元素,不能添加元素,不能删除元素 -->
        <h2>校长:{{headMaster}}</h2>
        <hr/>
        <h1>学生信息</h1>
        <button @click="addSex">添加性别</button>
        <h2>学生姓名:{{student.name}}</h2>
        <h2 v-if="">性别:{{student.sex}}</h2>
        <h2>学生年龄:{{student.age.rAge}},对外{{student.age.sAge}}</h2>
        <h2>朋友们</h2>
        <ul>
            <li  v-for="(f,index) in student.friends" :key="index">{{f.name}}--{{f.age}}</li>
        </ul>

    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    const vm =new Vue({
        el:'#root',
        data:{
            names:'清华大学',
            address:'北京',
            student:{
                name:'tom',
                age:{
                    rAge:40,
                    sAge:29
                },
                friends:[
                   {name:'jerry',age:30},
                   {name:'lucy',age:28}
                ]
            },
            
        },
        methods:{
            addSex(){
                Vue.set(this.student,'sex','男')
            }
        }
    })
</script>
</html>

收集表单数据

若,则v-model收集的是value值,用户输入的就是value值

若,则v-model收集的是value值,且要给标签配置value值

1.没有配置input的value属性,那么收集的就是checked(勾选 or 不勾选,是布尔值)

2.配置input的value属性

(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 不勾选,是布尔值)

(2)v-model的初始值是数组,那么收集的就是value组成的数组

备注: v-model的三个修饰符:

lazy:失去焦点再收集数据

number:输入字符串转为有效的数字

trim:输入首尾空格过滤

html 复制代码
<body>
    <div id="root">
        <form @submit.prevent="demo">
            账号:<input type="text" v-model="userInfo.account"><br><br>
            密码:<input type="password" v-model="userInfo.password"><br><br>
            性别:
            男<input type="radio" name="sex" value="male" v-model="userInfo.sex">
            女<input type="radio" name="sex" value="female" v-model="userInfo.sex"><br><br>
            爱好:
            打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
            看电影<input type="checkbox" v-model="userInfo.hobby" value="movie">
            看小说<input type="checkbox" v-model="userInfo.hobby" value="novel">
            <br><br>
            所属校区
            <select v-model="userInfo.city">
                <option value="">请选择校区</option>
                <option value="gaungzhou">广州校区</option>
                <option value="shenzhen">深圳校区</option>
                <option value="shanghai">上海校区</option>
            </select>
            <br><br>
            其他信息:
            <textarea v-model="userInfo.other"></textarea>
            <br><br>
            <input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.atguigu.com">《学员协议》</a>
            <br><br>
            <button>提交</button>
           
        </form>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    new Vue({
        el:'#root',
        data:{
          userInfo:{
            account:'',
            password:'',
            sex:'male',
            hobby:[],
            city:'guangzhou',
            other:'',
            agree:''
          }
        },
        methods:{
            demo(){
                console.log(JSON.stringify(this.userInfo));
                
            }
        }
    })
</script>

过滤器

html 复制代码
<body>
    <div id="root">
        <h2>显示格式化后的时间</h2>
        <!-- 计算属性 -->
         <h3>{{time1}}</h3>
         <!-- methods方法 -->
         <h3>{{time2()}}</h3>
          <!-- 过滤器实现 -->
         <h3>{{time3 | filterTime}}</h3>

         <h3>{{time3 | filterTime('YYYY') | mySlice}}</h3>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    //全局过滤器
    Vue.filter('mySlice',function(value){
        return value.slice(0,4)
    })
   new Vue({
    el:'#root',
    data:{
        time:1621561377603
    },
    computed:{
        time1(){
            return dayjs(tgis.time).format('YYYY-MM-DD HH:mm:ss')
        }
    },
    methods: {
        time2(){
            return dayjs(tgis.time).format('YYYY-MM-DD HH:mm:ss')
        }
    },
    // 局部过滤器
    filters:{
        
        filterTime(value,str){
            
            return dayjs(value).format(str)
        },
        
    }
   })
</script>

指令

内置指令

v-text

把所有的内容都当成文本解析

作用:向其所在的节点中渲染文本内容

与插值语法的区别:v-text会替换节点中的内容,{{xx}}则不会

v-html

作用:向指定节点中渲染包含html的结构的内容

与插值语法的区别:

  1. v-html会替换掉节点中所有内容,{{xx}}则不会
  2. v-html可以识别html结构
    注意:v-html有安全性问题
  3. 在网站上动态渲染任意html是非常危险的,容易导致xss攻击
  4. 一定要在可信的内容上使用html,永远不要在用户提交的内容
html 复制代码
<body>
    <div id="root">
        <div>{{name}}</div>
        <div v-html="str"></div>
        <div v-html="str1"></div>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    new Vue({
        el:'#root',
        data:{
            name:'我是名字',
            str:'我是字符串',
            str1:'<span style="color:red">我是字符串</span>'
        }
    })
</script>
v-cloak

该指令本身是没有值的

  1. 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
  2. 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题
html 复制代码
<style>
    /* v-cloak指令,用于解决在数据未加载完之前,页面上显示{{}} */
    /* [v-cloak]{
        display: none;
    } */
</style>
<body>
    <div id="root">
        <h2 v-cloak>{{name}}</h2>
    </div>
</body>
v-once
  1. v-once所在节点在初次动态渲染后,就视为静态内容了
  2. 以后结局的改变不会引起v-once所在结构的更新,可以用于优化性能
v-pre
  1. 跳过其所在节点的编译过程
  2. 可利用它跳过,没有使用指令语法,没有使用插值语法的节点,加快编译

自定义指令

html 复制代码
<body>
    <!-- 
    需求1:定义一个v-big指令,和v-text指令功能类似,但是将绑定的数据放大10倍
    需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让绑定的input元素默认获取焦点
     -->
    <div id="root">
       <h2>当前的n值是:<span v-text="n"></span></h2>
       <h2>放大10倍后的n值是:<span v-big="n"></span></h2>
       <button @click="n++">点我n+1</button>
       <br/>
       <input type="text" v-fbind:value="n">
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    new Vue({
        el:'#root',
        data:{
            name:'hello',
            n:18
        },
        directives:{
            // 何时被调用
            // 1指令与元素成功绑定时
            // 2.指令所在的模板被重新解析时
            big(element,binding){
                element.innerText = binding.value*10
            },
            fbind:{
                // 指令与元素成功绑定时
                bind(element,binding){
                    element.value = binding.value
                },
                //指令所在元素被插入页面时
                inserted(element,binding){
                    element.focus()
                },
                // 指令所在模板被重新解析时
                update(element,binding){
                    element.value = binding.value
                }
            }
           
        }
    })
</script>
相关推荐
Cachel wood24 分钟前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端25 分钟前
0基础学前端-----CSS DAY9
前端·css
joan_8529 分钟前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui
还是大剑师兰特1 小时前
什么是尾调用,使用尾调用有什么好处?
javascript·大剑师·尾调用
m0_748236111 小时前
Calcite Web 项目常见问题解决方案
开发语言·前端·rust
Watermelo6171 小时前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
m0_748248941 小时前
HTML5系列(11)-- Web 无障碍开发指南
前端·html·html5
m0_748235611 小时前
从零开始学前端之HTML(三)
前端·html
一个处女座的程序猿O(∩_∩)O3 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
hackeroink6 小时前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss