VUE demo

vue实践和vue组件通信

Posted by SkioFox on April 12, 2018

vue组件通信

  1. 父子组件通过属性传递数据
    • 父传子
        <Cart :name="name" :cart="cart"></Cart>
        // 子组件
        <div>
            购物车
        </div>
        export default {
            name: 'Cart',
            props:['name',"cart"],
            data () {
                return {
                          
                }
            },
            methods: {
                }
            }
        // 校验
            props:{
                name:{
                    type:String,
                    required:true
                },
                cart:{
                    type:Array
                }
            },
      
    • 子通知父改变:$emit 实现子组件向父组件通信。

      
        // $emit 绑定一个自定义事件event  vm.$emit( event, arg )
        // 子组件监听自定义事件titleChanged
        <template>
            <header>
                <h1 @click="changeTitle"></h1>//绑定一个点击事件
            </header>
        </template>
        <script>
        export default {
            name: 'app-header',
            data() {
                return {
                    title:"Vue.js Demo"
                }
            },
            methods:{
                changeTitle() {
                    this.$emit("titleChanged","子向父组件传值");//自定义事件  传递值“子向父组件传值”
                }
            }
        }
        </script>
        // 父组件响应titleChanged事件
        <template>
            <div id="app">
                <app-header v-on:titleChanged="updateTitle" ></app-header>//与子组件titleChanged自定义事件保持一致updateTitle($event)接受传递过来的文字
                <h2></h2>
            </div>
        </template>
        <script>
            import Header from "./components/Header"
            export default {
                name: 'App',
                data(){
                    return{
                        title:"传递的是一个值"
                    }
                },
                methods:{
                        updateTitle(e){   //声明这个函数
                        this.title = e;
                    }
                },
                components:{
                    "app-header":Header,
                }
            }
        </script>
      
  2. 两个任意组件传递
    • 使用总线机制传递,vue每个实例都有订阅/发布模式的实现,使用$on和$emit来使用

        // main.js
        Vue.prototype.$bus = new Vue
        // App.vue 父组件
        addCart(i){
            const good = this.goods[i]
            this.$bus.$emit('addCart',good)
        }
        // Cart.vue 子组件
        created() {
            // 监听一下父组件添加商品事件
            this.$bus.$on("addCart", good => {
                const ret = this.cart.find(v => v.text == good.text);
                if (ret) {
                    ret.count += 1;
                } else {
                    this.cart.push({ ...good, active: true, count: 1 });
                }
            });
        },
      
    • 原理:发布和订阅模式=>实现Bus类
        class Bus{
            constructor(){
                // {
                //   eventName1:[fn1,fn2],
                //   eventName2:[fn3,fn4],
                // }
                this.callbacks = {}
            }
            $on(name,fn){
                this.callbacks[name] = this.callbacks[name] || []
                this.callbacks[name].push(fn)
            }
            $emit(name,args){
                if(this.callbacks[name]){
                // 存在 遍历所有callback
                this.callbacks[name].forEach(cb=> cb(args))
                }
            }
        }
        // 挂载到vue原型上
        Vue.prototype.$bus = new Bus()
      
    • 使用
        // 触发
        eventBus(){
            this.$bus.$emit('event-bus','测试eventBus')
        }
      
        // 监听
        this.$bus.$on("event-bus",msg=>{
            this.msg = '接收event-bus消息:'+ msg
        })
      
      
  3. 状态管理最佳实践 vuex
  4. 在vue.config.js中配置mock数据=>cli 3中的
         //这里是全局配置可以覆盖webpack配置
         module.exports = {
             configureWebpack: {
                 devServer: {
                     // 这里是中间件,相当于接口
                     before(app) {
                         // koa写法
                         app.get('/api/goods', function(req,res){
                                 res.json({
                                     code:0,
                                     list: [
                                         { id: 1, text: "华为P30", price: 1000 },
                                         { id: 2, text: "OPPO Rena 10X", price: 1000 }
                                     ]
                                 })
                         }) 
                     }
                 },
             }
         }
         // 在app.vue中使用接口获取数据
           async created() {
             // 创建钩子,组件创建完成执行一次
             setTimeout(() => {
                 this.showName = true;
             }, 1000);
    
             // 查询产品列表
             try {
                 const response = await axios.get("/api/goods");
                 // console.log(response);
                 this.goods = response.data.list;
             } catch (error) {
             // 错误处理
             }
    
             // 不用await
             // axios.get("/api/goods").then(resp => {
             //   this.goods = response.data.list;
             // }).catch(err => {
             //   // 错误处理
             // })
         },
            
    
  5. 数据持久化localStorage+vue监听器=>setItem/getItem
     // cart.vue
    
     data() {
         return {
             cart: JSON.parse(localStorage.getItem("cart")) || []
         };
     },
     watch: {
         cart: {
             handler(n, o) {
                 localStorage.setItem("cart", JSON.stringify(n));
             },
         deep: true
         }
     }
    
  6. computed

         //可以对data进行复杂的逻辑运算,数据变化才会执行,优于watch
         <tr>
             <td></td>
             <td colspan='2'>/ 8</td>
             <td colspan='2'>􀓝</td>
         </tr>
    
         computed:{
             total(){
                 let num = 0
                 this.cart.forEach(v=>{
                     if(v.active){
                     num+= v.price*v.count
                     }
                 })
                 return num
                 //....
                 //return this.cart.reduce((sum,v)=>{
                 // if(v.active){
                     // return sum + v.price*v.count
                     // }
                 // },0)
             },
             count(){
                 return this.cart.length
             },
             activeCount(){
                 return this.cart.filter(v=>v.active).length
             }
         },