【Vue】二
一个第三方js处理类库 BootCDN
Vue过滤器
Date.now() 获取时间戳
Date.now()
1652411231222
计算属性实现
<body>
    <div id="root">
        <h2>现在是:{{fmtTime}}</h2>
    </div>
</body>
<script>
    Vue.config.productionTip = false
    const vm = new Vue({
        el: "#root",
        data: {
            time: 1652411751706
        },
        computed: {
            fmtTime() {
                return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
            }
        }
    })
</script>
methods实现
<body>
    <div id="root">
        <h2>现在是:{{getFmtTime()}}</h2>
    </div>
</body>
<script>
    Vue.config.productionTip = false
    const vm = new Vue({
        el: "#root",
        data: {
            time: 1652411751706
        },
        computed: {
            fmtTime() {
                return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
            }
        },
        methods: {
            getFmtTime() {
                return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
            }
        }
    })
</script>
函数有返回值时,调用的函数值名必须加括号
过滤器实现
<body>
    <div id="root">
        <h2>现在是:{{time | Timeformat('YYYY-MM-DD') | subStr(4)}}</h2>
    </div>
</body>
过滤器使用管道符号将管道前的值作为参数传入管道符后的过滤器函数
        filters: {
            Timeformat(val, str) {
                return dayjs(val).format(str)
            },
            subStr(val, len) {
                return val.slice(0,len)
            }
        }
过滤器适用于{{}}差值语法、v-bind(:)单向绑定但不适用于model双向绑定
全局过滤器
上面的过滤器全是在Vue实例中配置的,因此是局部过滤器
    Vue.filter('Timeformat', function(val, str){
        return dayjs(val).format(str)
    })
这样所有的VUe实例均可以使用此过滤器
一些Vue内置指令
v-text
作用: 向所在节点中渲染文本内容
与插值语法的区别: v-text会替换节点中的内容,插值语法不会
    <div id="root">
        <h2 v-text="time">现在是:{{time | Timeformat('YYYY-MM-DD') | subStr(4)}}</h2>
    </div>
结果只显示time数据
v-html
作用: 支持结构解析,v-text不能
可能存在安全注入问题:
①在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击
如用户输入: <a href="www....com?document.cookie">
②一定要在可信的内容上使用v-html,永远不要用在用户的提交上
解决: 后端使用HTTPOnly,即只有Http传输能读取到这些cookie
v-cloak 防止网速慢导致未经解析的模板加载到页面

如上图,由于js没有加载导致vue也不能加载,页面会显示容器中未曾解析的{{name}},但是加上v-cloak后,根据css样式会隐藏属性为v-cloak的节点,而v-cloak的特性是vue加载时会自动删掉,因此解析后的模板就会显示了。
v-once
v-once所在节点在初次动态渲染之后,就被视为静态内容了
以后的数据的改变也不会引起v-once所在结构的更新,可以用于优化性能
v-pre
v-pre可以让vue跳过所在节点的编译过程
可以利用它跳过没有使用指令、差值语法的节点,会加快编译
自定义指令
Vue生命周期
浏览器本地存储
localStorage
保存
        let person = {
            name: 'gravce',
            sex: 'male'
        }
        function SaveData() {
            localStorage.setItem('msg', 'hello')
            localStorage.setItem('msg1', 123)
            localStorage.setItem('person', JSON.stringify(person))
        }
数据保存会以字符串形式,对象应该使用json
获取
        function GetData() {
            document.getElementById('output').value =
                             localStorage.getItem('person')
        }
删除
        function DeleteData() {
            localStorage.removeItem('person')
        }
清空
        function ClearData() {
            localStorage.clear()
        }
SessionStorage
LocalStorage是保存在用户磁盘上的,浏览器关闭会话结束后不会消失,而SessionStorage会
使用浏览器本地存储保存Todolist结果
只需使用一个监视属性即可解决
    data() {
      return {
          todos: JSON.parse(localStorage.getItem('todos')) || []
      }
    },
    watch: {
      todos(val) {
        localStorage.setItem('todos', JSON.stringify(val))
      }
    },
