Do you see any problem with this?
You aren't really emplacing with this. There's still an assignment.
std::vector<T> doesn't allocate an array of T. It allocates raw memory with the size and alignment of an array of T, and then instantiates objects in that raw memory.
With that in mind, you should probably implement push_back in terms of emplace_back, rather than the other way around.
template <typename T>
class my_vector {
    T * start;
    std::size_t size;
    std::size_t capacity;
    void grow(); // Implementation of this is left as an exercise to the reader
public:
    template <typename... Args>
    reference emplace_back(Args&&... args) {
        if (size == capacity) grow();
        return *new (start + size++) T(std::forward<Args>(args)...);
    }
    reference push_back(const T & t) { return emplace_back(t); }
    reference push_back(T && t) { return emplace_back(std::move(t)); }
}
Also, please let me know how does this work?
template <typename... Args> allows zero or more types to match this template, and then T(std::forward<Args>(args)...) is constructing a T with those arguments, "perfectly forwarding" them, i.e. rvalues are passed as rvalues and lvalues as lvalues.
N.b. because std::vector doesn't new[], you cannot implement something that behaves exactly like std::vector before C++ 20, because it has to be able to return a pointer to an array of T from data without constructing an array of T.