注意代码中的"|| []",这是为了防止localStorage为空时,导致JSON解析为null,进而导致todos拿到的不是空数组而是null进而引起的后续错误
意料之外的bug
上面的代码在刷新页面之后不能显示做没做完,原因是没有开启深度监视
    watch: {
      todos: {
        handler(val) {
          localStorage.setItem('todos', JSON.stringify(val))
        },
        deep: true
      }
    },
组件自定义事件
绑定事件
    <!-- 给组件绑定一个hikaru自定义事件,当Student组件中触发该事件时,demo就会被调用 -->
    <Student v-on:hikaru="demo"></Student>
给组件绑定一个hikaru自定义事件,当Student组件中触发该事件时,demo就会被调用
绑定的简写
<Student @hikaru="demo"></Student>
组件事件的触发 $emit
        methods: {
            getName() {
                // 触发Student组件身hikaru事件
                this.$emit('hikaru')
            }
        },
在App.vue中使用mounted、$on 延迟事件的触发
<Student ref="stu"></Student>
mounted() {
  setTimeout(()=>{
    this.$refs.stu.$on('hikaru', this.demo)
  }, 3000)
},
解绑自定义事件 $off
methods: {
    getName() {
        // 触发Student组件身上的getName事件
        this.$emit('hikaru')
    },
    unbind() {
        this.$off('hikaru')
    }
},
解绑多个事件:this.$off(['hikaru', 'xxx'])
解绑所有事件:this.$off()
全局事件总线 实现任意组件之间的通信
分析:全局事件总线,实质是创建一个中间组件或者vue实体,所有的其他组件都能在这个中间体上绑定事件并通过触发事件获取数据,因此,此中间体需要满足两个条件:
①所有组件都能看见它
②它可以调用$on、$off、$emit方法
定义方式一:通过VueComponent
1 在main.js安装事件总线
const vc = Vue.extend({})
Vue.prototype.bus = new vc()
2 在事件总线上绑定事件
    mounted() {
      let items = this.$refs.list.$refs.item
      items.forEach(item => {
        item.$on('checkTodo', this.checkTodo)
        item.$on('deleteOne', this.deleteOne)
      });
      this.bus.$on('hikaru', this.hikaru)
    }
3 其他组件在时间总线上触发事件
<button @click="bus.$emit('hikaru')">hikaru</button>
定义方式一:通过VM
vm本身就可以作为原型对象,不需要在创建vue
在main.js安装事件总线
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
  render: h => h(App),
  beforeCreate() {
    Vue.prototype.bus = this
  }
}).$mount('#app')
需要注意总线bus的赋值时机,在vm创建之前的话vm没有生成,而在之后的话vm已经执行完了mounted挂载,因此需要放在beforeCreate钩子中
全局事件总线的使用场景

消息订阅与发布
动画效果
<template>
    <div>
        <transition appear name="hello">
            <div v-show="isShow">
                <div class="black"> </div>
                <div class="hello">
                    Hello
                </div>
            </div>
        </transition>
        <button @click="isShow = !isShow">click</button>
    </div>
</template>
<script>
    export default {
        name: 'Test',
        data() {
            return {
                isShow: true
            }
        }
    }
</script>
<style scoped>
    .black {
        background-color: rgb(0, 0, 0);
        width: 15px;
        height: auto;
        float: left;
    }
    .hello {
        background-color: orange;
        width: 100px;
        float: left;
    }
    .hello-enter-active{
        animation: comeAndgo 1s linear
    }
    .hello-leave-active{
        animation: comeAndgo 1s linear reverse
    }
    @keyframes comeAndgo {
        from {
            transform: translateX(-115px);
        }
        to {
            transform: translateX(0px);
        }
    }
</style>
过渡实现动画效果
    /* 进入的起点 */
    .hello-enter, .hello-leave-to{
        transform: translateX(-100%);
    }
    /* 进入的重点 */
    .hello-enter-to, .hello-leave{
        transform: translateX(0);
    }
    /* 进入离开动画 */
    .hello-enter-active, .hello-leave-active {
        transition: 1s ;
    }
多个元素过渡
        <transition-group appear name="hello">
            <div v-show="isShow" key="1">
                <div class="black"> </div>
                <div class="hello">
                    Hello
                </div>
            </div>
            <div v-show="isShow" key="2">
                <div class="black"> </div>
                <div class="hello">
                    Hello
                </div>
            </div>
        </transition-group>
多个元素过渡需要使用transition-group,并且需要在元素上添加key值
集成第三方动画库
        <transition-group 
            appear 
            name="animate__animated animate__bounce"
            enter-active-class="animate__zoomInDown"
            leave-active-class="animate__zoomOut"
        >
            <div v-show="isShow" key="1">
                <div class="black"> </div>
                <div class="hello">
                    Hello
                </div>
            </div>
        </transition-group>
(1) 安装并导入
$ npm install animate.css --save
<script>
    import 'animate.css'
    export default {
        name: 'Test',
        data() {
            return {
                isShow: true
            }
        }
    }
</script>
(2) 配置name、进入离开动画
        <transition-group 
            appear 
            name="animate__animated animate__bounce"
            enter-active-class="animate__zoomInDown"
            leave-active-class="animate__zoomOut"
        >
group必须配置key
配置代理 解决ajax请求跨域问题
几种Ajax
① xhr(原生js实现)
xhr = new XMLHTTPRequest()
xhr.open() 配置请求信息
xhr.send() 发送请求
② JQuery
$.get $.post
③ axios(最常用)
④ fetch
②③都是对xhr进行二次封装,fetch和xhr都是原生的js实现
fetch获取响应需要两层then,且兼容性不好
使用axios获取学生信息
        methods: {
            getStuInfo() {
                axios.get('http://localhost:5000/students').then(
                    response => {
                        console.log(response.data)
                    },
                    error => {
                        console.log(error.message)
                    }
                )
            }
        }
存在的跨域问题
跨域:违背了同源策略,即协议名、主机名、端口号必须一致。

如图所示,浏览器端口号8080与服务器5000不一致导致跨域问题,需要注意的是跨域问题并不是没有发送响应请求,而是在服务器响应给浏览器时,浏览器发现跨域而将数据隐藏了起来
解决跨域的策略
1 cors
大致思路:服务器在响应给浏览器数据时会在响应体中携带一些特殊的响应头,以告知浏览器可以无视跨域问题。
但是在开发中响应头是不能随便修改的,而且这种策略需要完全由后端进行
2 jsonp
大致思路:利用script标签的src属性不受同源跨域问题影响的特性
但是需要前后端同时进行修改,而且只能处理get请求
3 使用代理服务器(常用)

如此一来,8080端口的浏览器端和8080代理服务器通过ajax请求通信就不存在跨域问题,而且同时服务器和代理服务器是通过http通信,更不存在跨域问题
代理服务器的配置 方式一
vue.config.js
module.exports = {
  pages: {
    index: {
      entry: 'src/main.js'
    }
  },
  devServer: {
    proxy: 'http://localhost:5000'
  }
  }
同时修改前端页面的请求端口号为代理服务器的8080
Test2.vue
    export default {
        name: 'Test2',
        methods: {
            getStuInfo() {
                axios.get('http://localhost:8080/students').then(
                    response => {
                        console.log(response.data)
                    },
                    error => {
                        console.log(error.message)
                    }
                )
            }
        }
    }
但是这样存在两个个问题:请求会首先在8080端口号下查找student资源,当发现没有的时候才去向代理服务器发送请求;另一个问题是只能给一台服务器转发请求
代理服务器的配置 方式二
  devServer: {
    proxy: {
      '/hikaru': {
        target: "http://localhost:5000",
        pathRewrite: {'^/hikaru':''},
        ws: true,
        changeOrign: true
      }
    }
  }
 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号